Re: [PATCH v6] vfs, security: Fix automount superblock LSM init problem, preventing NFS sb sharing
From: Paul Moore
Date: Wed Aug 02 2023 - 14:16:10 EST
On Aug 2, 2023 Jeff Layton <jlayton@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)
>
> Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
> Signed-off-by: Jeff Layton <jlayton@xxxxxxxxxx>
> Fixes: 9bc61ab18b1d ("vfs: Introduce fs_context, switch vfs_kern_mount() to it.")
> Fixes: 779df6a5480f ("NFS: Ensure security label is set for root inode)
> Tested-by: Jeff Layton <jlayton@xxxxxxxxxx>
> Reviewed-by: Jeff Layton <jlayton@xxxxxxxxxx>
> Acked-by: Casey Schaufler <casey@xxxxxxxxxxxxxxxx>
> Acked-by: "Christian Brauner (Microsoft)" <brauner@xxxxxxxxxx>
> Link: https://lore.kernel.org/r/165962680944.3334508.6610023900349142034.stgit@xxxxxxxxxxxxxxxxxxxxxx/ # v1
> Link: https://lore.kernel.org/r/165962729225.3357250.14350728846471527137.stgit@xxxxxxxxxxxxxxxxxxxxxx/ # v2
> Link: https://lore.kernel.org/r/165970659095.2812394.6868894171102318796.stgit@xxxxxxxxxxxxxxxxxxxxxx/ # v3
> Link: https://lore.kernel.org/r/166133579016.3678898.6283195019480567275.stgit@xxxxxxxxxxxxxxxxxxxxxx/ # v4
> Link: https://lore.kernel.org/r/217595.1662033775@xxxxxxxxxxxxxxxxxxxxxx/ # v5
> ---
> This patch was originally sent by David several months ago, but it
> never got merged. I'm resending to resurrect the discussion. Can we
> get this fixed?
Sorry, I sorta lost track of this after the ROOTCONTEXT_MNT discussion
back in v3. Looking at it a bit closer now I have one nitpicky
request and one larger concern (see below).
> diff --git a/fs/super.c b/fs/super.c
> index e781226e2880..13adf43e2e5d 100644
> --- a/fs/super.c
> +++ b/fs/super.c
> @@ -1541,10 +1541,12 @@ int vfs_get_tree(struct fs_context *fc)
> smp_wmb();
> sb->s_flags |= SB_BORN;
>
> - error = security_sb_set_mnt_opts(sb, fc->security, 0, NULL);
> - if (unlikely(error)) {
> - fc_drop_locked(fc);
> - return error;
> + if (!(fc->lsm_set)) {
> + error = security_sb_set_mnt_opts(sb, fc->security, 0, NULL);
> + if (unlikely(error)) {
> + fc_drop_locked(fc);
> + return error;
> + }
> }
I generally dislike core kernel code which makes LSM calls conditional
on some kernel state maintained outside the LSM. Sometimes it has to
be done as there is no other good options, but I would like us to try
and avoid it if possible. The commit description mentioned that this
was put here to avoid a SELinux complaint, can you provide an example
of the complain? Does it complain about a double/invalid mount, e.g.
"SELinux: mount invalid. Same superblock, different security ..."?
I'd like to understand why the sb_set_mnt_opts() call fails when it
comes after the fs_context_init() call. I'm particulary curious to
know if the failure is due to conflicting SELinux state in the
fs_context, or if it is simply an issue of sb_set_mnt_opts() not
properly handling existing values. Perhaps I'm being overly naive,
but I'm hopeful that we can address both of these within the SELinux
code itself.
In a worst case situation, we could always implement a flag *inside*
the SELinux code, similar to what has been done with 'lsm_set' here.
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index d06e350fedee..29cce0fadbeb 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -2745,6 +2745,30 @@ 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;
> + struct selinux_mnt_opts *opts;
> +
> + if (fc->purpose == FS_CONTEXT_FOR_SUBMOUNT) {
> + opts = kzalloc(sizeof(*opts), GFP_KERNEL);
> + if (!opts)
> + return -ENOMEM;
> +
> + 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 & DEFCONTEXT_MNT)
> + opts->defcontext_sid = sbsec->def_sid;
I acknowledge this is very nitpicky, but we're starting to make a
greater effort towards using consistent style within the SELinux
code. With that in mind, please remove the alignment whitespace in
the assignments above. Thank you.
> + fc->security = opts;
> + }
> +
> + return 0;
> +}
> +
> static int selinux_fs_context_dup(struct fs_context *fc,
> struct fs_context *src_fc)
> {
--
paul-moore.com