18c2ecf20Sopenharmony_ci=========
28c2ecf20Sopenharmony_ciSafeSetID
38c2ecf20Sopenharmony_ci=========
48c2ecf20Sopenharmony_ciSafeSetID is an LSM module that gates the setid family of syscalls to restrict
58c2ecf20Sopenharmony_ciUID/GID transitions from a given UID/GID to only those approved by a
68c2ecf20Sopenharmony_cisystem-wide allowlist. These restrictions also prohibit the given UIDs/GIDs
78c2ecf20Sopenharmony_cifrom obtaining auxiliary privileges associated with CAP_SET{U/G}ID, such as
88c2ecf20Sopenharmony_ciallowing a user to set up user namespace UID/GID mappings.
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ciBackground
128c2ecf20Sopenharmony_ci==========
138c2ecf20Sopenharmony_ciIn absence of file capabilities, processes spawned on a Linux system that need
148c2ecf20Sopenharmony_cito switch to a different user must be spawned with CAP_SETUID privileges.
158c2ecf20Sopenharmony_ciCAP_SETUID is granted to programs running as root or those running as a non-root
168c2ecf20Sopenharmony_ciuser that have been explicitly given the CAP_SETUID runtime capability. It is
178c2ecf20Sopenharmony_cioften preferable to use Linux runtime capabilities rather than file
188c2ecf20Sopenharmony_cicapabilities, since using file capabilities to run a program with elevated
198c2ecf20Sopenharmony_ciprivileges opens up possible security holes since any user with access to the
208c2ecf20Sopenharmony_cifile can exec() that program to gain the elevated privileges.
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ciWhile it is possible to implement a tree of processes by giving full
238c2ecf20Sopenharmony_ciCAP_SET{U/G}ID capabilities, this is often at odds with the goals of running a
248c2ecf20Sopenharmony_citree of processes under non-root user(s) in the first place. Specifically,
258c2ecf20Sopenharmony_cisince CAP_SETUID allows changing to any user on the system, including the root
268c2ecf20Sopenharmony_ciuser, it is an overpowered capability for what is needed in this scenario,
278c2ecf20Sopenharmony_ciespecially since programs often only call setuid() to drop privileges to a
288c2ecf20Sopenharmony_cilesser-privileged user -- not elevate privileges. Unfortunately, there is no
298c2ecf20Sopenharmony_cigenerally feasible way in Linux to restrict the potential UIDs that a user can
308c2ecf20Sopenharmony_ciswitch to through setuid() beyond allowing a switch to any user on the system.
318c2ecf20Sopenharmony_ciThis SafeSetID LSM seeks to provide a solution for restricting setid
328c2ecf20Sopenharmony_cicapabilities in such a way.
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ciThe main use case for this LSM is to allow a non-root program to transition to
358c2ecf20Sopenharmony_ciother untrusted uids without full blown CAP_SETUID capabilities. The non-root
368c2ecf20Sopenharmony_ciprogram would still need CAP_SETUID to do any kind of transition, but the
378c2ecf20Sopenharmony_ciadditional restrictions imposed by this LSM would mean it is a "safer" version
388c2ecf20Sopenharmony_ciof CAP_SETUID since the non-root program cannot take advantage of CAP_SETUID to
398c2ecf20Sopenharmony_cido any unapproved actions (e.g. setuid to uid 0 or create/enter new user
408c2ecf20Sopenharmony_cinamespace). The higher level goal is to allow for uid-based sandboxing of system
418c2ecf20Sopenharmony_ciservices without having to give out CAP_SETUID all over the place just so that
428c2ecf20Sopenharmony_cinon-root programs can drop to even-lesser-privileged uids. This is especially
438c2ecf20Sopenharmony_cirelevant when one non-root daemon on the system should be allowed to spawn other
448c2ecf20Sopenharmony_ciprocesses as different uids, but its undesirable to give the daemon a
458c2ecf20Sopenharmony_cibasically-root-equivalent CAP_SETUID.
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ciOther Approaches Considered
498c2ecf20Sopenharmony_ci===========================
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ciSolve this problem in userspace
528c2ecf20Sopenharmony_ci-------------------------------
538c2ecf20Sopenharmony_ciFor candidate applications that would like to have restricted setid capabilities
548c2ecf20Sopenharmony_cias implemented in this LSM, an alternative option would be to simply take away
558c2ecf20Sopenharmony_cisetid capabilities from the application completely and refactor the process
568c2ecf20Sopenharmony_cispawning semantics in the application (e.g. by using a privileged helper program
578c2ecf20Sopenharmony_cito do process spawning and UID/GID transitions). Unfortunately, there are a
588c2ecf20Sopenharmony_cinumber of semantics around process spawning that would be affected by this, such
598c2ecf20Sopenharmony_cias fork() calls where the program doesn't immediately call exec() after the
608c2ecf20Sopenharmony_cifork(), parent processes specifying custom environment variables or command line
618c2ecf20Sopenharmony_ciargs for spawned child processes, or inheritance of file handles across a
628c2ecf20Sopenharmony_cifork()/exec(). Because of this, as solution that uses a privileged helper in
638c2ecf20Sopenharmony_ciuserspace would likely be less appealing to incorporate into existing projects
648c2ecf20Sopenharmony_cithat rely on certain process-spawning semantics in Linux.
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ciUse user namespaces
678c2ecf20Sopenharmony_ci-------------------
688c2ecf20Sopenharmony_ciAnother possible approach would be to run a given process tree in its own user
698c2ecf20Sopenharmony_cinamespace and give programs in the tree setid capabilities. In this way,
708c2ecf20Sopenharmony_ciprograms in the tree could change to any desired UID/GID in the context of their
718c2ecf20Sopenharmony_ciown user namespace, and only approved UIDs/GIDs could be mapped back to the
728c2ecf20Sopenharmony_ciinitial system user namespace, affectively preventing privilege escalation.
738c2ecf20Sopenharmony_ciUnfortunately, it is not generally feasible to use user namespaces in isolation,
748c2ecf20Sopenharmony_ciwithout pairing them with other namespace types, which is not always an option.
758c2ecf20Sopenharmony_ciLinux checks for capabilities based off of the user namespace that "owns" some
768c2ecf20Sopenharmony_cientity. For example, Linux has the notion that network namespaces are owned by
778c2ecf20Sopenharmony_cithe user namespace in which they were created. A consequence of this is that
788c2ecf20Sopenharmony_cicapability checks for access to a given network namespace are done by checking
798c2ecf20Sopenharmony_ciwhether a task has the given capability in the context of the user namespace
808c2ecf20Sopenharmony_cithat owns the network namespace -- not necessarily the user namespace under
818c2ecf20Sopenharmony_ciwhich the given task runs. Therefore spawning a process in a new user namespace
828c2ecf20Sopenharmony_cieffectively prevents it from accessing the network namespace owned by the
838c2ecf20Sopenharmony_ciinitial namespace. This is a deal-breaker for any application that expects to
848c2ecf20Sopenharmony_ciretain the CAP_NET_ADMIN capability for the purpose of adjusting network
858c2ecf20Sopenharmony_ciconfigurations. Using user namespaces in isolation causes problems regarding
868c2ecf20Sopenharmony_ciother system interactions, including use of pid namespaces and device creation.
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ciUse an existing LSM
898c2ecf20Sopenharmony_ci-------------------
908c2ecf20Sopenharmony_ciNone of the other in-tree LSMs have the capability to gate setid transitions, or
918c2ecf20Sopenharmony_cieven employ the security_task_fix_setuid hook at all. SELinux says of that hook:
928c2ecf20Sopenharmony_ci"Since setuid only affects the current process, and since the SELinux controls
938c2ecf20Sopenharmony_ciare not based on the Linux identity attributes, SELinux does not need to control
948c2ecf20Sopenharmony_cithis operation."
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ciDirections for use
988c2ecf20Sopenharmony_ci==================
998c2ecf20Sopenharmony_ciThis LSM hooks the setid syscalls to make sure transitions are allowed if an
1008c2ecf20Sopenharmony_ciapplicable restriction policy is in place. Policies are configured through
1018c2ecf20Sopenharmony_cisecurityfs by writing to the safesetid/uid_allowlist_policy and
1028c2ecf20Sopenharmony_cisafesetid/gid_allowlist_policy files at the location where securityfs is
1038c2ecf20Sopenharmony_cimounted. The format for adding a policy is '<UID>:<UID>' or '<GID>:<GID>',
1048c2ecf20Sopenharmony_ciusing literal numbers, and ending with a newline character such as '123:456\n'.
1058c2ecf20Sopenharmony_ciWriting an empty string "" will flush the policy. Again, configuring a policy
1068c2ecf20Sopenharmony_cifor a UID/GID will prevent that UID/GID from obtaining auxiliary setid
1078c2ecf20Sopenharmony_ciprivileges, such as allowing a user to set up user namespace UID/GID mappings.
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ciNote on GID policies and setgroups()
1108c2ecf20Sopenharmony_ci====================================
1118c2ecf20Sopenharmony_ciIn v5.9 we are adding support for limiting CAP_SETGID privileges as was done
1128c2ecf20Sopenharmony_cipreviously for CAP_SETUID. However, for compatibility with common sandboxing
1138c2ecf20Sopenharmony_cirelated code conventions in userspace, we currently allow arbitrary
1148c2ecf20Sopenharmony_cisetgroups() calls for processes with CAP_SETGID restrictions. Until we add
1158c2ecf20Sopenharmony_cisupport in a future release for restricting setgroups() calls, these GID
1168c2ecf20Sopenharmony_cipolicies add no meaningful security. setgroups() restrictions will be enforced
1178c2ecf20Sopenharmony_cionce we have the policy checking code in place, which will rely on GID policy
1188c2ecf20Sopenharmony_ciconfiguration code added in v5.9.
119