Skip to content

Commit 779df6a

Browse files
scottmayhewpcmoore
authored andcommitted
NFS: Ensure security label is set for root inode
When using NFSv4.2, the security label for the root inode should be set via a call to nfs_setsecurity() during the mount process, otherwise the inode will appear as unlabeled for up to acdirmin seconds. Currently the label for the root inode is allocated, retrieved, and freed entirely witin nfs4_proc_get_root(). Add a field for the label to the nfs_fattr struct, and allocate & free the label in nfs_get_root(), where we also add a call to nfs_setsecurity(). Note that for the call to nfs_setsecurity() to succeed, it's necessary to also move the logic calling security_sb_{set,clone}_security() from nfs_get_tree_common() down into nfs_get_root()... otherwise the SBLABEL_MNT flag will not be set in the super_block's security flags and nfs_setsecurity() will silently fail. Reported-by: Richard Haines <[email protected]> Signed-off-by: Scott Mayhew <[email protected]> Acked-by: Stephen Smalley <[email protected]> Tested-by: Stephen Smalley <[email protected]> [PM: fixed 80-char line width problems] Signed-off-by: Paul Moore <[email protected]>
1 parent 2797887 commit 779df6a

File tree

4 files changed

+39
-38
lines changed

4 files changed

+39
-38
lines changed

fs/nfs/getroot.c

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
7373
struct inode *inode;
7474
char *name;
7575
int error = -ENOMEM;
76+
unsigned long kflags = 0, kflags_out = 0;
7677

7778
name = kstrdup(fc->source, GFP_KERNEL);
7879
if (!name)
@@ -83,24 +84,27 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
8384
if (fsinfo.fattr == NULL)
8485
goto out_name;
8586

87+
fsinfo.fattr->label = nfs4_label_alloc(server, GFP_KERNEL);
88+
if (IS_ERR(fsinfo.fattr->label))
89+
goto out_fattr;
8690
error = server->nfs_client->rpc_ops->getroot(server, ctx->mntfh, &fsinfo);
8791
if (error < 0) {
8892
dprintk("nfs_get_root: getattr error = %d\n", -error);
8993
nfs_errorf(fc, "NFS: Couldn't getattr on root");
90-
goto out_fattr;
94+
goto out_label;
9195
}
9296

9397
inode = nfs_fhget(s, ctx->mntfh, fsinfo.fattr, NULL);
9498
if (IS_ERR(inode)) {
9599
dprintk("nfs_get_root: get root inode failed\n");
96100
error = PTR_ERR(inode);
97101
nfs_errorf(fc, "NFS: Couldn't get root inode");
98-
goto out_fattr;
102+
goto out_label;
99103
}
100104

101105
error = nfs_superblock_set_dummy_root(s, inode);
102106
if (error != 0)
103-
goto out_fattr;
107+
goto out_label;
104108

105109
/* root dentries normally start off anonymous and get spliced in later
106110
* if the dentry tree reaches them; however if the dentry already
@@ -111,7 +115,7 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
111115
dprintk("nfs_get_root: get root dentry failed\n");
112116
error = PTR_ERR(root);
113117
nfs_errorf(fc, "NFS: Couldn't get root dentry");
114-
goto out_fattr;
118+
goto out_label;
115119
}
116120

117121
security_d_instantiate(root, inode);
@@ -123,12 +127,39 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
123127
}
124128
spin_unlock(&root->d_lock);
125129
fc->root = root;
130+
if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
131+
kflags |= SECURITY_LSM_NATIVE_LABELS;
132+
if (ctx->clone_data.sb) {
133+
if (d_inode(fc->root)->i_fop != &nfs_dir_operations) {
134+
error = -ESTALE;
135+
goto error_splat_root;
136+
}
137+
/* clone lsm security options from the parent to the new sb */
138+
error = security_sb_clone_mnt_opts(ctx->clone_data.sb,
139+
s, kflags, &kflags_out);
140+
} else {
141+
error = security_sb_set_mnt_opts(s, fc->security,
142+
kflags, &kflags_out);
143+
}
144+
if (error)
145+
goto error_splat_root;
146+
if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL &&
147+
!(kflags_out & SECURITY_LSM_NATIVE_LABELS))
148+
NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL;
149+
150+
nfs_setsecurity(inode, fsinfo.fattr, fsinfo.fattr->label);
126151
error = 0;
127152

153+
out_label:
154+
nfs4_label_free(fsinfo.fattr->label);
128155
out_fattr:
129156
nfs_free_fattr(fsinfo.fattr);
130157
out_name:
131158
kfree(name);
132159
out:
133160
return error;
161+
error_splat_root:
162+
dput(fc->root);
163+
fc->root = NULL;
164+
goto out_label;
134165
}

fs/nfs/nfs4proc.c

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3988,31 +3988,25 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
39883988
{
39893989
int error;
39903990
struct nfs_fattr *fattr = info->fattr;
3991-
struct nfs4_label *label = NULL;
3991+
struct nfs4_label *label = fattr->label;
39923992

39933993
error = nfs4_server_capabilities(server, mntfh);
39943994
if (error < 0) {
39953995
dprintk("nfs4_get_root: getcaps error = %d\n", -error);
39963996
return error;
39973997
}
39983998

3999-
label = nfs4_label_alloc(server, GFP_KERNEL);
4000-
if (IS_ERR(label))
4001-
return PTR_ERR(label);
4002-
40033999
error = nfs4_proc_getattr(server, mntfh, fattr, label, NULL);
40044000
if (error < 0) {
40054001
dprintk("nfs4_get_root: getattr error = %d\n", -error);
4006-
goto err_free_label;
4002+
goto out;
40074003
}
40084004

40094005
if (fattr->valid & NFS_ATTR_FATTR_FSID &&
40104006
!nfs_fsid_equal(&server->fsid, &fattr->fsid))
40114007
memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
40124008

4013-
err_free_label:
4014-
nfs4_label_free(label);
4015-
4009+
out:
40164010
return error;
40174011
}
40184012

fs/nfs/super.c

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,7 +1179,6 @@ int nfs_get_tree_common(struct fs_context *fc)
11791179
struct super_block *s;
11801180
int (*compare_super)(struct super_block *, struct fs_context *) = nfs_compare_super;
11811181
struct nfs_server *server = ctx->server;
1182-
unsigned long kflags = 0, kflags_out = 0;
11831182
int error;
11841183

11851184
ctx->server = NULL;
@@ -1239,26 +1238,6 @@ int nfs_get_tree_common(struct fs_context *fc)
12391238
goto error_splat_super;
12401239
}
12411240

1242-
if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
1243-
kflags |= SECURITY_LSM_NATIVE_LABELS;
1244-
if (ctx->clone_data.sb) {
1245-
if (d_inode(fc->root)->i_fop != &nfs_dir_operations) {
1246-
error = -ESTALE;
1247-
goto error_splat_root;
1248-
}
1249-
/* clone any lsm security options from the parent to the new sb */
1250-
error = security_sb_clone_mnt_opts(ctx->clone_data.sb, s, kflags,
1251-
&kflags_out);
1252-
} else {
1253-
error = security_sb_set_mnt_opts(s, fc->security,
1254-
kflags, &kflags_out);
1255-
}
1256-
if (error)
1257-
goto error_splat_root;
1258-
if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL &&
1259-
!(kflags_out & SECURITY_LSM_NATIVE_LABELS))
1260-
NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL;
1261-
12621241
s->s_flags |= SB_ACTIVE;
12631242
error = 0;
12641243

@@ -1268,10 +1247,6 @@ int nfs_get_tree_common(struct fs_context *fc)
12681247
out_err_nosb:
12691248
nfs_free_server(server);
12701249
goto out;
1271-
1272-
error_splat_root:
1273-
dput(fc->root);
1274-
fc->root = NULL;
12751250
error_splat_super:
12761251
deactivate_locked_super(s);
12771252
goto out;

include/linux/nfs_xdr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ struct nfs_fattr {
7575
struct nfs4_string *owner_name;
7676
struct nfs4_string *group_name;
7777
struct nfs4_threshold *mdsthreshold; /* pNFS threshold hints */
78+
struct nfs4_label *label;
7879
};
7980

8081
#define NFS_ATTR_FATTR_TYPE (1U << 0)

0 commit comments

Comments
 (0)