NULL pointer dereference in nvidia-modeset via nv_drm_framebuffer_create (DRM_IOCTL_MODE_ADDFB2) #1356
LeChatOTapas
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Posting here rather than as an Issue: the functional-bug template requires confirming the problem does not occur with the proprietary driver, which would be untrue here. The defective code is shared verbatim between
kernel/andkernel-open/, so both flavours are affected. Happy to move this wherever you prefer.nv_drm_framebuffer_init()callsnvKms->isVidmem(nv_gem->pMemory)on GEM objects of arbitrary type, without checkingpMemory. Several GEM types legitimately havepMemory == NULL, andisVidmem()dereferences it unconditionally. Any Wayland compositor that hands such a buffer toDRM_IOCTL_MODE_ADDFB2oopses the kernel.Reproducible 100% of the time on the affected setup, and fixed by a two-line null check (patch below, validated).
Still present in
mainas of 615.71.09. Verified onkernel-open/nvidia-drm/nvidia-drm-fb.cin this repository: the offending line is unchanged from 595.99.02, and the same file ships byte-identically in the proprietary driver'skernel/tree (verified by sha256 against the 595.99.02.run).Environment
--kernel-module-type=proprietary). Code path unchanged inmainat 615.71.09.Not reproducible under X11: the NVIDIA DDX does not use the DRM
ADDFB2path.Reproduction
ADDFB2. The kernel oopses andkwin_waylandis killed.The following OpenGL errors from the compositor immediately precede the oops, and are the signature of the cross-GPU buffer import that produces the offending framebuffer:
Oops
_nv000556kmsis theisVidmementry ofstruct NvKmsKapiFunctionsTable. This is established without guessing: innv-modeset-kernel.o_binarythe symbol has exactly one relocation, insidenvKmsKapiGetFunctionsTableInternal, storing it at table offset+0xc0, which isoffsetof(struct NvKmsKapiFunctionsTable, isVidmem)as computed from the shippednvkms-kapi.h. The five neighbouring slots line up withmapMemory,unmapMemory,gc6BlockerRefCntInc,gc6BlockerRefCntDecandcreateSurface.The function body is a 9-byte accessor, and the faulting instruction in the
Code:field above matches it exactly:Root cause
nvidia-drm/nvidia-drm-fb.c,nv_drm_framebuffer_init()(line 134), loop at line 158, offending call at line 167:isVidmem()is documented innvkms-kapi.has taking "Memory allocated using allocateMemory()", so passing NULL is a caller-side bug. Two paths legitimately producepMemory == NULL:nv_drm_gem_prime_import_sg_table()(nvidia-drm-gem-dma-buf.c:153-156) setspMemory = NULLand only fills it fromgetSystemMemoryHandleFromDmaBuf(), which can fail. The rest of the driver handles that explicitly, e.g.nv_drm_gem_export_dmabuf_memory_ioctl()at line 199 testsif (!nv_dma_buf->base.pMemory).nv_drm_gem_import_userspace_memory()(nvidia-drm-gem-user-memory.c:232) always passesNULL /* pMemory */.nvidia-drm-fb.c:167is the only site in the driver that callsisVidmem()on a GEM of arbitrary type. The five other call sites are all innvidia-drm-gem-nvkms-memory.cand operate on objects created through__nv_drm_nvkms_gem_obj_init(), whose four callers all null-checkpMemorybeforehand (lines 414, 477, 596, 643).Proposed fix
This reuses the existing
non_scanout_mem_backedpath, so it introduces no new state:nv_fb->pSurfacestays NULL, and the two consumers ofpSurface(cursor_plane_req_config_update()andplane_req_config_update()innvidia-drm-crtc.c) already null-check it and return-EINVALat atomic check time.ADDFB2therefore succeeds and any scanout attempt fails cleanly instead of panicking. Behaviour is unchanged wheneverpMemoryis valid.Validation
Reproduced in a VM (Debian 13, KDE Wayland, same GPU via VFIO passthrough) with an identical call trace down to the offsets, then fixed. With the patch applied and an added one-shot log line, the kernel confirms the path is taken and handled:
On the original hardware, the patched driver no longer oopses and the external display now works, which it never did before, since the hot-plug always panicked first.
Unrelated second issue in the same file
nv_drm_gem_prime_import_sg_table()(nvidia-drm-gem-dma-buf.c:146) returns a bareNULLon allocation failure. The DRM core checks this hook withIS_ERR(), which is false for NULL, so the returned NULL would be treated as a valid GEM object and dereferenced. The sibling hooknv_drm_gem_prime_import()(nvidia-drm-gem.c:168), registered next to it in the samedrm_driver, correctly returnsERR_PTR(-ENOTSUPP).Both are still present verbatim in
mainat 615.71.09.All reactions