• Axel Rasmussen's avatar
    mm/secretmem: fix panic when growing a memfd_secret · f9b141f9
    Axel Rasmussen authored
    When one tries to grow an existing memfd_secret with ftruncate, one gets
    a panic [1].  For example, doing the following reliably induces the
    panic:
    
        fd = memfd_secret();
    
        ftruncate(fd, 10);
        ptr = mmap(NULL, 10, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
        strcpy(ptr, "123456789");
    
        munmap(ptr, 10);
        ftruncate(fd, 20);
    
    The basic reason for this is, when we grow with ftruncate, we call down
    into simple_setattr, and then truncate_inode_pages_range, and eventually
    we try to zero part of the memory.  The normal truncation code does this
    via the direct map (i.e., it calls page_address() and hands that to
    memset()).
    
    For memfd_secret though, we specifically don't map our pages via the
    direct map (i.e.  we call set_direct_map_invalid_noflush() on every
    fault).  So the address returned by page_address() isn't useful, and
    when we try to memset() with it we panic.
    
    This patch avoids the panic by implementing a custom setattr for
    memfd_secret, which detects resizes specifically (setting the size for
    the first time works just fine, since there are no existing pages to try
    to zero), and rejects them with EINVAL.
    
    One could argue growing should be supported, but I think that will
    require a significantly more lengthy change.  So, I propose a minimal
    fix for the benefit of stable kernels, and then perhaps to extend
    memfd_secret to support growing in a separate patch.
    
    [1]:
    
      BUG: unable to handle page fault for address: ffffa0a889277028
      #PF: supervisor write access in kernel mode
      #PF: error_code(0x0002) - not-present page
      PGD afa01067 P4D afa01067 PUD 83f909067 PMD 83f8bf067 PTE 800ffffef6d88060
      Oops: 0002 [#1] PREEMPT SMP DEBUG_PAGEALLOC PTI
      CPU: 0 PID: 281 Comm: repro Not tainted 5.17.0-dbg-DEV #1
      Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
      RIP: 0010:memset_erms+0x9/0x10
      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 <f3> aa 4c 89 c8 c3 90 49 89 fa 40 0f b6 ce 48 b8 01 01 01 01 01 01
      RSP: 0018:ffffb932c09afbf0 EFLAGS: 00010246
      RAX: 0000000000000000 RBX: ffffda63c4249dc0 RCX: 0000000000000fd8
      RDX: 0000000000000fd8 RSI: 0000000000000000 RDI: ffffa0a889277028
      RBP: ffffb932c09afc00 R08: 0000000000001000 R09: ffffa0a889277028
      R10: 0000000000020023 R11: 0000000000000000 R12: ffffda63c4249dc0
      R13: ffffa0a890d70d98 R14: 0000000000000028 R15: 0000000000000fd8
      FS:  00007f7294899580(0000) GS:ffffa0af9bc00000(0000) knlGS:0000000000000000
      CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
      CR2: ffffa0a889277028 CR3: 0000000107ef6006 CR4: 0000000000370ef0
      DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
      DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
      Call Trace:
       ? zero_user_segments+0x82/0x190
       truncate_inode_partial_folio+0xd4/0x2a0
       truncate_inode_pages_range+0x380/0x830
       truncate_setsize+0x63/0x80
       simple_setattr+0x37/0x60
       notify_change+0x3d8/0x4d0
       do_sys_ftruncate+0x162/0x1d0
       __x64_sys_ftruncate+0x1c/0x20
       do_syscall_64+0x44/0xa0
       entry_SYSCALL_64_after_hwframe+0x44/0xae
      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
      CR2: ffffa0a889277028
    
    [lkp@intel.com: secretmem_iops can be static]
    Signed-off-by: default avatarkernel test robot <lkp@intel.com>
    [axelrasmussen@google.com: return EINVAL]
    
    Link: https://lkml.kernel.org/r/20220324210909.1843814-1-axelrasmussen@google.com
    Link: https://lkml.kernel.org/r/20220412193023.279320-1-axelrasmussen@google.comSigned-off-by: default avatarAxel Rasmussen <axelrasmussen@google.com>
    Cc: Mike Rapoport <rppt@kernel.org>
    Cc: Matthew Wilcox <willy@infradead.org>
    Cc: <stable@vger.kernel.org>
    Cc: kernel test robot <lkp@intel.com>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    f9b141f9
secretmem.c 5.96 KB