Most modern operating systems are multi-user and give processes a ‘user identity’. This is a label denoting privilege. Access to objects that may be shared is controlled by the system. The OS provides expressive mechanisms that can represent a range of policies, the specific policy is then decided by the users of the system.
Example Access Control Policy
“Alice can read Alice’s mail, but Bob can’t.” The operating system will deny the request if Bob tries to read Alice’s mail.
Considerations for Access Control
We need to consider:
- what kind of policies are useful?
- how do we keep mechanisms simple, flexible, expressive, and efficient?
- when do we perform checks?
- are (human) user identities enough for expressing policy?
- how does this impact the design of the system call interface?
- how does this impact how we program?
- how do we establish identity?
- how do we distribute everything?
Example design: Unix pathnames, inodes and file descriptors
In Unix, we open() a file by pathname:
int fd = open("/home/alice/mail", O_RDONLY);
# then read(), write() on file handlesPermission checking is only done at open().
-rw-------- 1 alice alice 450871 Mar 4 2023 /home/alice/mail
# ^ owner is alice
# ^ group is alice
# rw-: owner can read, write but not execute
# ---: other members of group alice can do nothing
# ---: other users can do nothingPermission bits are stored in a Unix filesystem data structure called the inode.
After open(), having the file handle is enough and checks are not done at read() or write(). File descriptors may however be restricted at the time of open().
In the earlier example, we used
O_RDONLYwhich means onlyread()and notwrite()will succeed on handlefd.
The design means:
- cost of checking is amortised
- delegation is possible: can transmit
fdto other processes - revocation is hard: changing permissions doesn’t revoke open descriptors
Model of policies: access control matrix
We can draw a table of who has what access to which object:
| subject / object | /etc/passwd | /vmunix | /usr/bin/ls | /home/alice/project |
|---|---|---|---|---|
| alice | read | - | read, execute | read, write |
| bob | read | - | read, execute | read, write |
| charlie | read | - | read, execute | - |
| dave | read | - | read, execute | - |
We want to turn this into a data structure on a running system, we generally use one of two strategies: ACLs and Capabilities
| ACLs | Capabilities |
|---|---|
| stored with objects | stored with subjects |
| check permissions on access | check permission on issue + validity on use |
| easy to revoke | hard to revoke |
| hard to delegate | easy to delegate |
| usually coarse-grained | easily made fine-grained |
| easy to audit | hard to audit |
| easy to retrofit | must usually ‘design in’ |
| tend to bottleneck distribution | distributes more scalably |
| authority is ambient | authority is designated |
Access Control List (ACL)
Access Control List (ACL)
We can store each object with a list of pairs: (who, what access)
Unix’s ‘user’, ‘group’, ‘other’ permission bits are a limited ACL Full explicit ACLs can become large (when added up) and performance-sensitive (if checks are frequent).
The protect the object, at the object. Which means:
- easy to revoke permissions
- easy to understand and audit
However:
Link to original
- scale can become a problem if there are many users, files, actions
- authority is ambient: based on who you are; we can’t delegate fine-grained access to some code or process
Capabilities
Capabilities
We can give each subject a list of pairs: (which object, what access)
Each of these pairs is a capability similar to a file descriptor. We can also store capabilities with each process instead of user, enabling them to be fine-grained and dynamic.
Unforgeable token of authority on some object, possessing a valid reference is enough. Similar to keys on a keyring:
- each key has a distinct authority - can be fine-grained\
- to open a door you have to pick a key - designated, not ambient
- more than 1 key might open the same door differently
Link to originalThe validity check can be distributed using cryptography.