summaryrefslogtreecommitdiffstats
path: root/fs/nfs/super.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r--fs/nfs/super.c68
1 files changed, 63 insertions, 5 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 1fb381843650..f9219024f31a 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -589,8 +589,6 @@ static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags)
struct nfs_server *server = NFS_SB(vfsmnt->mnt_sb);
struct rpc_clnt *rpc;
- shrink_submounts(vfsmnt, &nfs_automount_list);
-
if (!(flags & MNT_FORCE))
return;
/* -EIO all pending I/O */
@@ -632,7 +630,7 @@ static int nfs_verify_server_address(struct sockaddr *addr)
switch (addr->sa_family) {
case AF_INET: {
struct sockaddr_in *sa = (struct sockaddr_in *)addr;
- return sa->sin_addr.s_addr != INADDR_ANY;
+ return sa->sin_addr.s_addr != htonl(INADDR_ANY);
}
case AF_INET6: {
struct in6_addr *sa = &((struct sockaddr_in6 *)addr)->sin6_addr;
@@ -684,8 +682,9 @@ static void nfs_parse_server_address(char *value,
static int nfs_parse_mount_options(char *raw,
struct nfs_parsed_mount_data *mnt)
{
- char *p, *string;
+ char *p, *string, *secdata;
unsigned short port = 0;
+ int rc;
if (!raw) {
dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
@@ -693,6 +692,20 @@ static int nfs_parse_mount_options(char *raw,
}
dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw);
+ secdata = alloc_secdata();
+ if (!secdata)
+ goto out_nomem;
+
+ rc = security_sb_copy_data(raw, secdata);
+ if (rc)
+ goto out_security_failure;
+
+ rc = security_sb_parse_opts_str(secdata, &mnt->lsm_opts);
+ if (rc)
+ goto out_security_failure;
+
+ free_secdata(secdata);
+
while ((p = strsep(&raw, ",")) != NULL) {
substring_t args[MAX_OPT_ARGS];
int option, token;
@@ -1042,7 +1055,10 @@ static int nfs_parse_mount_options(char *raw,
out_nomem:
printk(KERN_INFO "NFS: not enough memory to parse option\n");
return 0;
-
+out_security_failure:
+ free_secdata(secdata);
+ printk(KERN_INFO "NFS: security options invalid: %d\n", rc);
+ return 0;
out_unrec_vers:
printk(KERN_INFO "NFS: unrecognized NFS version number\n");
return 0;
@@ -1214,6 +1230,33 @@ static int nfs_validate_mount_data(void *options,
args->namlen = data->namlen;
args->bsize = data->bsize;
args->auth_flavors[0] = data->pseudoflavor;
+
+ /*
+ * The legacy version 6 binary mount data from userspace has a
+ * field used only to transport selinux information into the
+ * the kernel. To continue to support that functionality we
+ * have a touch of selinux knowledge here in the NFS code. The
+ * userspace code converted context=blah to just blah so we are
+ * converting back to the full string selinux understands.
+ */
+ if (data->context[0]){
+#ifdef CONFIG_SECURITY_SELINUX
+ int rc;
+ char *opts_str = kmalloc(sizeof(data->context) + 8, GFP_KERNEL);
+ if (!opts_str)
+ return -ENOMEM;
+ strcpy(opts_str, "context=");
+ data->context[NFS_MAX_CONTEXT_LEN] = '\0';
+ strcat(opts_str, &data->context[0]);
+ rc = security_sb_parse_opts_str(opts_str, &args->lsm_opts);
+ kfree(opts_str);
+ if (rc)
+ return rc;
+#else
+ return -EINVAL;
+#endif
+ }
+
break;
default: {
unsigned int len;
@@ -1476,6 +1519,8 @@ static int nfs_get_sb(struct file_system_type *fs_type,
};
int error;
+ security_init_mnt_opts(&data.lsm_opts);
+
/* Validate the mount data */
error = nfs_validate_mount_data(raw_data, &data, &mntfh, dev_name);
if (error < 0)
@@ -1515,6 +1560,10 @@ static int nfs_get_sb(struct file_system_type *fs_type,
goto error_splat_super;
}
+ error = security_sb_set_mnt_opts(s, &data.lsm_opts);
+ if (error)
+ goto error_splat_root;
+
s->s_flags |= MS_ACTIVE;
mnt->mnt_sb = s;
mnt->mnt_root = mntroot;
@@ -1523,12 +1572,15 @@ static int nfs_get_sb(struct file_system_type *fs_type,
out:
kfree(data.nfs_server.hostname);
kfree(data.mount_server.hostname);
+ security_free_mnt_opts(&data.lsm_opts);
return error;
out_err_nosb:
nfs_free_server(server);
goto out;
+error_splat_root:
+ dput(mntroot);
error_splat_super:
up_write(&s->s_umount);
deactivate_super(s);
@@ -1608,6 +1660,9 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags,
mnt->mnt_sb = s;
mnt->mnt_root = mntroot;
+ /* clone any lsm security options from the parent to the new sb */
+ security_sb_clone_mnt_opts(data->sb, s);
+
dprintk("<-- nfs_xdev_get_sb() = 0\n");
return 0;
@@ -1850,6 +1905,8 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
};
int error;
+ security_init_mnt_opts(&data.lsm_opts);
+
/* Validate the mount data */
error = nfs4_validate_mount_data(raw_data, &data, dev_name);
if (error < 0)
@@ -1898,6 +1955,7 @@ out:
kfree(data.client_address);
kfree(data.nfs_server.export_path);
kfree(data.nfs_server.hostname);
+ security_free_mnt_opts(&data.lsm_opts);
return error;
out_free: