diff options
author | Scott Mayhew <smayhew@redhat.com> | 2017-06-05 11:45:04 -0400 |
---|---|---|
committer | Paul Moore <paul@paul-moore.com> | 2017-06-09 16:17:47 -0400 |
commit | 0b4d3452b8b4a5309b4445b900e3cec022cca95a (patch) | |
tree | 3c758827bc8bab1cd36f9c551840cdae00636e97 /security/selinux | |
parent | b4958c892e02241b9bd121f3397b76225ff6f4a3 (diff) |
security/selinux: allow security_sb_clone_mnt_opts to enable/disable native labeling behavior
When an NFSv4 client performs a mount operation, it first mounts the
NFSv4 root and then does path walk to the exported path and performs a
submount on that, cloning the security mount options from the root's
superblock to the submount's superblock in the process.
Unless the NFS server has an explicit fsid=0 export with the
"security_label" option, the NFSv4 root superblock will not have
SBLABEL_MNT set, and neither will the submount superblock after cloning
the security mount options. As a result, setxattr's of security labels
over NFSv4.2 will fail. In a similar fashion, NFSv4.2 mounts mounted
with the context= mount option will not show the correct labels because
the nfs_server->caps flags of the cloned superblock will still have
NFS_CAP_SECURITY_LABEL set.
Allowing the NFSv4 client to enable or disable SECURITY_LSM_NATIVE_LABELS
behavior will ensure that the SBLABEL_MNT flag has the correct value
when the client traverses from an exported path without the
"security_label" option to one with the "security_label" option and
vice versa. Similarly, checking to see if SECURITY_LSM_NATIVE_LABELS is
set upon return from security_sb_clone_mnt_opts() and clearing
NFS_CAP_SECURITY_LABEL if necessary will allow the correct labels to
be displayed for NFSv4.2 mounts mounted with the context= mount option.
Resolves: https://github.com/SELinuxProject/selinux-kernel/issues/35
Signed-off-by: Scott Mayhew <smayhew@redhat.com>
Reviewed-by: Stephen Smalley <sds@tycho.nsa.gov>
Tested-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Paul Moore <paul@paul-moore.com>
Diffstat (limited to 'security/selinux')
-rw-r--r-- | security/selinux/hooks.c | 35 |
1 files changed, 33 insertions, 2 deletions
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, |