linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Qian Cai <cai@lca.pw>
To: Al Viro <viro@zeniv.linux.org.uk>
Cc: Linus Torvalds <torvalds@linux-foundation.org>,
	linux-fsdevel@vger.kernel.org,
	LKML <linux-kernel@vger.kernel.org>
Subject: Re: Null-ptr-deref due to "sanitized pathwalk machinery (v4)"
Date: Tue, 24 Mar 2020 21:49:48 -0400	[thread overview]
Message-ID: <A32DAE66-ADBA-46C7-BD26-F9BA8F12BC18@lca.pw> (raw)
In-Reply-To: <20200324214637.GI23230@ZenIV.linux.org.uk>



> On Mar 24, 2020, at 5:46 PM, Al Viro <viro@zeniv.linux.org.uk> wrote:
> 
> On Tue, Mar 24, 2020 at 05:06:03PM -0400, Qian Cai wrote:
>> Reverted the series on the top of today's linux-next fixed boot crashes.
> 
> Umm...  How about a reproducer (or bisect of vfs.git#work.dotdot, assuming
> it reproduces there)?

Booting powerpc (power9 PowerNV) and arm64 (HPE Apollo 70, Thunder X2) a
few times could trigger it using the configs here,

https://github.com/cailca/linux-mm

> 
>> [   53.027443][ T3519] BUG: Kernel NULL pointer dereference on read at 0x00000000
>> [   53.027480][ T3519] Faulting instruction address: 0xc0000000004dbfa4
>> [   53.027498][ T3519] Oops: Kernel access of bad area, sig: 11 [#1]
>> [   53.027521][ T3519] LE PAGE_SIZE=64K MMU=Radix SMP NR_CPUS=256 DEBUG_PAGEALLOC NUMA PowerNV
>> [   53.027538][ T3519] Modules linked in: kvm_hv kvm ip_tables x_tables xfs sd_mod bnx2x ahci libahci mdio libata tg3 libphy firmware_class dm_mirror dm_region_hash dm_log dm_mod
>> [   53.027594][ T3519] CPU: 36 PID: 3519 Comm: polkitd Not tainted 5.6.0-rc7-next-20200324 #1
>> [   53.027618][ T3519] NIP:  c0000000004dbfa4 LR: c0000000004dc040 CTR: 0000000000000000
>> [   53.027634][ T3519] REGS: c0002013879af810 TRAP: 0300   Not tainted  (5.6.0-rc7-next-20200324)
>> [   53.027668][ T3519] MSR:  9000000000009033 <SF,HV,EE,ME,IR,DR,RI,LE>  CR: 24004422  XER: 20040000
>> [   53.027708][ T3519] CFAR: c0000000004dc044 DAR: 0000000000000000 DSISR: 40000000 IRQMASK: 0 
>> [   53.027708][ T3519] GPR00: c0000000004dc040 c0002013879afaa0 c00000000165a500 0000000000000000 
>> [   53.027708][ T3519] GPR04: c000000001511408 0000000000000000 c0002013879af834 0000000000000002 
>> [   53.027708][ T3519] GPR08: 0000000000000001 0000000000000000 0000000000000000 0000000000000001 
>> [   53.027708][ T3519] GPR12: 0000000000004000 c000001ffffe1e00 0000000000000000 0000000000000000 
>> [   53.027708][ T3519] GPR16: 0000000000000000 0000000000000001 0000000000000000 0000000000000000 
>> [   53.027708][ T3519] GPR20: c000200ea1eacf38 c000201c8102f043 2f2f2f2f2f2f2f2f 0000000000000003 
>> [   53.027708][ T3519] GPR24: 0000000000000000 c0002013879afbc8 fffffffffffff000 0000000000200000 
>> [   53.027708][ T3519] GPR28: ffffffffffffffff 61c8864680b583eb 0000000000000000 0000000000002e2e 
>> [   53.027931][ T3519] NIP [c0000000004dbfa4] link_path_walk+0x284/0x4c0
>> __d_entry_type at include/linux/dcache.h:389
>> (inlined by) d_can_lookup at include/linux/dcache.h:404
>> (inlined by) link_path_walk at fs/namei.c:2178
> 
> ... and apparently NULL nd->path.dentry there.  After walk_component()
> having returned NULL.  Which means either handle_dots() returning NULL
> or step_into() doing the same.  The former means either (for "..")
> step_into() having returned NULL, or nd->path.dentry left unchanged.
> 
> So we either have step_into() returning NULL with nd->path.dentry ending up
> NULL, or we'd entered link_path_walk() with nd->path.dentry being NULL (it
> must have been that way on the entry, or we would've barfed on the previous
> iteration).
> 
> 1) step_into() returns NULL either after
>        if (likely(!d_is_symlink(path.dentry)) ||
>           ((flags & WALK_TRAILING) && !(nd->flags & LOOKUP_FOLLOW)) ||
>           (flags & WALK_NOFOLLOW)) {
>                /* not a symlink or should not follow */
>                if (!(nd->flags & LOOKUP_RCU)) {
>                        dput(nd->path.dentry);
>                        if (nd->path.mnt != path.mnt)
>                                mntput(nd->path.mnt);
>                }  
>                nd->path = path;
>                nd->inode = inode;
>                nd->seq = seq;
>                return NULL;
> in which case nd->path.dentry is left equal to path.dentry, which can't be
> NULL (we would've oopsed on d_is_symlink() if it had been) or it's
> pick_link() returning NULL and leaving NULL nd->path.dentry.
> 
> pick_link() either leaves nd->path unchanged (in which case we are back to
> the "had NULL nd->path.dentry on entry into link_path_walk()") or does
> nd_jump_root() (absolute symlinks) or has ->get_link() call nd_jump_link().
> nd_jump_root() cannot survive leaving NULL in ->path.dentry - it hits
> either
>                d = nd->path.dentry;
>                nd->inode = d->d_inode;
> or
>                nd->inode = nd->path.dentry->d_inode;
> and either would've ooped right there.
> nd_jump_link() hits
>        nd->inode = nd->path.dentry->d_inode;
> on the way out, which also should be impossible to survive.
> 
> So we appear to have hit link_path_walk() with NULL nd->path.dentry.  And
> it's path_lookupat() from vfs_statx(), so we don't have LOOKUP_DOWN there.
> Which means either path_init() leaving NULL nd->path.dentry or lookup_last()
> returning NULL and leaving NULL nd->path.dentry...  The latter is basically
> walk_component(), so we would've had left link_path_walk() without an
> error, with symlink picked and with NULL nd->path.dentry.  Which means
> having the previous call of link_path_walk() also entered with NULL
> nd->path.dentry...
> 
> OK, so it looks like path_init() returning a string and leaving that...
> And I don't see any way for that to happen...
> 
> 
> Right, so...  Could you slap the following
> 	if (WARN_ON(!nd->path.dentry))
> 		printk(KERN_ERR "pathname = %s\n", nd->name->name);
> 1) into beginning of link_path_walk(), right before
>        while (*name=='/')
>                name++;
>        if (!*name)
>                return 0;
> in there.
> 2) into pick_link(), right after
> all_done: // pure jump
> 
> and see what your reproducer catches?

It does not catch anything at all with the patch,

diff --git a/fs/namei.c b/fs/namei.c
index 311e33dbac63..d3ab3dd3e522 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1659,6 +1659,8 @@ static const char *pick_link(struct nameidata *nd, struct path *link,
        if (*res)
                return res;
 all_done: // pure jump
+if (WARN_ON(!nd->path.dentry))
+               printk(KERN_ERR "pathname = %s\n", nd->name->name);
        put_link(nd);
        return NULL;
 }
@@ -2096,6 +2098,8 @@ static int link_path_walk(const char *name, struct nameidata *nd)
        nd->flags |= LOOKUP_PARENT;
        if (IS_ERR(name))
                return PTR_ERR(name);
+if (WARN_ON(!nd->path.dentry))
+               printk(KERN_ERR "pathname = %s\n", nd->name->name);
        while (*name=='/')
                name++;
        if (!*name)


  reply	other threads:[~2020-03-25  1:49 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-24 21:06 Null-ptr-deref due to "sanitized pathwalk machinery (v4)" Qian Cai
2020-03-24 21:46 ` Al Viro
2020-03-25  1:49   ` Qian Cai [this message]
2020-03-25  2:13     ` Al Viro
2020-03-25  3:24       ` Qian Cai
2020-03-25  4:03         ` Al Viro
2020-03-25  5:58           ` Al Viro
2020-03-25 14:02             ` Al Viro
2020-03-25 14:05               ` Al Viro
2020-03-25 19:43             ` Qian Cai
2020-03-25 21:07               ` Al Viro
2020-03-25 13:21           ` Qian Cai

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=A32DAE66-ADBA-46C7-BD26-F9BA8F12BC18@lca.pw \
    --to=cai@lca.pw \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=torvalds@linux-foundation.org \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).