lkml.org 
[lkml]   [2020]   [Oct]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.9 395/757] fs: fix NULL dereference due to data race in prepend_path()
    Date
    From: Andrii Nakryiko <andrii@kernel.org>

    [ Upstream commit 09cad07547445bf3a41683e4d3abcd154c123ef5 ]

    Fix data race in prepend_path() with re-reading mnt->mnt_ns twice
    without holding the lock.

    is_mounted() does check for NULL, but is_anon_ns(mnt->mnt_ns) might
    re-read the pointer again which could be NULL already, if in between
    reads one of kern_unmount()/kern_unmount_array()/umount_tree() sets
    mnt->mnt_ns to NULL.

    This is seen in production with the following stack trace:

    BUG: kernel NULL pointer dereference, address: 0000000000000048
    ...
    RIP: 0010:prepend_path.isra.4+0x1ce/0x2e0
    Call Trace:
    d_path+0xe6/0x150
    proc_pid_readlink+0x8f/0x100
    vfs_readlink+0xf8/0x110
    do_readlinkat+0xfd/0x120
    __x64_sys_readlinkat+0x1a/0x20
    do_syscall_64+0x42/0x110
    entry_SYSCALL_64_after_hwframe+0x44/0xa9

    Fixes: f2683bd8d5bd ("[PATCH] fix d_absolute_path() interplay with fsmount()")
    Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
    Reviewed-by: Josef Bacik <josef@toxicpanda.com>
    Cc: Alexander Viro <viro@zeniv.linux.org.uk>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    fs/d_path.c | 6 +++++-
    1 file changed, 5 insertions(+), 1 deletion(-)

    diff --git a/fs/d_path.c b/fs/d_path.c
    index 0f1fc1743302f..a69e2cd36e6e3 100644
    --- a/fs/d_path.c
    +++ b/fs/d_path.c
    @@ -102,6 +102,8 @@ static int prepend_path(const struct path *path,

    if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
    struct mount *parent = READ_ONCE(mnt->mnt_parent);
    + struct mnt_namespace *mnt_ns;
    +
    /* Escaped? */
    if (dentry != vfsmnt->mnt_root) {
    bptr = *buffer;
    @@ -116,7 +118,9 @@ static int prepend_path(const struct path *path,
    vfsmnt = &mnt->mnt;
    continue;
    }
    - if (is_mounted(vfsmnt) && !is_anon_ns(mnt->mnt_ns))
    + mnt_ns = READ_ONCE(mnt->mnt_ns);
    + /* open-coded is_mounted() to use local mnt_ns */
    + if (!IS_ERR_OR_NULL(mnt_ns) && !is_anon_ns(mnt_ns))
    error = 1; // absolute root
    else
    error = 2; // detached or not attached yet
    --
    2.25.1


    \
     
     \ /
      Last update: 2020-10-27 17:11    [W:3.216 / U:0.076 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site