On Fri, 05 Sep 2025, Zilin Guan <[email protected]> wrote: > The drm_edid_alloc() function uses kmemdup() to copy raw EDID data, > which can be loaded from firmware. A problem exists because the firmware > subsystem uses vfree() to release its data buffer. This implies the > buffer may be allocated with vmalloc() and can thus be larger than > kmalloc() typically supports. Since kmemdup() uses kmalloc() internally, > attempting to duplicate a large, vmalloc'd EDID buffer can lead to an > allocation failure.
Real world EDIDs are usually under 1 kB and if the user provides a much bigger EDID via the firmware loader it's okay to fail at the allocation time. BR, Jani. > > To fix this mismatch and robustly handle EDID data of any size, this > patch replaces kmemdup() with kvmemdup(). The kvmemdup() function is > designed for this scenario, as it can safely handle a vmalloc'd source > and choose an appropriate allocator for the destination. The corresponding > free calls are therefore updated to kvfree(). > > Signed-off-by: Zilin Guan <[email protected]> > --- > drivers/gpu/drm/drm_edid.c | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) > > diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c > index e2e85345aa9a..97142bfc45ad 100644 > --- a/drivers/gpu/drm/drm_edid.c > +++ b/drivers/gpu/drm/drm_edid.c > @@ -2530,13 +2530,13 @@ const struct drm_edid *drm_edid_alloc(const void > *edid, size_t size) > if (!edid || !size || size < EDID_LENGTH) > return NULL; > > - edid = kmemdup(edid, size, GFP_KERNEL); > + edid = kvmemdup(edid, size, GFP_KERNEL); > if (!edid) > return NULL; > > drm_edid = _drm_edid_alloc(edid, size); > if (!drm_edid) > - kfree(edid); > + kvfree(edid); > > return drm_edid; > } > @@ -2568,7 +2568,7 @@ void drm_edid_free(const struct drm_edid *drm_edid) > if (!drm_edid) > return; > > - kfree(drm_edid->edid); > + kvfree(drm_edid->edid); > kfree(drm_edid); > } > EXPORT_SYMBOL(drm_edid_free); -- Jani Nikula, Intel
