I was asked by email whether SE Linux could implement traditional Unix users and groups.
The Strictly Literal Answer to that Question
The core of the SE Linux access control is the domain-type model where every process has a domain and every object that a process can access (including other processes) has a type. Domains are not strongly differentiated from types.
It would be possible to create a SE Linux policy that created a domain for every combination of UID and GID that is valid for a user shell given that such combinations are chosen by the sysadmin who could limit them to some degree. There are about 2^32 possible UIDs and about 2^32 possible GIDs, as every domain is listed in kernel memory we obviously can’t have 2^64 domains, but we could have enough to map a typical system that’s in use. Of course the possible combinations of supplemental groups probably makes this impossible for even relatively small systems, but we can use a simpler model that doesn’t emulate supplemental groups.
For files there are more possible combinations because anyone who is a member of a group can create a SETGID directory and let other users create files in it. But in a typical system the number of groups is not much greater than the number of users – the maximum number of groups is typically the number of users plus about 60. So if we had 100 users then the number of combinations of UID and GID would be something like 100*(100+60)=16,000 – it should be possible to have that many domains in a SE Linux policy (but not desirable).
Then all that would be needed is rules specifying that each domain (which is based on a combination of UID and GID) can have certain types of access to certain other types based on them having either the same UID or the same GID.
Such a policy would be large, it would waste a lot of kernel memory, it would need to be regenerated whenever a user is added, and it’s generally something you don’t want to use. No-one has considered implementing such a policy, I merely describe it to illustrate why certain configuration options are not desirable. The rest of this post is about realistic things that you can do with SE Linux policy and how it will be implemented in Debian/Squeeze.
The History of mapping Unix Accounts to SE Linux Access Control
In the early releases of SE Linux (long before it was included in Fedora) every user who could login to a system needed to have their user-name compiled into the policy. The policy specified which roles the user could access, the roles specified which domains could be accessed, and therefore what the user could do. The identity of files on disk was used for two purposes, one was logging (you could see who created a file) and the other was a permission check for the SE Linux patched version of Vixie cron which would not execute any command on behalf of a user unless the identity on the crontab file in the cron spool matched the identity used to run it – this is an analogy of the checks that Vixie cron makes on the Unix UID of the crontab file (some other cron daemons do fewer checks).
Having to recompile policy source every time you added a user was annoying. So a later development was to allow arbitrary mappings between Unix account names and SE Linux Identities (which included a default identity) and another later development was to have a utility program semanage to map particular Unix account and group names to SE Linux identities. This was all done years ago. Fedora Core 5 which was released in 2006 had the modular policy which included these features (apart from mapping Unix groups to SE Linux identities which was more recent).
Fedora Core 5 also introduced MCS which was comprised of a set of categories that a security context may have. The sysadmin would configure the set of categories that each account would have.
A recent development has been a concept named UBAC (User Based Access Control) which basically means that a process running directly on behalf of a regular user (IE with a SE Linux identity that’s not system_u) can only access files that have an identity of system_u or which have the same identity as the process. This means that you can only access your own files or system files – not files of other users which may have inappropriate Unix permissions. So for example if a user with a SE Linux identity of “john” gives their home directory the Unix permission mode of 0777 then a user with a SE Linux identity of “jane” can’t access their files. Of course this means that if you have a group of people working together on a project then they probably need to all have the same Identity and in practice you would probably end up with everyone having the same identity. I’ve given up on the idea of using UBAC in Debian.
The Current Plan for Users and SE Linux Access Control in Debian
My plan is to have things work in Squeeze in much the same way as in Lenny.
You have a SE Linux identity assigned to a login session and everything related to it (including cron jobs) based on the Unix account name or possibly the Unix group name (if there are login entries for both the user-name and the group-name then the user-name entry has precedence). The mapping between Unix accounts and SE Linux identities is configured by the sysadmin and SE Linux identities don’t matter much for the Targeted configuration (which is what most people use).
The identity determines which roles may be used and also has a limit on the MCS categories. The MCS categories are also specified in the login configuration which has to be a sub-set of the categories used by the identity record.
So for example the following is the output of a couple of commands run on a Debian/Unstable system. They show that the “test” Unix account is assigned a SE Linux identity of “staff_u” and an MCS range of “s0-s0:c1” (this means it creates files by default at level “s0” and can also write to other files at that level, but can also have read/write access to files at the level “s0:c1”). The “staff_u” identity (as shown in the output of “semanage user -l” can be used with all categories in the set “s0:c0.c1023” where the dot means the set of categories from c0 to c1023 inclusive) but in the case of the “test” user only one category will be used. The “test” group however (as expressed with “%test”) is given the identity “user_u” and is not permitted to use any categories.
# semanage login -l Login Name SELinux User MLS/MCS Range %test user_u s0 __default__ unconfined_u s0-s0:c0.c1023 root unconfined_u s0-s0:c0.c1023 system_u system_u s0-s0:c0.c1023 test staff_u s0-s0:c1 # semanage user -l Labeling MLS/ MLS/ SELinux User Prefix MCS Level MCS Range SELinux Roles root sysadm s0 s0-s0:c0.c1023 staff_r sysadm_r system_r staff_u staff s0 s0-s0:c0.c1023 staff_r sysadm_r sysadm_u sysadm s0 s0-s0:c0.c1023 sysadm_r system_u user s0 s0-s0:c0.c1023 system_r unconfined_u unconfined s0 s0-s0:c0.c1023 system_r unconfined_r user_u user s0 s0 user_r
I hope to get the policy written to support multiple user roles in time for the release of Squeeze. If I don’t make it then I will put such a policy on my own web site and try to get it included in an update. The policy currently basically works for a Targeted configuration where the users are not confined (apart from MCS).
How MMCS Basically Works
The vast majority of SE Linux users run with the MCS policy rather than the MLS policy. For Debian I have written a modified version of MCS that I call MMCS. MMCS is mandatory (you can’t relabel files to escape it) and it prevents write-down.
If a process has the range s0-s0:c1,c3 then it has full access to files labelled as s0, s0:c1, s0:c3, and s0:c1,c3 – and any files it creates will be labeled as s0.
If a process has the range s0:c1-s0:c1,c3 then it has read-only access to files labelled as s0 and s0:c3 and read-write access to files labelled as s0:c1 and s0:c1,c3. This means that any secret data it accesses that was labelled with category c1 can’t be leaked down to a file that is not labelled with that category.
Now MCS currently has no network access controls, so there’s nothing stopping a user from using scp or other network utilities to transfer files. But that’s the way with most usable systems. I don’t think that this is necessarily a problem, the almost total lack of network access controls in a traditional Unix model doesn’t seem to concern most people.
Now to REALLY Answer that Question
Unix permissions are based on each file having a UID, a GID, and a set of permissions and each process having a UID, a GID, and a set of supplementary GIDs. If a user runs a setuid or setgid program then the process will have extra privileges. It also has a lot of stuff that most people aren’t aware of such as real vs effective UIDs, the tag bit, setgid directories, and lots more – including some quite arbitrary things like making ports <1024 special.
SE Linux is based on every object (process, file, socket, etc) having a single security label which includes an identity, a role, a type, and a sensitivity label (MCS categories or an MLS range). There is no support for an object to have more than one label. The SE Linux equivalent to setuid/setgid files is a label for a file which triggers a domain transition when it’s executed. This differs from setuid files in that the domain transition is complete (the old privileges can’t be restored) and the transition is generally not to a strict super-set of the access (usually a different sub-set of possible access and sometimes to lesser access).
These differences are quite fundamental. So really SE Linux can’t implement traditional Unix access control. What SE Linux is designed to do is to provide a second layer of defense and to also provide access controls that have different aims than that of Unix permissions – such as being mandatory and implementing features such as MLS.