Re: apparmor NULL pointer dereference on resume [efivarfs]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Mar 11, 2025 at 08:16:34AM +0100, Ard Biesheuvel wrote:
> (cc Al Viro)
> 
> On Mon, 10 Mar 2025 at 22:49, James Bottomley
> <James.Bottomley@xxxxxxxxxxxxxxxxxxxxx> wrote:
> >
> > On Mon, 2025-03-10 at 12:57 -0700, Ryan Lee wrote:
> > > On Wed, Mar 5, 2025 at 1:47 PM Malte Schröder
> > > <malte.schroeder@xxxxxxxx> wrote:
> > > >
> > > > On 05/03/2025 20:22, Ryan Lee wrote:
> > > > > On Wed, Mar 5, 2025 at 11:11 AM Malte Schröder
> > > > > <malte.schroeder@xxxxxxxx> wrote:
> > > > > > Hi,
> > > > > >
> > > > > > I hope this is the right place to report this. Since 6.14-rc1
> > > > > > ff. resume
> > > > > > from hibernate does not work anymore. Now I finally managed to
> > > > > > get dmesg
> > > > > > from when this happens (Console is frozen, but managed to login
> > > > > > via
> > > > > > network). If I read that trace correctly there seems to be some
> > > > > > interaction with apparmor. I retried with apparmor disabled and
> > > > > > the
> > > > > > issue didn't trigger.
> > > > > Also CC'ing the AppArmor-specific mailing list in this reply.
> > > > >
> > > > > > I am happy to provide more data if required.
> > > > > Could you try to reproduce this NULL pointer dereference with a
> > > > > clean
> > > > > kernel with debug info (that I'd be able to access the source
> > > > > code of)
> > > > > and send a symbolized stacktrace processed with
> > > > > scripts/decode_stacktrace.sh?
> > > >
> > > > Sure. Result using plain v6.14-rc5:
> > > >
> > > > [  142.014428] BUG: kernel NULL pointer dereference, address:
> > > > 0000000000000018
> > > > [  142.014429] #PF: supervisor read access in kernel mode
> > > > [  142.014431] #PF: error_code(0x0000) - not-present page
> > > > [  142.014432] PGD 0 P4D 0
> > > > [  142.014433] Oops: Oops: 0000 [#1] PREEMPT SMP NOPTI
> > > > [  142.014436] CPU: 4 UID: 0 PID: 6833 Comm: systemd-sleep Not
> > > > tainted
> > > > 6.14.0-rc5 #1
> > > > [  142.014437] Hardware name: To Be Filled By O.E.M. X570
> > > > Extreme4/X570
> > > > Extreme4, BIOS P5.60 01/18/2024
> > > > [  142.014439] RIP: 0010:apparmor_file_open
> > > > (./include/linux/mount.h:78
> > > > (discriminator 2) ./include/linux/fs.h:2781 (discriminator 2)
> > > > security/apparmor/lsm.c:483 (discriminator 2))
> > > > [ 142.014442] Code: c5 00 08 00 00 0f 85 4b 01 00 00 4c 89 e9 31 c0
> > > > f6
> > > > c1 02 0f 85 fd 00 00 00 48 8b 87 88 00 00 00 4c 8d b7 88 00 00 00
> > > > 48 89
> > > > fd <48> 8b 40 18 48 8b 4f 70 0f b7 11 48 89 c7 66 89 54 24 04 48 8b
> > > > 51
> > > > All code
> > > > ========
> > > >    0:    c5 00 08                 (bad)
> > > >    3:    00 00                    add    %al,(%rax)
> > > >    5:    0f 85 4b 01 00 00        jne    0x156
> > > >    b:    4c 89 e9                 mov    %r13,%rcx
> > > >    e:    31 c0                    xor    %eax,%eax
> > > >   10:    f6 c1 02                 test   $0x2,%cl
> > > >   13:    0f 85 fd 00 00 00        jne    0x116
> > > >   19:    48 8b 87 88 00 00 00     mov    0x88(%rdi),%rax
> > > >   20:    4c 8d b7 88 00 00 00     lea    0x88(%rdi),%r14
> > > >   27:    48 89 fd                 mov    %rdi,%rbp
> > > >   2a:*    48 8b 40 18              mov    0x18(%rax),%rax        <-
> > > > -
> > > > trapping instruction
> > > >   2e:    48 8b 4f 70              mov    0x70(%rdi),%rcx
> > > >   32:    0f b7 11                 movzwl (%rcx),%edx
> > > >   35:    48 89 c7                 mov    %rax,%rdi
> > > >   38:    66 89 54 24 04           mov    %dx,0x4(%rsp)
> > > >   3d:    48                       rex.W
> > > >   3e:    8b                       .byte 0x8b
> > > >   3f:    51                       push   %rcx
> > > >
> > > > Code starting with the faulting instruction
> > > > ===========================================
> > > >    0:    48 8b 40 18              mov    0x18(%rax),%rax
> > > >    4:    48 8b 4f 70              mov    0x70(%rdi),%rcx
> > > >    8:    0f b7 11                 movzwl (%rcx),%edx
> > > >    b:    48 89 c7                 mov    %rax,%rdi
> > > >    e:    66 89 54 24 04           mov    %dx,0x4(%rsp)
> > > >   13:    48                       rex.W
> > > >   14:    8b                       .byte 0x8b
> > > >   15:    51                       push   %rcx
> > > > [  142.014443] RSP: 0018:ffffb9ef7189bc50 EFLAGS: 00010246
> > > > [  142.014445] RAX: 0000000000000000 RBX: ffff95eb5e555b00 RCX:
> > > > 0000000000000300
> > > > [  142.014446] RDX: ffff95f838227538 RSI: 00000000002ba677 RDI:
> > > > ffff95e992be2a00
> > > > [  142.014447] RBP: ffff95e992be2a00 R08: ffff95f838227520 R09:
> > > > 0000000000000002
> > > > [  142.014447] R10: ffff95ea72241d00 R11: 0000000000000001 R12:
> > > > 0000000000000010
> > > > [  142.014448] R13: 0000000000000300 R14: ffff95e992be2a88 R15:
> > > > ffff95e95a6034e0
> > > > [  142.014449] FS:  00007f74ab6cf880(0000)
> > > > GS:ffff95f838200000(0000)
> > > > knlGS:0000000000000000
> > > > [  142.014450] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > > > [  142.014451] CR2: 0000000000000018 CR3: 00000002473b6000 CR4:
> > > > 0000000000f50ef0
> > > > [  142.014452] PKRU: 55555554
> > > > [  142.014453] Call Trace:
> > > > [  142.014454]  <TASK>
> > > > [  142.014456] ? __die_body (arch/x86/kernel/dumpstack.c:421)
> > > > [  142.014459] ? page_fault_oops (arch/x86/mm/fault.c:710)
> > > > [  142.014460] ? __lock_acquire (kernel/locking/lockdep.c:?
> > > > kernel/locking/lockdep.c:5174)
> > > > [  142.014462] ? local_lock_acquire
> > > > (./include/linux/local_lock_internal.h:29 (discriminator 1))
> > > > [  142.014465] ? do_user_addr_fault (arch/x86/mm/fault.c:?)
> > > > [  142.014467] ? exc_page_fault
> > > > (./arch/x86/include/asm/irqflags.h:37
> > > > ./arch/x86/include/asm/irqflags.h:92 arch/x86/mm/fault.c:1488
> > > > arch/x86/mm/fault.c:1538)
> > > > [  142.014468] ? asm_exc_page_fault
> > > > (./arch/x86/include/asm/idtentry.h:623)
> > > > [  142.014471] ? apparmor_file_open (./include/linux/mount.h:78
> > > > (discriminator 2) ./include/linux/fs.h:2781 (discriminator 2)
> > > > security/apparmor/lsm.c:483 (discriminator 2))
> > > > [  142.014472] security_file_open (security/security.c:?)
> > > > [  142.014474] do_dentry_open (fs/open.c:934)
> > > > [  142.014476] kernel_file_open (fs/open.c:1201)
> > > > [  142.014477] efivarfs_pm_notify (fs/efivarfs/super.c:505)
> > >
> > > I traced the NULL dereference down to efivarfs_pm_notify creating a
> > > struct path with a NULL .mnt pointer which is then passed into
> > > kernel_file_open, which then invokes the LSM file_open security hook,
> > > where AppArmor is not expecting a path that has a NULL .mnt pointer.
> > > The code in question was introduced in b5d1e6ee761a (efivarfs: add
> > > variable resync after hibernation).
> > >
> > > I have sent in a patch to the AppArmor mailing list at
> > > https://lists.ubuntu.com/archives/apparmor/2025-March/013545.html
> > > which should give improved diagnostics for this case happening again.
> > > My understanding is that path .mnt pointers generally should not be
> > > NULL, but I do not know what an appropriate (non-NULL) value for that
> > > pointer should be, as I am not familiar with the efivarfs subsystem.
> >
> > The problem comes down to the superblock functions not being able to
> > get the struct vfsmount for the superblock (because it isn't even
> > allocated until after they've all been called).  The assumption I was
> > operating under was that provided I added O_NOATIME to prevent the
> > parent directory being updated, passing in a NULL mnt for the purposes
> > of iterating the directory dentry was safe.  What apparmour is trying
> > to do is look up the idmap for the mount point to do one of its checks.
> >
> > There are two ways of fixing this that I can think of.  One would be
> > exporting a function that lets me dig the vfsmount out of s_mounts and
> > use that (it's well hidden in the internals of fs/mount.h, so I suspect
> > this might not be very acceptable) or to get mnt_idmap to return

Nope, please don't.

> > &nop_mnt_idmap if the passed in mnt is NULL.  I'd lean towards the
> > latter, but I'm cc'ing fsdevel to see what others think.

A struct path with mount NULL and dentry != NULL is guaranteed to bit us
in the ass in other places. That's the bug.

> >
> 
> 
> Al spotted the same issue based on a syzbot report [0]
> 
> [0] https://lore.kernel.org/all/20250310235831.GL2023217@ZenIV/

efivars as written only has a single global superblock and it doesn't
support idmapped mounts and I don't see why it ever would.

But since efivars does only ever have a single global superblock, one
possibility is to an internal superblock that always exits and is
resurfaced whenever userspace mounts efivarfs. That's essentially the
devtmpfs model.

Then you can stash:

static struct vfsmount *efivarfs_mnt;

globally and use that in efivarfs_pm_notify() to fill in struct path.




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux