diff options
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/internal.h | 3 | ||||
-rw-r--r-- | fs/nfs/super.c | 64 |
2 files changed, 65 insertions, 2 deletions
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 0f5619611b8d..931992763e68 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -3,6 +3,7 @@ | |||
3 | */ | 3 | */ |
4 | 4 | ||
5 | #include <linux/mount.h> | 5 | #include <linux/mount.h> |
6 | #include <linux/security.h> | ||
6 | 7 | ||
7 | struct nfs_string; | 8 | struct nfs_string; |
8 | 9 | ||
@@ -57,6 +58,8 @@ struct nfs_parsed_mount_data { | |||
57 | char *export_path; | 58 | char *export_path; |
58 | int protocol; | 59 | int protocol; |
59 | } nfs_server; | 60 | } nfs_server; |
61 | |||
62 | struct security_mnt_opts lsm_opts; | ||
60 | }; | 63 | }; |
61 | 64 | ||
62 | /* client.c */ | 65 | /* client.c */ |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 1fb381843650..fcf4b982c885 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -684,8 +684,9 @@ static void nfs_parse_server_address(char *value, | |||
684 | static int nfs_parse_mount_options(char *raw, | 684 | static int nfs_parse_mount_options(char *raw, |
685 | struct nfs_parsed_mount_data *mnt) | 685 | struct nfs_parsed_mount_data *mnt) |
686 | { | 686 | { |
687 | char *p, *string; | 687 | char *p, *string, *secdata; |
688 | unsigned short port = 0; | 688 | unsigned short port = 0; |
689 | int rc; | ||
689 | 690 | ||
690 | if (!raw) { | 691 | if (!raw) { |
691 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); | 692 | dfprintk(MOUNT, "NFS: mount options string was NULL.\n"); |
@@ -693,6 +694,20 @@ static int nfs_parse_mount_options(char *raw, | |||
693 | } | 694 | } |
694 | dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw); | 695 | dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw); |
695 | 696 | ||
697 | secdata = alloc_secdata(); | ||
698 | if (!secdata) | ||
699 | goto out_nomem; | ||
700 | |||
701 | rc = security_sb_copy_data(raw, secdata); | ||
702 | if (rc) | ||
703 | goto out_security_failure; | ||
704 | |||
705 | rc = security_sb_parse_opts_str(secdata, &mnt->lsm_opts); | ||
706 | if (rc) | ||
707 | goto out_security_failure; | ||
708 | |||
709 | free_secdata(secdata); | ||
710 | |||
696 | while ((p = strsep(&raw, ",")) != NULL) { | 711 | while ((p = strsep(&raw, ",")) != NULL) { |
697 | substring_t args[MAX_OPT_ARGS]; | 712 | substring_t args[MAX_OPT_ARGS]; |
698 | int option, token; | 713 | int option, token; |
@@ -1042,7 +1057,10 @@ static int nfs_parse_mount_options(char *raw, | |||
1042 | out_nomem: | 1057 | out_nomem: |
1043 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); | 1058 | printk(KERN_INFO "NFS: not enough memory to parse option\n"); |
1044 | return 0; | 1059 | return 0; |
1045 | 1060 | out_security_failure: | |
1061 | free_secdata(secdata); | ||
1062 | printk(KERN_INFO "NFS: security options invalid: %d\n", rc); | ||
1063 | return 0; | ||
1046 | out_unrec_vers: | 1064 | out_unrec_vers: |
1047 | printk(KERN_INFO "NFS: unrecognized NFS version number\n"); | 1065 | printk(KERN_INFO "NFS: unrecognized NFS version number\n"); |
1048 | return 0; | 1066 | return 0; |
@@ -1214,6 +1232,33 @@ static int nfs_validate_mount_data(void *options, | |||
1214 | args->namlen = data->namlen; | 1232 | args->namlen = data->namlen; |
1215 | args->bsize = data->bsize; | 1233 | args->bsize = data->bsize; |
1216 | args->auth_flavors[0] = data->pseudoflavor; | 1234 | args->auth_flavors[0] = data->pseudoflavor; |
1235 | |||
1236 | /* | ||
1237 | * The legacy version 6 binary mount data from userspace has a | ||
1238 | * field used only to transport selinux information into the | ||
1239 | * the kernel. To continue to support that functionality we | ||
1240 | * have a touch of selinux knowledge here in the NFS code. The | ||
1241 | * userspace code converted context=blah to just blah so we are | ||
1242 | * converting back to the full string selinux understands. | ||
1243 | */ | ||
1244 | if (data->context[0]){ | ||
1245 | #ifdef CONFIG_SECURITY_SELINUX | ||
1246 | int rc; | ||
1247 | char *opts_str = kmalloc(sizeof(data->context) + 8, GFP_KERNEL); | ||
1248 | if (!opts_str) | ||
1249 | return -ENOMEM; | ||
1250 | strcpy(opts_str, "context="); | ||
1251 | data->context[NFS_MAX_CONTEXT_LEN] = '\0'; | ||
1252 | strcat(opts_str, &data->context[0]); | ||
1253 | rc = security_sb_parse_opts_str(opts_str, &args->lsm_opts); | ||
1254 | kfree(opts_str); | ||
1255 | if (rc) | ||
1256 | return rc; | ||
1257 | #else | ||
1258 | return -EINVAL; | ||
1259 | #endif | ||
1260 | } | ||
1261 | |||
1217 | break; | 1262 | break; |
1218 | default: { | 1263 | default: { |
1219 | unsigned int len; | 1264 | unsigned int len; |
@@ -1476,6 +1521,8 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
1476 | }; | 1521 | }; |
1477 | int error; | 1522 | int error; |
1478 | 1523 | ||
1524 | security_init_mnt_opts(&data.lsm_opts); | ||
1525 | |||
1479 | /* Validate the mount data */ | 1526 | /* Validate the mount data */ |
1480 | error = nfs_validate_mount_data(raw_data, &data, &mntfh, dev_name); | 1527 | error = nfs_validate_mount_data(raw_data, &data, &mntfh, dev_name); |
1481 | if (error < 0) | 1528 | if (error < 0) |
@@ -1515,6 +1562,10 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
1515 | goto error_splat_super; | 1562 | goto error_splat_super; |
1516 | } | 1563 | } |
1517 | 1564 | ||
1565 | error = security_sb_set_mnt_opts(s, &data.lsm_opts); | ||
1566 | if (error) | ||
1567 | goto error_splat_root; | ||
1568 | |||
1518 | s->s_flags |= MS_ACTIVE; | 1569 | s->s_flags |= MS_ACTIVE; |
1519 | mnt->mnt_sb = s; | 1570 | mnt->mnt_sb = s; |
1520 | mnt->mnt_root = mntroot; | 1571 | mnt->mnt_root = mntroot; |
@@ -1523,12 +1574,15 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
1523 | out: | 1574 | out: |
1524 | kfree(data.nfs_server.hostname); | 1575 | kfree(data.nfs_server.hostname); |
1525 | kfree(data.mount_server.hostname); | 1576 | kfree(data.mount_server.hostname); |
1577 | security_free_mnt_opts(&data.lsm_opts); | ||
1526 | return error; | 1578 | return error; |
1527 | 1579 | ||
1528 | out_err_nosb: | 1580 | out_err_nosb: |
1529 | nfs_free_server(server); | 1581 | nfs_free_server(server); |
1530 | goto out; | 1582 | goto out; |
1531 | 1583 | ||
1584 | error_splat_root: | ||
1585 | dput(mntroot); | ||
1532 | error_splat_super: | 1586 | error_splat_super: |
1533 | up_write(&s->s_umount); | 1587 | up_write(&s->s_umount); |
1534 | deactivate_super(s); | 1588 | deactivate_super(s); |
@@ -1608,6 +1662,9 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, | |||
1608 | mnt->mnt_sb = s; | 1662 | mnt->mnt_sb = s; |
1609 | mnt->mnt_root = mntroot; | 1663 | mnt->mnt_root = mntroot; |
1610 | 1664 | ||
1665 | /* clone any lsm security options from the parent to the new sb */ | ||
1666 | security_sb_clone_mnt_opts(data->sb, s); | ||
1667 | |||
1611 | dprintk("<-- nfs_xdev_get_sb() = 0\n"); | 1668 | dprintk("<-- nfs_xdev_get_sb() = 0\n"); |
1612 | return 0; | 1669 | return 0; |
1613 | 1670 | ||
@@ -1850,6 +1907,8 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
1850 | }; | 1907 | }; |
1851 | int error; | 1908 | int error; |
1852 | 1909 | ||
1910 | security_init_mnt_opts(&data.lsm_opts); | ||
1911 | |||
1853 | /* Validate the mount data */ | 1912 | /* Validate the mount data */ |
1854 | error = nfs4_validate_mount_data(raw_data, &data, dev_name); | 1913 | error = nfs4_validate_mount_data(raw_data, &data, dev_name); |
1855 | if (error < 0) | 1914 | if (error < 0) |
@@ -1898,6 +1957,7 @@ out: | |||
1898 | kfree(data.client_address); | 1957 | kfree(data.client_address); |
1899 | kfree(data.nfs_server.export_path); | 1958 | kfree(data.nfs_server.export_path); |
1900 | kfree(data.nfs_server.hostname); | 1959 | kfree(data.nfs_server.hostname); |
1960 | security_free_mnt_opts(&data.lsm_opts); | ||
1901 | return error; | 1961 | return error; |
1902 | 1962 | ||
1903 | out_free: | 1963 | out_free: |