@@ -273,9 +273,6 @@ pub(super) fn fs_node_init_on_create(
273273 // Compute both the SID to store on the in-memory node and the xattr to persist on-disk
274274 // (or None if this circumstance is such that there's no xattr to persist).
275275 let ( sid, xattr) = match label. scheme {
276- FileSystemLabelingScheme :: Mountpoint => {
277- return Ok ( None ) ;
278- }
279276 FileSystemLabelingScheme :: FsUse { fs_use_type, .. } => {
280277 let current_task_sid = current_task. read ( ) . security_state . attrs . current_sid ;
281278 if fs_use_type == FsUseType :: Task {
@@ -299,7 +296,7 @@ pub(super) fn fs_node_init_on_create(
299296 ( sid, xattr)
300297 }
301298 }
302- FileSystemLabelingScheme :: GenFsCon => {
299+ FileSystemLabelingScheme :: Mountpoint | FileSystemLabelingScheme :: GenFsCon => {
303300 // The label in this case is decided in the `fs_node_init_with_dentry` hook.
304301 return Ok ( None ) ;
305302 }
@@ -639,23 +636,90 @@ pub(super) fn fs_node_setsecurity<L>(
639636where
640637 L : LockEqualOrBefore < FileOpsCore > ,
641638{
642- fs_node. ops ( ) . set_xattr (
639+ if name != FsStr :: new ( XATTR_NAME_SELINUX . to_bytes ( ) ) {
640+ return fs_node. ops ( ) . set_xattr (
641+ & mut locked. cast_locked :: < FileOpsCore > ( ) ,
642+ fs_node,
643+ current_task,
644+ name,
645+ value,
646+ op,
647+ ) ;
648+ }
649+
650+ // If the "security.selinux" attribute is being modified then the result depends on the
651+ // `FileSystem`'s labeling scheme.
652+ let fs = fs_node. fs ( ) ;
653+ let fs_label = match & mut * fs. security_state . state . 0 . lock ( ) {
654+ FileSystemLabelState :: Unlabeled { .. } => {
655+ // If the `FileSystem` has not yet been labeled then store the xattr but leave the
656+ // label on the in-memory `fs_node` to be set up when the `FileSystem`'s labeling state
657+ // has been initialized, during load of the initial policy.
658+ return fs_node. ops ( ) . set_xattr (
659+ & mut locked. cast_locked :: < FileOpsCore > ( ) ,
660+ fs_node,
661+ current_task,
662+ name,
663+ value,
664+ op,
665+ ) ;
666+ }
667+ FileSystemLabelState :: Labeled { label } => label. clone ( ) ,
668+ } ;
669+
670+ // If the "mountpoint"-labeling is used by this filesystem then setting labels is not supported.
671+ // TODO: - Is re-labeling of "genfscon" nodes allowed?
672+ if fs_label. scheme == FileSystemLabelingScheme :: Mountpoint {
673+ return error ! ( ENOTSUP ) ;
674+ }
675+
676+ // TODO: - Lock the `fs_node` security label here, to ensure consistency.
677+
678+ // Verify that the requested modification is permitted by the loaded policy.
679+ let new_sid = security_server. security_context_to_sid ( value. into ( ) ) . ok ( ) ;
680+ if security_server. is_enforcing ( ) {
681+ let new_sid = new_sid. ok_or_else ( || errno ! ( EINVAL ) ) ?;
682+ let task_sid = current_task. read ( ) . security_state . attrs . current_sid ;
683+ let old_sid = fs_node_effective_sid ( fs_node) ;
684+ let file_class = file_class_from_file_mode ( fs_node. info ( ) . mode ) ?;
685+ let permission_check = security_server. as_permission_check ( ) ;
686+ check_permission (
687+ & permission_check,
688+ task_sid,
689+ old_sid,
690+ CommonFilePermission :: RelabelFrom . for_class ( file_class) ,
691+ ) ?;
692+ check_permission (
693+ & permission_check,
694+ task_sid,
695+ new_sid,
696+ CommonFilePermission :: RelabelTo . for_class ( file_class) ,
697+ ) ?;
698+ check_permission (
699+ & permission_check,
700+ new_sid,
701+ fs_label. sid ,
702+ FileSystemPermission :: Associate ,
703+ ) ?;
704+ }
705+
706+ // Apply the change to the file node.
707+ let result = fs_node. ops ( ) . set_xattr (
643708 & mut locked. cast_locked :: < FileOpsCore > ( ) ,
644709 fs_node,
645710 current_task,
646711 name,
647712 value,
648713 op,
649- ) ?;
650- if name == FsStr :: new ( XATTR_NAME_SELINUX . to_bytes ( ) ) {
651- // If the new value is a valid Security Context then label the node with the corresponding
652- // SID, otherwise use the policy's "unlabeled" SID.
653- let sid = security_server
654- . security_context_to_sid ( value. into ( ) )
655- . unwrap_or ( SecurityId :: initial ( InitialSid :: Unlabeled ) ) ;
656- set_cached_sid ( fs_node, sid)
714+ ) ;
715+
716+ // If the operation succeeded then update the label cached on the file node.
717+ if result. is_ok ( ) {
718+ let effective_new_sid = new_sid. unwrap_or ( SecurityId :: initial ( InitialSid :: Unlabeled ) ) ;
719+ set_cached_sid ( fs_node, effective_new_sid) ;
657720 }
658- Ok ( ( ) )
721+
722+ result
659723}
660724
661725/// Returns the `SecurityId` that should be used for SELinux access control checks against `fs_node`.
@@ -1127,8 +1191,10 @@ mod tests {
11271191 let dir_entry = & testing:: create_test_file ( locked, current_task) . entry ;
11281192 let node = & dir_entry. node ;
11291193
1130- // Store a valid Security Context in the attribute, and ensure any label cached on the `FsNode`
1131- // is removed, to force the effective-SID query to resolve the label again.
1194+ // Store a valid Security Context in the attribute, then clear the cached label and
1195+ // re-resolve it. The hooks test policy defines that "tmpfs" use "fs_use_xattr"
1196+ // labeling, which should result in the (valid) label being read from the file, and
1197+ // the corresponding SID cached.
11321198 node. ops ( )
11331199 . set_xattr (
11341200 & mut locked. cast_locked :: < FileOpsCore > ( ) ,
@@ -1139,8 +1205,6 @@ mod tests {
11391205 XattrOp :: Set ,
11401206 )
11411207 . expect ( "setxattr" ) ;
1142-
1143- // Clear the cached SID and use `fs_node_init_with_dentry()` to re-resolve the label.
11441208 clear_cached_sid ( node) ;
11451209 assert_eq ! ( None , get_cached_sid( node) ) ;
11461210 fs_node_init_with_dentry ( locked, & security_server, & current_task, dir_entry)
0 commit comments