Re: [syzbot] [integrity] [overlayfs] general protection fault in d_path

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

 



On Fri, Sep 29, 2023 at 3:02 AM Stefan Berger <stefanb@xxxxxxxxxxxxx> wrote:
>
>
> On 9/21/23 07:48, Christian Brauner wrote:
> >
> > Imho, this is all very wild but I'm not judging.
> >
> > Two solutions imho:
> > (1) teach stacking filesystems like overlayfs and ecryptfs to use
> >      vfs_getattr_nosec() in their ->getattr() implementation when they
> >      are themselves called via vfs_getattr_nosec(). This will fix this by
> >      not triggering another LSM hook.
>
> This somewhat lengthy patch I think would be a solution for (1). I don't
> think the Fixes tag is correct but IMO it should propagate farther back,
> if possible.
>
>
>  From 01467f6e879c4cd757abb4d79cb18bf11150bed8 Mon Sep 17 00:00:00 2001
> From: Stefan Berger <stefanb@xxxxxxxxxxxxx>
> Date: Thu, 28 Sep 2023 14:42:39 -0400
> Subject: [PATCH] fs: Enable GETATTR_NOSEC parameter for getattr interface
>   function
>
> When vfs_getattr_nosec() calls a filesystem's getattr interface function
> then the 'nosec' should propagate into this function so that
> vfs_getattr_nosec() can again be called from the filesystem's gettattr
> rather than vfs_getattr(). The latter would add unnecessary security
> checks that the initial vfs_getattr_nosec() call wanted to avoid.
> Therefore, introduce the getattr flag GETATTR_NOSEC and allow to pass
> with the new getattr_flags parameter to the getattr interface function.
> In overlayfs and ecryptfs use this flag to determine which one of the
> two functions to call.
>
> In a recent code change introduced to IMA vfs_getattr_nosec() ended up
> calling vfs_getattr() in overlayfs, which in turn called
> security_inode_getattr() on an exiting process that did not have
> current->fs set anymore, which then caused a kernel NULL pointer
> dereference. With this change the call to security_inode_getattr() can
> be avoided, thus avoiding the NULL pointer dereference.
>
> Reported-by: syzbot+a67fc5321ffb4b311c98@xxxxxxxxxxxxxxxxxxxxxxxxx
> Fixes: db1d1e8b9867 ("IMA: use vfs_getattr_nosec to get the i_version")
> Signed-off-by: Stefan Berger <stefanb@xxxxxxxxxxxxx>
>
> ---
>
> simple_getattr has been adjusted and all files returned by the following
> grep have been adjusted as well.
>
>   grep -rEI "^[[:space:]]+\.getattr" ./ | \
>     grep -v simple_getattr  | \
>     cut -d ":" -f1 | sort | uniq
> ---
>   fs/9p/vfs_inode.c             |  3 ++-
>   fs/9p/vfs_inode_dotl.c        |  3 ++-
>   fs/afs/inode.c                |  3 ++-
>   fs/afs/internal.h             |  2 +-
>   fs/bad_inode.c                |  3 ++-
>   fs/btrfs/inode.c              |  3 ++-
>   fs/ceph/inode.c               |  9 ++++++---
>   fs/ceph/super.h               |  3 ++-
>   fs/coda/coda_linux.h          |  2 +-
>   fs/coda/inode.c               |  3 ++-
>   fs/ecryptfs/inode.c           | 14 ++++++++++----
>   fs/erofs/inode.c              |  2 +-
>   fs/erofs/internal.h           |  2 +-
>   fs/exfat/exfat_fs.h           |  2 +-
>   fs/exfat/file.c               |  2 +-
>   fs/ext2/ext2.h                |  2 +-
>   fs/ext2/inode.c               |  3 ++-
>   fs/ext4/ext4.h                |  6 ++++--
>   fs/ext4/inode.c               |  9 ++++++---
>   fs/ext4/symlink.c             |  6 ++++--
>   fs/f2fs/f2fs.h                |  3 ++-
>   fs/f2fs/file.c                |  3 ++-
>   fs/f2fs/namei.c               |  6 ++++--
>   fs/fat/fat.h                  |  3 ++-
>   fs/fat/file.c                 |  3 ++-
>   fs/fuse/dir.c                 |  3 ++-
>   fs/gfs2/inode.c               |  4 +++-
>   fs/hfsplus/hfsplus_fs.h       |  2 +-
>   fs/hfsplus/inode.c            |  2 +-
>   fs/kernfs/inode.c             |  3 ++-
>   fs/kernfs/kernfs-internal.h   |  3 ++-
>   fs/libfs.c                    |  5 +++--
>   fs/minix/inode.c              |  3 ++-
>   fs/minix/minix.h              |  3 ++-
>   fs/nfs/inode.c                |  3 ++-
>   fs/nfs/namespace.c            |  5 +++--
>   fs/ntfs3/file.c               |  3 ++-
>   fs/ntfs3/ntfs_fs.h            |  3 ++-
>   fs/ocfs2/file.c               |  3 ++-
>   fs/ocfs2/file.h               |  3 ++-
>   fs/orangefs/inode.c           |  3 ++-
>   fs/orangefs/orangefs-kernel.h |  3 ++-
>   fs/overlayfs/inode.c          |  8 ++++++--
>   fs/overlayfs/overlayfs.h      |  3 ++-
>   fs/proc/base.c                |  6 ++++--
>   fs/proc/fd.c                  |  3 ++-
>   fs/proc/generic.c             |  3 ++-
>   fs/proc/internal.h            |  3 ++-
>   fs/proc/proc_net.c            |  3 ++-
>   fs/proc/proc_sysctl.c         |  3 ++-
>   fs/proc/root.c                |  3 ++-
>   fs/smb/client/cifsfs.h        |  3 ++-
>   fs/smb/client/inode.c         |  3 ++-
>   fs/stat.c                     |  3 ++-
>   fs/sysv/itree.c               |  3 ++-
>   fs/sysv/sysv.h                |  2 +-
>   fs/ubifs/dir.c                |  3 ++-
>   fs/ubifs/file.c               |  6 ++++--
>   fs/ubifs/ubifs.h              |  3 ++-
>   fs/udf/symlink.c              |  3 ++-
>   fs/vboxsf/utils.c             |  3 ++-
>   fs/vboxsf/vfsmod.h            |  2 +-
>   fs/xfs/xfs_iops.c             |  3 ++-
>   include/linux/fs.h            | 10 ++++++++--
>   include/linux/nfs_fs.h        |  2 +-
>   mm/shmem.c                    |  3 ++-
>   66 files changed, 159 insertions(+), 82 deletions(-)
>

You can avoid all this churn.
Just use the existing query_flags arg.
Nothing outside the AT_STATX_SYNC_TYPE query_flags is
passed into filesystems from userspace.

Mast out AT_STATX_SYNC_TYPE in vfs_getattr()
And allow kernel internal request_flags in vfs_getattr_nosec()

The AT_ flag namespace is already a challenge, but mixing user
flags and kernel-only flags in vfs interfaces has been done before.

...

> @@ -171,7 +172,10 @@ int ovl_getattr(struct mnt_idmap *idmap, const
> struct path *path,
>
>       type = ovl_path_real(dentry, &realpath);
>       old_cred = ovl_override_creds(dentry->d_sb);
> -    err = vfs_getattr(&realpath, stat, request_mask, flags);
> +    if (getattr_flags & GETATTR_NOSEC)
> +        err = vfs_getattr_nosec(&realpath, stat, request_mask, flags);
> +    else
> +        err = vfs_getattr(&realpath, stat, request_mask, flags);
>       if (err)
>           goto out;
>

There are two more vfs_getattr() calls in this function that you missed.

Please create ovl_do_getattr() inline wrapper in overlayfs.h next to all
the other ovl_do_ wrappers and use it here.

Thanks,
Amir.




[Index of Archives]     [Linux Filesystems Devel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux