@@ -14,6 +14,7 @@ use crate::vfs::{
1414 DirEntry , DirEntryHandle , FileHandle , FileObject , FileSystem , FileSystemHandle , FsNode , FsStr ,
1515 FsString , PathBuilder , UnlinkKind , ValueOrSize , XattrOp ,
1616} ;
17+ use crate :: TODO_DENY ;
1718use audit:: { audit_log, AuditContext } ;
1819use bstr:: BStr ;
1920use linux_uapi:: XATTR_NAME_SELINUX ;
@@ -31,6 +32,7 @@ use starnix_uapi::arc_key::WeakKey;
3132use starnix_uapi:: device_type:: DeviceType ;
3233use starnix_uapi:: errors:: { Errno , ENODATA } ;
3334use starnix_uapi:: file_mode:: FileMode ;
35+ use starnix_uapi:: open_flags:: OpenFlags ;
3436use starnix_uapi:: {
3537 errno, error, FIGETBSZ , FIOASYNC , FIONBIO , FIONREAD , FS_IOC_GETFLAGS , FS_IOC_GETVERSION ,
3638 FS_IOC_SETFLAGS , FS_IOC_SETVERSION ,
@@ -42,6 +44,29 @@ use std::sync::{Arc, OnceLock};
4244/// contexts in a filesystem node extended attributes.
4345const SECURITY_SELINUX_XATTR_VALUE_MAX_SIZE : usize = 4096 ;
4446
47+ /// Returns the set of `Permissions` on `class`, corresponding to the specified `flags`.
48+ fn permissions_from_flags ( flags : PermissionFlags , class : FileClass ) -> Vec < Permission > {
49+ let mut result = Vec :: new ( ) ;
50+ if flags. contains ( PermissionFlags :: READ ) {
51+ result. push ( CommonFilePermission :: Read . for_class ( class) ) ;
52+ }
53+ // SELinux uses the `APPEND` bit to distinguish which of the "append" or the more general
54+ // "write" permission to check for.
55+ if flags. contains ( PermissionFlags :: APPEND ) {
56+ result. push ( CommonFilePermission :: Append . for_class ( class) ) ;
57+ } else if flags. contains ( PermissionFlags :: WRITE ) {
58+ result. push ( CommonFilePermission :: Write . for_class ( class) ) ;
59+ }
60+ if flags. contains ( PermissionFlags :: EXEC ) {
61+ if class == FileClass :: Dir {
62+ result. push ( DirPermission :: Search . into ( ) ) ;
63+ } else {
64+ result. push ( CommonFilePermission :: Execute . for_class ( class) ) ;
65+ }
66+ }
67+ result
68+ }
69+
4570/// Checks that `current_task` has permission to "use" the specified `file`, and the specified
4671/// `permissions` to the underlying [`crate::vfs::FsNode`].
4772fn has_file_permissions (
@@ -53,7 +78,8 @@ fn has_file_permissions(
5378 // Validate that the `subject` has the "fd { use }" permission to the `file`.
5479 // If the file and task security domains are identical then `fd { use }` is implicitly granted.
5580 let file_sid = file. security_state . state . sid ;
56- if subject_sid != file_sid {
81+ // TODO: https://fxbug.dev/385121365 - Should the kernel be implicitly allowed to "use" all FDs?
82+ if subject_sid != SecurityId :: initial ( InitialSid :: Kernel ) && subject_sid != file_sid {
5783 check_permission ( permission_check, subject_sid, file_sid, FdPermission :: Use ) ?;
5884 }
5985
@@ -108,6 +134,31 @@ fn todo_has_fs_node_permissions(
108134 Ok ( ( ) )
109135}
110136
137+ /// Checks whether the `current_task`` has the permissions specified by `mask` to the `file`.
138+ pub fn file_permission (
139+ security_server : & SecurityServer ,
140+ current_task : & CurrentTask ,
141+ file : & FileObject ,
142+ mut permission_flags : PermissionFlags ,
143+ ) -> Result < ( ) , Errno > {
144+ let current_sid = current_task. security_state . lock ( ) . current_sid ;
145+ let file_mode = file. name . entry . node . info ( ) . mode ;
146+ let file_class = file_class_from_file_mode ( file_mode) ?;
147+
148+ if file. flags ( ) . contains ( OpenFlags :: APPEND ) {
149+ permission_flags |= PermissionFlags :: APPEND ;
150+ }
151+
152+ has_file_permissions ( & security_server. as_permission_check ( ) , current_sid, file, & [ ] ) ?;
153+ todo_has_fs_node_permissions (
154+ TODO_DENY ! ( "https://fxbug.dev/385121365" , "Enforce file_permission() checks" ) ,
155+ & security_server. as_permission_check ( ) ,
156+ current_sid,
157+ file. node ( ) ,
158+ & permissions_from_flags ( permission_flags, file_class) ,
159+ )
160+ }
161+
111162/// Returns the relative path from the root of the file system containing this `DirEntry`.
112163fn get_fs_relative_path ( dir_entry : & DirEntryHandle ) -> FsString {
113164 let mut path_builder = PathBuilder :: new ( ) ;
@@ -300,7 +351,8 @@ fn make_fs_node_security_xattr(
300351}
301352
302353fn file_class_from_file_mode ( mode : FileMode ) -> Result < FileClass , Errno > {
303- match mode. bits ( ) & starnix_uapi:: S_IFMT {
354+ let file_type = mode. bits ( ) & starnix_uapi:: S_IFMT ;
355+ match file_type {
304356 starnix_uapi:: S_IFLNK => Ok ( FileClass :: Link ) ,
305357 starnix_uapi:: S_IFREG => Ok ( FileClass :: File ) ,
306358 starnix_uapi:: S_IFDIR => Ok ( FileClass :: Dir ) ,
@@ -779,70 +831,14 @@ pub fn fs_node_permission(
779831 permission_flags : PermissionFlags ,
780832) -> Result < ( ) , Errno > {
781833 let current_sid = current_task. security_state . lock ( ) . current_sid ;
782- let FsNodeSidAndClass { sid : file_sid, class : file_class } =
783- fs_node_effective_sid_and_class ( fs_node) ;
784- if permission_flags. contains ( PermissionFlags :: READ ) {
785- todo_check_permission (
786- TODO_DENY ! (
787- "https://fxbug.dev/380855359" ,
788- "Check read permission when calling fs_node_permission."
789- ) ,
790- & security_server. as_permission_check ( ) ,
791- current_sid,
792- file_sid,
793- CommonFilePermission :: Read . for_class ( file_class) ,
794- ) ?;
795- }
796-
797- if permission_flags. contains ( PermissionFlags :: WRITE ) {
798- todo_check_permission (
799- TODO_DENY ! (
800- "https://fxbug.dev/380855359" ,
801- "Check write permission when calling fs_node_permission."
802- ) ,
803- & security_server. as_permission_check ( ) ,
804- current_sid,
805- file_sid,
806- CommonFilePermission :: Write . for_class ( file_class) ,
807- ) ?;
808- }
809-
810- if permission_flags. contains ( PermissionFlags :: APPEND ) {
811- check_permission (
812- & security_server. as_permission_check ( ) ,
813- current_sid,
814- file_sid,
815- CommonFilePermission :: Append . for_class ( file_class) ,
816- ) ?;
817- }
818-
819- if permission_flags. contains ( PermissionFlags :: EXEC ) {
820- if file_class == FileClass :: Dir {
821- todo_check_permission (
822- TODO_DENY ! (
823- "https://fxbug.dev/380855359" ,
824- "Check search permission when calling fs_node_permission."
825- ) ,
826- & security_server. as_permission_check ( ) ,
827- current_sid,
828- file_sid,
829- DirPermission :: Search ,
830- ) ?;
831- } else {
832- todo_check_permission (
833- TODO_DENY ! (
834- "https://fxbug.dev/380855359" ,
835- "Check execute permission when calling fs_node_permission."
836- ) ,
837- & security_server. as_permission_check ( ) ,
838- current_sid,
839- file_sid,
840- CommonFilePermission :: Execute . for_class ( file_class) ,
841- ) ?;
842- }
843- }
844-
845- Ok ( ( ) )
834+ let file_class = fs_node. security_state . lock ( ) . class ;
835+ todo_has_fs_node_permissions (
836+ TODO_DENY ! ( "https://fxbug.dev/380855359" , "Enforce fs_node_permission checks." ) ,
837+ & security_server. as_permission_check ( ) ,
838+ current_sid,
839+ fs_node,
840+ & permissions_from_flags ( permission_flags, file_class) ,
841+ )
846842}
847843
848844pub ( super ) fn check_fs_node_getattr_access (
0 commit comments