Bug 2532387 (CVE-2026-89483)

Summary: CVE-2026-89483 kernel: nvme: zero the discard fallback page
Product: [Other] Security Response Reporter: OSIDB Bzimport <bzimport>
Component: vulnerabilityAssignee: Product Security DevOps Team <prodsec-dev>
Status: NEW --- QA Contact:
Severity: medium Docs Contact:
Priority: medium    
Version: unspecifiedCC: akhatavk, aos-team-art-private, asdas, dpaolell, jdelft, jupierce, lgarciaa, mbiarnes, ppalepu, ppostler, prdhamdh, rhel-process-autobot, sghai, sidsharm, suppawar, vlaad, watson-tool-maintainers
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: ---
Doc Text:
A flaw was found in the Linux kernel's Non-Volatile Memory Express (NVMe) subsystem. Under specific memory pressure conditions, a local user could trigger a scenario where uninitialized kernel memory is used and potentially exposed. This could lead to information disclosure, revealing sensitive data from the system's memory.
Story Points: ---
Clone Of: Environment:
Last Closed: Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description OSIDB Bzimport 2026-09-11 22:42:23 UTC
In the Linux kernel, the following vulnerability has been resolved:

nvme: zero the discard fallback page

nvme_setup_discard() always maps sizeof(struct nvme_dsm_range) *
NVME_DSM_MAX_RANGES = 4096 bytes as the DSM payload however many ranges
the command declares, because some devices ignore the 'Number of Ranges'
field - the Fixes: commit records two that read past the declared ranges.
A single-range discard fills only the first 16 bytes.

Normally the buffer comes from kzalloc() and the other 4080 bytes are
zero.  When that allocation fails the code falls back to the
per-controller ctrl->discard_page, which nvme_init_ctrl() obtains with
alloc_page(GFP_KERNEL) and nothing ever zeroes, so those 4080 bytes are
whatever the page last held and are handed to the controller.  Reaching
it requires the kzalloc(GFP_ATOMIC | __GFP_NOWARN) to fail, that is
memory pressure; it is not remotely triggerable.  Failing the allocation
under KMSAN reproduces it, with the leaked tail full of vmemmap struct
page pointers.  The extent in the report is a partial transfer of the
payload, not the whole 4096 bytes; the 16-byte boundary in it is the one
declared range:

[   11.991601] BUG: KMSAN: uninit-value in dma_map_phys+0x14c8/0x1900
[   11.991969]  dma_map_phys+0x14c8/0x1900
[   11.992220]  dma_map_page_attrs+0xcf/0x130
[   11.992485]  e1000_xmit_frame+0x4099/0x6d10
[   11.992768]  dev_hard_start_xmit+0x22f/0xa80
[   11.993068]  sch_direct_xmit+0x35c/0xcb0
[   11.993315]  __dev_queue_xmit+0x1ee5/0x5eb0
[   11.993608]  ip_finish_output2+0x1903/0x1c30
[   11.993881]  ip_finish_output+0x288/0x870
[   11.994125]  ip_output+0x15e/0x400
[   11.994365]  __ip_queue_xmit+0x1e85/0x1fb0
[   11.994639]  ip_queue_xmit+0x60/0x80
[   11.994899]  __tcp_transmit_skb+0x4e71/0x5fa0
[   11.995210]  tcp_write_xmit+0x3a36/0x9160
[   11.995533]  __tcp_push_pending_frames+0xc5/0x3c0
[   11.995854]  tcp_push+0x7dc/0x840
[   11.996076]  tcp_sendmsg_locked+0x766c/0x8400
[   11.996371]  tcp_sendmsg+0x4b/0x90
[   11.996572]  inet_sendmsg+0x134/0x2a0
[   11.996823]  __sock_sendmsg+0x265/0x360
[   11.997076]  sock_sendmsg+0x100/0x1e0
[   11.997293]  nvme_tcp_try_send+0x196f/0x6370
[   11.997605]  nvme_tcp_queue_rq+0x1d54/0x20b0
[   11.997882]  blk_mq_dispatch_rq_list+0x5ee/0x2e50
[   11.998175]  __blk_mq_sched_dispatch_requests+0x16dc/0x24a0
[   11.998539]  blk_mq_sched_dispatch_requests+0x11b/0x2c0
[   11.998865]  blk_mq_run_work_fn+0x13b/0x280
[   11.999146]  process_scheduled_works+0x966/0x1ad0
[   11.999465]  worker_thread+0xe44/0x1480
[   11.999709]  kthread+0x53b/0x600
[   11.999927]  ret_from_fork+0x29f/0x7c0
[   12.000191]  ret_from_fork_asm+0x1a/0x30
[   12.000460]
[   12.000558] Uninit was created at:
[   12.000788]  __alloc_frozen_pages_noprof+0x8bf/0xd30
[   12.001096]  alloc_pages_mpol+0x1d0/0x5f0
[   12.001326]  alloc_pages_noprof+0x102/0x290
[   12.001627]  nvme_init_ctrl+0x5a3/0x9f0
[   12.001891]  nvme_tcp_create_ctrl+0xd75/0x19b0
[   12.002170]  nvmf_dev_write+0x4c68/0x4fd0
[   12.002426]  vfs_write+0x587/0x1a10
[   12.002636]  __x64_sys_write+0x207/0x4f0
[   12.002874]  x64_sys_call+0x2ff0/0x3ea0
[   12.003123]  do_syscall_64+0x147/0x3b0
[   12.003400]  entry_SYSCALL_64_after_hwframe+0x77/0x7f
[   12.003680]
[   12.003777] Bytes 16-2843 of 2844 are uninitialized
[   12.004068] Memory access of size 2844 starts at ffff888109f82000
[   12.004412]
[   12.004530] CPU: 0 UID: 0 PID: 101 Comm: kworker/0:1H Not tainted 7.2.0-rc5-NVMECTL-gf5098b6bae76 #1 PREEMPT(lazy)
[   12.005127] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[   12.005762] Workqueue: kblockd blk_mq_run_work_fn
[   12.006073] =====================================================

Allocate the page with __GFP_ZERO.  The single allocation site covers
every use of it: bytes no discard has written stay zero, and bytes one
did write hold that controller's own range list, which it has already
been sent.