CVE-2022-49049
Publication date:
26/02/2025
In the Linux kernel, the following vulnerability has been resolved:<br />
<br />
mm/secretmem: fix panic when growing a memfd_secret<br />
<br />
When one tries to grow an existing memfd_secret with ftruncate, one gets<br />
a panic [1]. For example, doing the following reliably induces the<br />
panic:<br />
<br />
fd = memfd_secret();<br />
<br />
ftruncate(fd, 10);<br />
ptr = mmap(NULL, 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);<br />
strcpy(ptr, "123456789");<br />
<br />
munmap(ptr, 10);<br />
ftruncate(fd, 20);<br />
<br />
The basic reason for this is, when we grow with ftruncate, we call down<br />
into simple_setattr, and then truncate_inode_pages_range, and eventually<br />
we try to zero part of the memory. The normal truncation code does this<br />
via the direct map (i.e., it calls page_address() and hands that to<br />
memset()).<br />
<br />
For memfd_secret though, we specifically don&#39;t map our pages via the<br />
direct map (i.e. we call set_direct_map_invalid_noflush() on every<br />
fault). So the address returned by page_address() isn&#39;t useful, and<br />
when we try to memset() with it we panic.<br />
<br />
This patch avoids the panic by implementing a custom setattr for<br />
memfd_secret, which detects resizes specifically (setting the size for<br />
the first time works just fine, since there are no existing pages to try<br />
to zero), and rejects them with EINVAL.<br />
<br />
One could argue growing should be supported, but I think that will<br />
require a significantly more lengthy change. So, I propose a minimal<br />
fix for the benefit of stable kernels, and then perhaps to extend<br />
memfd_secret to support growing in a separate patch.<br />
<br />
[1]:<br />
<br />
BUG: unable to handle page fault for address: ffffa0a889277028<br />
#PF: supervisor write access in kernel mode<br />
#PF: error_code(0x0002) - not-present page<br />
PGD afa01067 P4D afa01067 PUD 83f909067 PMD 83f8bf067 PTE 800ffffef6d88060<br />
Oops: 0002 [#1] PREEMPT SMP DEBUG_PAGEALLOC PTI<br />
CPU: 0 PID: 281 Comm: repro Not tainted 5.17.0-dbg-DEV #1<br />
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014<br />
RIP: 0010:memset_erms+0x9/0x10<br />
Code: c1 e9 03 40 0f b6 f6 48 b8 01 01 01 01 01 01 01 01 48 0f af c6 f3 48 ab 89 d1 f3 aa 4c 89 c8 c3 90 49 89 f9 40 88 f0 48 89 d1 aa 4c 89 c8 c3 90 49 89 fa 40 0f b6 ce 48 b8 01 01 01 01 01 01<br />
RSP: 0018:ffffb932c09afbf0 EFLAGS: 00010246<br />
RAX: 0000000000000000 RBX: ffffda63c4249dc0 RCX: 0000000000000fd8<br />
RDX: 0000000000000fd8 RSI: 0000000000000000 RDI: ffffa0a889277028<br />
RBP: ffffb932c09afc00 R08: 0000000000001000 R09: ffffa0a889277028<br />
R10: 0000000000020023 R11: 0000000000000000 R12: ffffda63c4249dc0<br />
R13: ffffa0a890d70d98 R14: 0000000000000028 R15: 0000000000000fd8<br />
FS: 00007f7294899580(0000) GS:ffffa0af9bc00000(0000) knlGS:0000000000000000<br />
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033<br />
CR2: ffffa0a889277028 CR3: 0000000107ef6006 CR4: 0000000000370ef0<br />
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000<br />
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400<br />
Call Trace:<br />
? zero_user_segments+0x82/0x190<br />
truncate_inode_partial_folio+0xd4/0x2a0<br />
truncate_inode_pages_range+0x380/0x830<br />
truncate_setsize+0x63/0x80<br />
simple_setattr+0x37/0x60<br />
notify_change+0x3d8/0x4d0<br />
do_sys_ftruncate+0x162/0x1d0<br />
__x64_sys_ftruncate+0x1c/0x20<br />
do_syscall_64+0x44/0xa0<br />
entry_SYSCALL_64_after_hwframe+0x44/0xae<br />
Modules linked in: xhci_pci xhci_hcd virtio_net net_failover failover virtio_blk virtio_balloon uhci_hcd ohci_pci ohci_hcd evdev ehci_pci ehci_hcd 9pnet_virtio 9p netfs 9pnet<br />
CR2: ffffa0a889277028<br />
<br />
[lkp@intel.com: secretmem_iops can be static]<br />
[axelrasmussen@google.com: return EINVAL]
Severity CVSS v4.0: Pending analysis
Last modification:
14/10/2025