summaryrefslogtreecommitdiff
path: root/fs/nfs
diff options
context:
space:
mode:
authorScott Mayhew <smayhew@redhat.com>2021-06-22 08:11:59 -0400
committerTrond Myklebust <trond.myklebust@hammerspace.com>2021-06-28 09:34:39 -0400
commiteae00c5d6e48ccb2d78ae5873743d7d1a572951b (patch)
tree0477b418a7f0c9da6565a5d73528a9ab376b46ec /fs/nfs
parenta9601ac5e9160a3f96348ebc5d0751397a501701 (diff)
nfs: update has_sec_mnt_opts after cloning lsm options from parent
After calling security_sb_clone_mnt_opts() in nfs_get_root(), it's necessary to copy the value of has_sec_mnt_opts from the cloned super_block's nfs_server. Otherwise, calls to nfs_compare_super() using this super_block may not return the correct result, leading to mount failures. For example, mounting an nfs server with the following in /etc/exports: /export *(rw,insecure,crossmnt,no_root_squash,security_label) and having /export/scratch on a separate block device. mount -o v4.2,context=system_u:object_r:root_t:s0 server:/export/test /mnt/test mount -o v4.2,context=system_u:object_r:swapfile_t:s0 server:/export/scratch /mnt/scratch The second mount would fail with "mount.nfs: /mnt/scratch is busy or already mounted or sharecache fail" and "SELinux: mount invalid. Same superblock, different security settings for..." would appear in the syslog. Also while we're in there, replace several instances of "NFS_SB(s)" with "server", which was already declared at the top of the nfs_get_root(). Fixes: ec1ade6a0448 ("nfs: account for selinux security context when deciding to share superblock") Signed-off-by: Scott Mayhew <smayhew@redhat.com> Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/getroot.c12
1 files changed, 8 insertions, 4 deletions
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index aaeeb4659bff..59355c106ece 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -67,7 +67,7 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i
int nfs_get_root(struct super_block *s, struct fs_context *fc)
{
struct nfs_fs_context *ctx = nfs_fc2context(fc);
- struct nfs_server *server = NFS_SB(s);
+ struct nfs_server *server = NFS_SB(s), *clone_server;
struct nfs_fsinfo fsinfo;
struct dentry *root;
struct inode *inode;
@@ -127,7 +127,7 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
}
spin_unlock(&root->d_lock);
fc->root = root;
- if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
+ if (server->caps & NFS_CAP_SECURITY_LABEL)
kflags |= SECURITY_LSM_NATIVE_LABELS;
if (ctx->clone_data.sb) {
if (d_inode(fc->root)->i_fop != &nfs_dir_operations) {
@@ -137,15 +137,19 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
/* clone lsm security options from the parent to the new sb */
error = security_sb_clone_mnt_opts(ctx->clone_data.sb,
s, kflags, &kflags_out);
+ if (error)
+ goto error_splat_root;
+ clone_server = NFS_SB(ctx->clone_data.sb);
+ server->has_sec_mnt_opts = clone_server->has_sec_mnt_opts;
} else {
error = security_sb_set_mnt_opts(s, fc->security,
kflags, &kflags_out);
}
if (error)
goto error_splat_root;
- if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL &&
+ if (server->caps & NFS_CAP_SECURITY_LABEL &&
!(kflags_out & SECURITY_LSM_NATIVE_LABELS))
- NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL;
+ server->caps &= ~NFS_CAP_SECURITY_LABEL;
nfs_setsecurity(inode, fsinfo.fattr, fsinfo.fattr->label);
error = 0;