diff options
| -rw-r--r-- | fs/nfs/super.c | 17 | ||||
| -rw-r--r-- | include/linux/lsm_hooks.h | 4 | ||||
| -rw-r--r-- | include/linux/security.h | 8 | ||||
| -rw-r--r-- | security/security.c | 7 | ||||
| -rw-r--r-- | security/selinux/hooks.c | 35 |
5 files changed, 63 insertions, 8 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 2f3822a4a7d5..b8e073546507 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
| @@ -2544,10 +2544,25 @@ EXPORT_SYMBOL_GPL(nfs_set_sb_security); | |||
| 2544 | int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot, | 2544 | int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot, |
| 2545 | struct nfs_mount_info *mount_info) | 2545 | struct nfs_mount_info *mount_info) |
| 2546 | { | 2546 | { |
| 2547 | int error; | ||
| 2548 | unsigned long kflags = 0, kflags_out = 0; | ||
| 2549 | |||
| 2547 | /* clone any lsm security options from the parent to the new sb */ | 2550 | /* clone any lsm security options from the parent to the new sb */ |
| 2548 | if (d_inode(mntroot)->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) | 2551 | if (d_inode(mntroot)->i_op != NFS_SB(s)->nfs_client->rpc_ops->dir_inode_ops) |
| 2549 | return -ESTALE; | 2552 | return -ESTALE; |
| 2550 | return security_sb_clone_mnt_opts(mount_info->cloned->sb, s); | 2553 | |
| 2554 | if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL) | ||
| 2555 | kflags |= SECURITY_LSM_NATIVE_LABELS; | ||
| 2556 | |||
| 2557 | error = security_sb_clone_mnt_opts(mount_info->cloned->sb, s, kflags, | ||
| 2558 | &kflags_out); | ||
| 2559 | if (error) | ||
| 2560 | return error; | ||
| 2561 | |||
| 2562 | if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL && | ||
| 2563 | !(kflags_out & SECURITY_LSM_NATIVE_LABELS)) | ||
| 2564 | NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL; | ||
| 2565 | return 0; | ||
| 2551 | } | 2566 | } |
| 2552 | EXPORT_SYMBOL_GPL(nfs_clone_sb_security); | 2567 | EXPORT_SYMBOL_GPL(nfs_clone_sb_security); |
| 2553 | 2568 | ||
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 68d91e423bca..3cc9d77c7527 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h | |||
| @@ -1409,7 +1409,9 @@ union security_list_options { | |||
| 1409 | unsigned long kern_flags, | 1409 | unsigned long kern_flags, |
| 1410 | unsigned long *set_kern_flags); | 1410 | unsigned long *set_kern_flags); |
| 1411 | int (*sb_clone_mnt_opts)(const struct super_block *oldsb, | 1411 | int (*sb_clone_mnt_opts)(const struct super_block *oldsb, |
| 1412 | struct super_block *newsb); | 1412 | struct super_block *newsb, |
| 1413 | unsigned long kern_flags, | ||
| 1414 | unsigned long *set_kern_flags); | ||
| 1413 | int (*sb_parse_opts_str)(char *options, struct security_mnt_opts *opts); | 1415 | int (*sb_parse_opts_str)(char *options, struct security_mnt_opts *opts); |
| 1414 | int (*dentry_init_security)(struct dentry *dentry, int mode, | 1416 | int (*dentry_init_security)(struct dentry *dentry, int mode, |
| 1415 | const struct qstr *name, void **ctx, | 1417 | const struct qstr *name, void **ctx, |
diff --git a/include/linux/security.h b/include/linux/security.h index 549cb828a888..b44e954815ce 100644 --- a/include/linux/security.h +++ b/include/linux/security.h | |||
| @@ -249,7 +249,9 @@ int security_sb_set_mnt_opts(struct super_block *sb, | |||
| 249 | unsigned long kern_flags, | 249 | unsigned long kern_flags, |
| 250 | unsigned long *set_kern_flags); | 250 | unsigned long *set_kern_flags); |
| 251 | int security_sb_clone_mnt_opts(const struct super_block *oldsb, | 251 | int security_sb_clone_mnt_opts(const struct super_block *oldsb, |
| 252 | struct super_block *newsb); | 252 | struct super_block *newsb, |
| 253 | unsigned long kern_flags, | ||
| 254 | unsigned long *set_kern_flags); | ||
| 253 | int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts); | 255 | int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts); |
| 254 | int security_dentry_init_security(struct dentry *dentry, int mode, | 256 | int security_dentry_init_security(struct dentry *dentry, int mode, |
| 255 | const struct qstr *name, void **ctx, | 257 | const struct qstr *name, void **ctx, |
| @@ -605,7 +607,9 @@ static inline int security_sb_set_mnt_opts(struct super_block *sb, | |||
| 605 | } | 607 | } |
| 606 | 608 | ||
| 607 | static inline int security_sb_clone_mnt_opts(const struct super_block *oldsb, | 609 | static inline int security_sb_clone_mnt_opts(const struct super_block *oldsb, |
| 608 | struct super_block *newsb) | 610 | struct super_block *newsb, |
| 611 | unsigned long kern_flags, | ||
| 612 | unsigned long *set_kern_flags) | ||
| 609 | { | 613 | { |
| 610 | return 0; | 614 | return 0; |
| 611 | } | 615 | } |
diff --git a/security/security.c b/security/security.c index 714433e3e9a2..30132378d103 100644 --- a/security/security.c +++ b/security/security.c | |||
| @@ -420,9 +420,12 @@ int security_sb_set_mnt_opts(struct super_block *sb, | |||
| 420 | EXPORT_SYMBOL(security_sb_set_mnt_opts); | 420 | EXPORT_SYMBOL(security_sb_set_mnt_opts); |
| 421 | 421 | ||
| 422 | int security_sb_clone_mnt_opts(const struct super_block *oldsb, | 422 | int security_sb_clone_mnt_opts(const struct super_block *oldsb, |
| 423 | struct super_block *newsb) | 423 | struct super_block *newsb, |
| 424 | unsigned long kern_flags, | ||
| 425 | unsigned long *set_kern_flags) | ||
| 424 | { | 426 | { |
| 425 | return call_int_hook(sb_clone_mnt_opts, 0, oldsb, newsb); | 427 | return call_int_hook(sb_clone_mnt_opts, 0, oldsb, newsb, |
| 428 | kern_flags, set_kern_flags); | ||
| 426 | } | 429 | } |
| 427 | EXPORT_SYMBOL(security_sb_clone_mnt_opts); | 430 | EXPORT_SYMBOL(security_sb_clone_mnt_opts); |
| 428 | 431 | ||
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 9926adbd50a9..9cc042df10d1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
| @@ -525,8 +525,16 @@ static int sb_finish_set_opts(struct super_block *sb) | |||
| 525 | } | 525 | } |
| 526 | 526 | ||
| 527 | sbsec->flags |= SE_SBINITIALIZED; | 527 | sbsec->flags |= SE_SBINITIALIZED; |
| 528 | |||
| 529 | /* | ||
| 530 | * Explicitly set or clear SBLABEL_MNT. It's not sufficient to simply | ||
| 531 | * leave the flag untouched because sb_clone_mnt_opts might be handing | ||
| 532 | * us a superblock that needs the flag to be cleared. | ||
| 533 | */ | ||
| 528 | if (selinux_is_sblabel_mnt(sb)) | 534 | if (selinux_is_sblabel_mnt(sb)) |
| 529 | sbsec->flags |= SBLABEL_MNT; | 535 | sbsec->flags |= SBLABEL_MNT; |
| 536 | else | ||
| 537 | sbsec->flags &= ~SBLABEL_MNT; | ||
| 530 | 538 | ||
| 531 | /* Initialize the root inode. */ | 539 | /* Initialize the root inode. */ |
| 532 | rc = inode_doinit_with_dentry(root_inode, root); | 540 | rc = inode_doinit_with_dentry(root_inode, root); |
| @@ -959,8 +967,11 @@ mismatch: | |||
| 959 | } | 967 | } |
| 960 | 968 | ||
| 961 | static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, | 969 | static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, |
| 962 | struct super_block *newsb) | 970 | struct super_block *newsb, |
| 971 | unsigned long kern_flags, | ||
| 972 | unsigned long *set_kern_flags) | ||
| 963 | { | 973 | { |
| 974 | int rc = 0; | ||
| 964 | const struct superblock_security_struct *oldsbsec = oldsb->s_security; | 975 | const struct superblock_security_struct *oldsbsec = oldsb->s_security; |
| 965 | struct superblock_security_struct *newsbsec = newsb->s_security; | 976 | struct superblock_security_struct *newsbsec = newsb->s_security; |
| 966 | 977 | ||
| @@ -975,6 +986,13 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, | |||
| 975 | if (!ss_initialized) | 986 | if (!ss_initialized) |
| 976 | return 0; | 987 | return 0; |
| 977 | 988 | ||
| 989 | /* | ||
| 990 | * Specifying internal flags without providing a place to | ||
| 991 | * place the results is not allowed. | ||
| 992 | */ | ||
| 993 | if (kern_flags && !set_kern_flags) | ||
| 994 | return -EINVAL; | ||
| 995 | |||
| 978 | /* how can we clone if the old one wasn't set up?? */ | 996 | /* how can we clone if the old one wasn't set up?? */ |
| 979 | BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED)); | 997 | BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED)); |
| 980 | 998 | ||
| @@ -990,6 +1008,18 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, | |||
| 990 | newsbsec->def_sid = oldsbsec->def_sid; | 1008 | newsbsec->def_sid = oldsbsec->def_sid; |
| 991 | newsbsec->behavior = oldsbsec->behavior; | 1009 | newsbsec->behavior = oldsbsec->behavior; |
| 992 | 1010 | ||
| 1011 | if (newsbsec->behavior == SECURITY_FS_USE_NATIVE && | ||
| 1012 | !(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) { | ||
| 1013 | rc = security_fs_use(newsb); | ||
| 1014 | if (rc) | ||
| 1015 | goto out; | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !set_context) { | ||
| 1019 | newsbsec->behavior = SECURITY_FS_USE_NATIVE; | ||
| 1020 | *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS; | ||
| 1021 | } | ||
| 1022 | |||
| 993 | if (set_context) { | 1023 | if (set_context) { |
| 994 | u32 sid = oldsbsec->mntpoint_sid; | 1024 | u32 sid = oldsbsec->mntpoint_sid; |
| 995 | 1025 | ||
| @@ -1009,8 +1039,9 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, | |||
| 1009 | } | 1039 | } |
| 1010 | 1040 | ||
| 1011 | sb_finish_set_opts(newsb); | 1041 | sb_finish_set_opts(newsb); |
| 1042 | out: | ||
| 1012 | mutex_unlock(&newsbsec->lock); | 1043 | mutex_unlock(&newsbsec->lock); |
| 1013 | return 0; | 1044 | return rc; |
| 1014 | } | 1045 | } |
| 1015 | 1046 | ||
| 1016 | static int selinux_parse_opts_str(char *options, | 1047 | static int selinux_parse_opts_str(char *options, |
