{"api_version":"1","generated_at":"2026-09-17T23:44:40+00:00","cve":"CVE-2026-89996","urls":{"html":"https://cve.report/CVE-2026-89996","api":"https://cve.report/api/cve/CVE-2026-89996.json","docs":"https://cve.report/api","cve_org":"https://www.cve.org/CVERecord?id=CVE-2026-89996","nvd":"https://nvd.nist.gov/vuln/detail/CVE-2026-89996"},"summary":{"title":"dma-buf: dma-heap: don't publish fd before copy_to_user() succeeds","description":"In the Linux kernel, the following vulnerability has been resolved:\n\ndma-buf: dma-heap: don't publish fd before copy_to_user() succeeds\n\nDMA_HEAP_IOCTL_ALLOC allocates a dma-buf and installs an fd into the\ncaller's fd table via dma_buf_fd() -> fd_install() before\ndma_heap_ioctl() copies the result back to userspace.  If the trailing\ncopy_to_user() fails, userspace never learns the fd number, but the\nfd (and the underlying dma-buf reference) are already visible to\nother threads in the same process and are leaked for the lifetime of\nthe process.\n\nThe obvious \"close it on the failure path\" fix is unsafe: once\nfd_install() has run, another thread can already dup() the fd, send\nit via SCM_RIGHTS, or close() it and let its number be reused, so a\nsubsequent close_fd() from the ioctl path can operate on an unrelated\nfile.  This was pointed out by Christian König on v1 [1].\n\nRestructure the allocation path so that fd_install() is the last,\nunfailable step of a successful ioctl:\n\n  1. heap->ops->allocate()      creates the dma_buf.\n  2. get_unused_fd_flags()      reserves an fd number in the caller's\n                                fd table without publishing it, so\n                                no other thread can observe it.\n  3. copy_to_user()             delivers the fd number to userspace;\n                                on failure the fd is returned with\n                                put_unused_fd() and the dma_buf\n                                reference is dropped with\n                                dma_buf_put(), leaving no user-\n                                visible state behind.\n  4. dma_buf_fd_install()       publishes the fd and emits the\n                                trace_dma_buf_fd tracepoint -- from\n                                here on the ioctl cannot fail.\n\nA new dma_buf_fd_install() helper is introduced in dma-buf.c to wrap\nfd_install() together with the DMA_BUF_TRACE() call, preserving the\nexport tracing that dma_buf_fd() provides.  dma_heap_ioctl_allocate()\nis refactored to return the struct dma_buf * directly (returning\nERR_PTR on failure) so the caller holds the dmabuf reference across\nsteps 3 and 4.\n\nThe failure at step 3 is easily reachable from userspace: pass a\nstruct dma_heap_allocation_data that lives in a page whose protection\nis flipped to PROT_READ between copy_from_user() and copy_to_user()\n(e.g. via mprotect()).  Before this change each such ioctl leaks one\ndmabuf fd; after it, the fd table is unchanged on failure and only\n/dev/dma_heap/<name> remains open.\n\nNo UAPI or heap-driver interface change.\n\n[1] https://lore.kernel.org/dri-devel/175e98de-f414-47d7-81c1-c0fe0a8f7f62@amd.com/","state":"PUBLISHED","assigner":"Linux","published_at":"2026-09-16 11:17:10","updated_at":"2026-09-16 11:17:10"},"problem_types":[],"metrics":[],"references":[{"url":"https://git.kernel.org/stable/c/69d57dbadb27ffd5eef34fd184bab145500cdabc","name":"https://git.kernel.org/stable/c/69d57dbadb27ffd5eef34fd184bab145500cdabc","refsource":"416baaa9-dc9f-4396-8d5f-8c081fb06d67","tags":[],"title":"","mime":"","httpstatus":"","archivestatus":"0"},{"url":"https://git.kernel.org/stable/c/0d4a5d218055db29b50cc07d3d73d27007c2a391","name":"https://git.kernel.org/stable/c/0d4a5d218055db29b50cc07d3d73d27007c2a391","refsource":"416baaa9-dc9f-4396-8d5f-8c081fb06d67","tags":[],"title":"","mime":"","httpstatus":"","archivestatus":"0"},{"url":"https://git.kernel.org/stable/c/30d0aff2c65a277135cfd8ea28fa1ee75e0ea4e0","name":"https://git.kernel.org/stable/c/30d0aff2c65a277135cfd8ea28fa1ee75e0ea4e0","refsource":"416baaa9-dc9f-4396-8d5f-8c081fb06d67","tags":[],"title":"","mime":"","httpstatus":"","archivestatus":"0"},{"url":"https://www.cve.org/CVERecord?id=CVE-2026-89996","name":"CVE Program record","refsource":"CVE.ORG","tags":["canonical"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-89996","name":"NVD vulnerability detail","refsource":"NVD","tags":["canonical","analysis"]}],"affected":[{"source":"CNA","vendor":"Linux","product":"Linux","version":"affected c02a81fba74fe3488ad6b08bfb5a1329005418f8 69d57dbadb27ffd5eef34fd184bab145500cdabc git","platforms":[]},{"source":"CNA","vendor":"Linux","product":"Linux","version":"affected c02a81fba74fe3488ad6b08bfb5a1329005418f8 0d4a5d218055db29b50cc07d3d73d27007c2a391 git","platforms":[]},{"source":"CNA","vendor":"Linux","product":"Linux","version":"affected c02a81fba74fe3488ad6b08bfb5a1329005418f8 30d0aff2c65a277135cfd8ea28fa1ee75e0ea4e0 git","platforms":[]},{"source":"CNA","vendor":"Linux","product":"Linux","version":"affected 5.6","platforms":[]},{"source":"CNA","vendor":"Linux","product":"Linux","version":"unaffected 5.6 semver","platforms":[]},{"source":"CNA","vendor":"Linux","product":"Linux","version":"unaffected 6.18.52 6.18.* semver","platforms":[]},{"source":"CNA","vendor":"Linux","product":"Linux","version":"unaffected 7.2.5 7.2.* semver","platforms":[]},{"source":"CNA","vendor":"Linux","product":"Linux","version":"unaffected 7.3-rc2 * original_commit_for_fix","platforms":[]}],"timeline":[],"solutions":[],"workarounds":[],"exploits":[],"credits":[],"nvd_cpes":[],"vendor_comments":[],"enrichments":{"kev":null,"epss":null,"legacy_qids":[]},"source_records":{"cve_program":{"containers":{"cna":{"affected":[{"defaultStatus":"unaffected","product":"Linux","programFiles":["drivers/dma-buf/dma-buf.c","drivers/dma-buf/dma-heap.c","include/linux/dma-buf.h"],"repo":"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git","vendor":"Linux","versions":[{"lessThan":"69d57dbadb27ffd5eef34fd184bab145500cdabc","status":"affected","version":"c02a81fba74fe3488ad6b08bfb5a1329005418f8","versionType":"git"},{"lessThan":"0d4a5d218055db29b50cc07d3d73d27007c2a391","status":"affected","version":"c02a81fba74fe3488ad6b08bfb5a1329005418f8","versionType":"git"},{"lessThan":"30d0aff2c65a277135cfd8ea28fa1ee75e0ea4e0","status":"affected","version":"c02a81fba74fe3488ad6b08bfb5a1329005418f8","versionType":"git"}]},{"defaultStatus":"affected","product":"Linux","programFiles":["drivers/dma-buf/dma-buf.c","drivers/dma-buf/dma-heap.c","include/linux/dma-buf.h"],"repo":"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git","vendor":"Linux","versions":[{"status":"affected","version":"5.6"},{"lessThan":"5.6","status":"unaffected","version":"0","versionType":"semver"},{"lessThanOrEqual":"6.18.*","status":"unaffected","version":"6.18.52","versionType":"semver"},{"lessThanOrEqual":"7.2.*","status":"unaffected","version":"7.2.5","versionType":"semver"},{"lessThanOrEqual":"*","status":"unaffected","version":"7.3-rc2","versionType":"original_commit_for_fix"}]}],"cpeApplicability":[{"nodes":[{"cpeMatch":[{"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionEndExcluding":"6.18.52","versionStartIncluding":"5.6","vulnerable":true},{"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionEndExcluding":"7.2.5","versionStartIncluding":"5.6","vulnerable":true},{"criteria":"cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*","versionEndExcluding":"7.3-rc2","versionStartIncluding":"5.6","vulnerable":true}],"negate":false,"operator":"OR"}]}],"descriptions":[{"lang":"en","value":"In the Linux kernel, the following vulnerability has been resolved:\n\ndma-buf: dma-heap: don't publish fd before copy_to_user() succeeds\n\nDMA_HEAP_IOCTL_ALLOC allocates a dma-buf and installs an fd into the\ncaller's fd table via dma_buf_fd() -> fd_install() before\ndma_heap_ioctl() copies the result back to userspace.  If the trailing\ncopy_to_user() fails, userspace never learns the fd number, but the\nfd (and the underlying dma-buf reference) are already visible to\nother threads in the same process and are leaked for the lifetime of\nthe process.\n\nThe obvious \"close it on the failure path\" fix is unsafe: once\nfd_install() has run, another thread can already dup() the fd, send\nit via SCM_RIGHTS, or close() it and let its number be reused, so a\nsubsequent close_fd() from the ioctl path can operate on an unrelated\nfile.  This was pointed out by Christian König on v1 [1].\n\nRestructure the allocation path so that fd_install() is the last,\nunfailable step of a successful ioctl:\n\n  1. heap->ops->allocate()      creates the dma_buf.\n  2. get_unused_fd_flags()      reserves an fd number in the caller's\n                                fd table without publishing it, so\n                                no other thread can observe it.\n  3. copy_to_user()             delivers the fd number to userspace;\n                                on failure the fd is returned with\n                                put_unused_fd() and the dma_buf\n                                reference is dropped with\n                                dma_buf_put(), leaving no user-\n                                visible state behind.\n  4. dma_buf_fd_install()       publishes the fd and emits the\n                                trace_dma_buf_fd tracepoint -- from\n                                here on the ioctl cannot fail.\n\nA new dma_buf_fd_install() helper is introduced in dma-buf.c to wrap\nfd_install() together with the DMA_BUF_TRACE() call, preserving the\nexport tracing that dma_buf_fd() provides.  dma_heap_ioctl_allocate()\nis refactored to return the struct dma_buf * directly (returning\nERR_PTR on failure) so the caller holds the dmabuf reference across\nsteps 3 and 4.\n\nThe failure at step 3 is easily reachable from userspace: pass a\nstruct dma_heap_allocation_data that lives in a page whose protection\nis flipped to PROT_READ between copy_from_user() and copy_to_user()\n(e.g. via mprotect()).  Before this change each such ioctl leaks one\ndmabuf fd; after it, the fd table is unchanged on failure and only\n/dev/dma_heap/<name> remains open.\n\nNo UAPI or heap-driver interface change.\n\n[1] https://lore.kernel.org/dri-devel/175e98de-f414-47d7-81c1-c0fe0a8f7f62@amd.com/"}],"providerMetadata":{"dateUpdated":"2026-09-16T10:33:08.620Z","orgId":"416baaa9-dc9f-4396-8d5f-8c081fb06d67","shortName":"Linux"},"references":[{"url":"https://git.kernel.org/stable/c/69d57dbadb27ffd5eef34fd184bab145500cdabc"},{"url":"https://git.kernel.org/stable/c/0d4a5d218055db29b50cc07d3d73d27007c2a391"},{"url":"https://git.kernel.org/stable/c/30d0aff2c65a277135cfd8ea28fa1ee75e0ea4e0"}],"title":"dma-buf: dma-heap: don't publish fd before copy_to_user() succeeds","x_generator":{"engine":"bippy-1.2.0"}}},"cveMetadata":{"assignerOrgId":"416baaa9-dc9f-4396-8d5f-8c081fb06d67","assignerShortName":"Linux","cveId":"CVE-2026-89996","datePublished":"2026-09-16T10:33:08.620Z","dateReserved":"2026-09-11T19:38:34.780Z","dateUpdated":"2026-09-16T10:33:08.620Z","state":"PUBLISHED"},"dataType":"CVE_RECORD","dataVersion":"5.2"},"nvd":{"publishedDate":"2026-09-16 11:17:10","lastModifiedDate":"2026-09-16 11:17:10","problem_types":[],"metrics":[],"configurations":[]},"legacy_mitre":{"record":{"CveYear":"2026","CveId":"89996","Ordinal":"1","Title":"dma-buf: dma-heap: don't publish fd before copy_to_user() succee","CVE":"CVE-2026-89996","Year":"2026"},"notes":[{"CveYear":"2026","CveId":"89996","Ordinal":"1","NoteData":"In the Linux kernel, the following vulnerability has been resolved:\n\ndma-buf: dma-heap: don't publish fd before copy_to_user() succeeds\n\nDMA_HEAP_IOCTL_ALLOC allocates a dma-buf and installs an fd into the\ncaller's fd table via dma_buf_fd() -> fd_install() before\ndma_heap_ioctl() copies the result back to userspace.  If the trailing\ncopy_to_user() fails, userspace never learns the fd number, but the\nfd (and the underlying dma-buf reference) are already visible to\nother threads in the same process and are leaked for the lifetime of\nthe process.\n\nThe obvious \"close it on the failure path\" fix is unsafe: once\nfd_install() has run, another thread can already dup() the fd, send\nit via SCM_RIGHTS, or close() it and let its number be reused, so a\nsubsequent close_fd() from the ioctl path can operate on an unrelated\nfile.  This was pointed out by Christian König on v1 [1].\n\nRestructure the allocation path so that fd_install() is the last,\nunfailable step of a successful ioctl:\n\n  1. heap->ops->allocate()      creates the dma_buf.\n  2. get_unused_fd_flags()      reserves an fd number in the caller's\n                                fd table without publishing it, so\n                                no other thread can observe it.\n  3. copy_to_user()             delivers the fd number to userspace;\n                                on failure the fd is returned with\n                                put_unused_fd() and the dma_buf\n                                reference is dropped with\n                                dma_buf_put(), leaving no user-\n                                visible state behind.\n  4. dma_buf_fd_install()       publishes the fd and emits the\n                                trace_dma_buf_fd tracepoint -- from\n                                here on the ioctl cannot fail.\n\nA new dma_buf_fd_install() helper is introduced in dma-buf.c to wrap\nfd_install() together with the DMA_BUF_TRACE() call, preserving the\nexport tracing that dma_buf_fd() provides.  dma_heap_ioctl_allocate()\nis refactored to return the struct dma_buf * directly (returning\nERR_PTR on failure) so the caller holds the dmabuf reference across\nsteps 3 and 4.\n\nThe failure at step 3 is easily reachable from userspace: pass a\nstruct dma_heap_allocation_data that lives in a page whose protection\nis flipped to PROT_READ between copy_from_user() and copy_to_user()\n(e.g. via mprotect()).  Before this change each such ioctl leaks one\ndmabuf fd; after it, the fd table is unchanged on failure and only\n/dev/dma_heap/<name> remains open.\n\nNo UAPI or heap-driver interface change.\n\n[1] https://lore.kernel.org/dri-devel/175e98de-f414-47d7-81c1-c0fe0a8f7f62@amd.com/","Type":"Description","Title":"dma-buf: dma-heap: don't publish fd before copy_to_user() succee"}]}}}