Thread (6 messages) 6 messages, 4 authors, 2022-08-19

Re: [PATCH v3] nfs: Fix automount superblock LSM init problem, preventing sb sharing

From: Paul Moore <paul@paul-moore.com>
Date: 2022-08-16 06:39:32
Also in: linux-fsdevel, linux-nfs, lkml, selinux

On Thu, Aug 11, 2022 at 8:28 AM Ondrej Mosnacek [off-list ref] wrote:
On Fri, Aug 5, 2022 at 3:36 PM David Howells [off-list ref] wrote:
quoted
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@redhat.com>
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 <redacted>
cc: Anna Schumaker <anna@kernel.org>
cc: Alexander Viro <viro@zeniv.linux.org.uk>
cc: Scott Mayhew <redacted>
cc: Jeff Layton <jlayton@kernel.org>
cc: Paul Moore <paul@paul-moore.com>
cc: Casey Schaufler <casey@schaufler-ca.com>
cc: linux-nfs@vger.kernel.org
cc: selinux@vger.kernel.org
cc: linux-security-module@vger.kernel.org
cc: linux-fsdevel@vger.kernel.org
---

 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>
quoted
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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help