Re: [PATCH v3] nfs: Fix automount superblock LSM init problem, preventing sb sharing
From: Paul Moore
Date: Tue Aug 16 2022 - 02:39:41 EST
On Thu, Aug 11, 2022 at 8:28 AM Ondrej Mosnacek <omosnace@xxxxxxxxxx> wrote:
> On Fri, Aug 5, 2022 at 3:36 PM David Howells <dhowells@xxxxxxxxxx> wrote:
> > When NFS superblocks are created by automounting, their LSM parameters
> > aren't set in the fs_context struct prior to sget_fc() being called,
> > leading to failure to match existing superblocks.
> >
> > Fix this by adding a new LSM hook to load fc->security for submount
> > creation when alloc_fs_context() is creating the fs_context for it.
> >
> > However, this uncovers a further bug: nfs_get_root() initialises the
> > superblock security manually by calling security_sb_set_mnt_opts() or
> > security_sb_clone_mnt_opts() - but then vfs_get_tree() calls
> > security_sb_set_mnt_opts(), which can lead to SELinux, at least,
> > complaining.
> >
> > Fix that by adding a flag to the fs_context that suppresses the
> > security_sb_set_mnt_opts() call in vfs_get_tree(). This can be set by NFS
> > when it sets the LSM context on the new superblock.
> >
> > The first bug leads to messages like the following appearing in dmesg:
> >
> > NFS: Cache volume key already in use (nfs,4.2,2,108,106a8c0,1,,,,100000,100000,2ee,3a98,1d4c,3a98,1)
> >
> > Changes
> > =======
> > ver #2)
> > - Made LSM parameter extraction dependent on fc->purpose ==
> > FS_CONTEXT_FOR_SUBMOUNT. Shouldn't happen on FOR_RECONFIGURE.
> >
> > ver #2)
> > - Added Smack support
> > - Made LSM parameter extraction dependent on reference != NULL.
> >
> > Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
> > Fixes: 9bc61ab18b1d ("vfs: Introduce fs_context, switch vfs_kern_mount() to it.")
> > Fixes: 779df6a5480f ("NFS: Ensure security label is set for root inode)
> > cc: Trond Myklebust <trond.myklebust@xxxxxxxxxxxxxxx>
> > cc: Anna Schumaker <anna@xxxxxxxxxx>
> > cc: Alexander Viro <viro@xxxxxxxxxxxxxxxxxx>
> > cc: Scott Mayhew <smayhew@xxxxxxxxxx>
> > cc: Jeff Layton <jlayton@xxxxxxxxxx>
> > cc: Paul Moore <paul@xxxxxxxxxxxxxx>
> > cc: Casey Schaufler <casey@xxxxxxxxxxxxxxxx>
> > cc: linux-nfs@xxxxxxxxxxxxxxx
> > cc: selinux@xxxxxxxxxxxxxxx
> > cc: linux-security-module@xxxxxxxxxxxxxxx
> > cc: linux-fsdevel@xxxxxxxxxxxxxxx
> > ---
> >
> > fs/fs_context.c | 4 +++
> > fs/nfs/getroot.c | 1 +
> > fs/super.c | 10 ++++---
> > include/linux/fs_context.h | 1 +
> > include/linux/lsm_hook_defs.h | 1 +
> > include/linux/lsm_hooks.h | 6 +++-
> > include/linux/security.h | 6 ++++
> > security/security.c | 5 +++
> > security/selinux/hooks.c | 29 +++++++++++++++++++
> > security/smack/smack_lsm.c | 61 +++++++++++++++++++++++++++++++++++++++++
> > 10 files changed, 119 insertions(+), 5 deletions(-)
>
> <snip>
>
> > diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> > index 1bbd53321d13..ddeaff4f3bb1 100644
> > --- a/security/selinux/hooks.c
> > +++ b/security/selinux/hooks.c
> > @@ -2768,6 +2768,34 @@ static int selinux_umount(struct vfsmount *mnt, int flags)
> > FILESYSTEM__UNMOUNT, NULL);
> > }
> >
> > +static int selinux_fs_context_init(struct fs_context *fc,
> > + struct dentry *reference)
> > +{
> > + const struct superblock_security_struct *sbsec;
> > + const struct inode_security_struct *root_isec;
> > + struct selinux_mnt_opts *opts;
> > +
> > + if (fc->purpose == FS_CONTEXT_FOR_SUBMOUNT) {
> > + opts = kzalloc(sizeof(*opts), GFP_KERNEL);
> > + if (!opts)
> > + return -ENOMEM;
> > +
> > + root_isec = backing_inode_security(reference->d_sb->s_root);
> > + sbsec = selinux_superblock(reference->d_sb);
> > + if (sbsec->flags & FSCONTEXT_MNT)
> > + opts->fscontext_sid = sbsec->sid;
> > + if (sbsec->flags & CONTEXT_MNT)
> > + opts->context_sid = sbsec->mntpoint_sid;
> > + if (sbsec->flags & ROOTCONTEXT_MNT)
> > + opts->rootcontext_sid = root_isec->sid;
>
> I wonder if this part is correct... The rootcontext=... mount option
> relates to the root inode of the mount where it is specified - i.e. in
> case of NFS only to the toplevel inode of the initial mount. Setting
> the same context on the root inode of submounts, which AFAIK are
> supposed to be transparent to the user, doesn't seem correct to me -
> i.e. it should just be left unset for the automatically created
> submounts.
Like Ondrej, I'm not going to say I'm very comfortable with some of
the VFS corner cases, but this is an interesting case ... as far as I
can tell, the submount has a superblock and is treated like a normal
filesystem mount with the one exception that it is mounted
automatically so that users might not be aware it is a separate mount.
I guess my question is this: for inodes inside the superblock, does
their superblock pointer point to the submount's superblock, or the
parent filesystem's superblock?
--
paul-moore.com