Security overview
- Security's goal: ensure the system does NOT perform any illegitimate function.
- How to define "legitimacy"?
- Principal: representation of a user inside the computer system
- Legitimate operations refer to a legtimate principal performing functions that he's been authorized for.
- Security mechanisms:
- Authenticity: correctly map users to principals
- Integrity: ensure requests for functions are not tampered with
- Authorization: ensure the principal is granted permission for performing a function
- Security goal is a negative goal.
- Easy to disprove: just find one instance of illegitimate operation.
- Hard to prove: one has to enumerate all possible ways to interact w/ systems and show no illegitmate operation is possible.
Design Principles
Why is securing computer systems difficult?
- Computer users are human: weak passwords, stolen passwords, installing random software, don't understand security mechanisms...
- Systems developers are human too: buggy software implementation, design could be buggy also...
Two important principles of building secure systems (book includes many other..)
1. Least privilege principle.
- Each program should only possess the minimal set of privileged required to perform its functions.
- The fewer privileges a program(user) has, the less can go wrong if the program(user) turns out to be buggy(stupid) or downright malicious.
2. Minimize trusted computing base (TCB).
- TCB refers to the portion of code (or sets of programs) that must work correctly to make the system secure.
- The simpler and smaller (in terms of LoC) the TCB, the better
- If TCB has fewer LoC to design/implement/inspect, the more likely it works correctly.
UNIX security mechanisms
Each user is identified by a (32-bit) UID
A root user (UID=0), treated specially by the kernel as the administrator. Root has all privileges.
Each process has a UID.
Each inode (file, dir) has an owner UID
One can view access control as a matrix, where each cell specifies allowed permissions
file_1 file_2 file_3 ... file_n
user_1 read write - - read
user_2 write write write - -
user_3 - - read - read
...
user_m read write read - write
Easier to specify permissions with role-based access control
- Each user is associated with one or more groups (GID).
Two ways to slice the permission matrix
- Along columns (The list system): OS stores list of principals that can access the object with the object. (e.g. UNIX)
- Along rows (The ticket system): Each principal holds a collection of "tickets" that give him access to objects. (capability system)
Now let's examine Unix protection
OS stores with each file permissions for user, group and others
$ ls -l index.html
-rw-rw-r-- 1 jinyang users ... 2009-04-15 13:22 index.html
/ /
/ /
owner group
$ ls -dl /etc/
drwxr-xr-x 135 root root 12288 2009-04-08 18:43 /etc
"User permissions" apply to processes with the same UID as the file/dir
"Group permissions" apply to processes with the same GID ...
"Other permissions" apply otherwise
Root (UID=0) has all privileges on all files/dirs
Other non-file access controls, e.g.
- Devices that show up in file system have permissions like files e.g. /dev/tty1
- Only root can bind TCP/UDP port less than 1024
- Only root can change the current process' UID and GID, setuid(UID)
- Only root can mount or umount file system
- Only root can change owner of a file
- Only root can halt or reboot machine
Privileged code (the TCB) in UNIX
All of UNIX kernel is certainly part of TCB.
In UNIX, many other user-level programs are privileged as well and hence part of TCB.
What runs as root and why?
Example: /bin/login runs as root. Why? In order to set the UID of a process to the authenticated user.
- UNIX users are stored in /etc/passwd: user name, UID, GID etc.
- H(salt, passwd) stored in /etc/shadow
- Match typed password to hashes in /etc/shadow
- If match, set UID and GID corresponding to user
- Execute user's shell with exec syscall
Login is part of TCB now. If it's buggy, ....
Example: rlogind runs "login [-f] username", then assume user already authenticated. User requests to login as "-froot"...
Many programs require privileges as part of their normal operations
- How can users change passwords?
- passwd program must be able to modify root-owned /etc/passwd and /etc/shadow
- How can email program append emails to each user's inboxes
UNIX solution: setuid/setgid programs (the alternative is to run a program as root)
Setuid-programs are very tricky to implement securely
- Bad guys can run setuid-programs anytime (don't have to wait for root to run them)
- Bad guys control many aspects of the program's environment
Example attacks on setuid-programs
- Change LD_PRELOAD, PATH... .
- fix: ignore LD_PRELOAD when running setuid-programs. always use full path in setuid-program.
- Close fd 2 before running setuid-program: may accidentally send error message into protected files.
- Caller send signals to setuid-programs (for legitimate reason: to kill a setuid-program. Bad guys: to pause and restart to exploit race conditions)
- Ptrace: let one process examine/modify another process's memory. Only allow when both real and effective UIDs match...
Getting setuid-programs right is harder than you think: exploit race conditions (TOCTTOU bugs)
xterm security hole:
- used to run as a setuid-program, because
- requires kernel pseudo-terminal device, needs to change device ownership to user
- writes protected utmp and wtmp file to record users
- xterm had a feature to log terminal session to a user specified log file
if (access (logfile, W_OK) < 0)
return error;
fd = open (logfile, O_CREAT|O_WRONLY|O_TRUNC, 0666);
/* ... */
- access call checks the permission of file access against real UID as opposed to effective UID. It is used to avoid writing to a file the user has no permission to.
- Is it secure?
TOCTTOU attack on xterm
| xterm attacker
| ------------------------------------------------------------------
| creat("/tmp/X")
| access("/tmp/X") -->OK
| unlink("/tmp/X")
| symlink("/tmp/X", "/etc/passwd")
| open("/tmp/X") -->OK
\|/
time
Attacker changes /tmp/X between check and use. xterm unwittingly overwrites /etc/passwd
setuid-programs often acquire and then drop privileges.
Another nasty case
Attacker creates two processes: A and B
| A B
| ---------------------------------------------------
| ptrace(B,...) --> OK
| execute "su attacker"
| su's effective UID becomes 0
| execute "su root"
| su's effective UID becomes 0
| A's allowed to trace "su root" because A's eUID=0
| A types in correct passwd
| su drops privilege
| now A is attached to process "su root" which has effective UID=0, can modify memory to get root shell
|
\|/
Limitations of UNIX's security
1. Cannot pass privileges to other processes
2. Cannot have multiple privileges at once
Programmers get around the limitations 1 and 2 by running setuid or root programs (violation of least privileges, bloated TCB)
3. UNIX security policy is somewhat ad-hoc:
- Only one rule is clear: root can do everything (violation of least privileges)
- when can non-root signal/debug processes? create links to files? (rules are changing to fix security holes discovered)
Alternative and (arguably better) security models
Capability-based systems (Hydra, KeyKOS)
- Slice the matrix along rows
- For each process, store a list of objects it can access
- Allow passing privileges around: e.g. give compiler arguments that specify output file and the capability to write to the file
- Another example: each user give mail program the privilege to write to his inbox file.
- Limitations of capabilities
- Performance overhead: Capability-based use lots more IPCs (to pass privileges aroud.) Performance concerns are perhaps no big deal nowadays
- Require changes throughout application software: to know what capabilities to use and to pass and accept capabitilities around.
Discretional vs. mandatory access control (DAC vs. MAC)
- UNIX implements DAC: the owner of the file can grant others' access, email it to the world etc.
- Military systems use MAC: security administrator can restrict information propagation
Typical MAC model:
- System has subjects (e.g. processes) and objects (e.g. files)
- Each subject and object has a security level (c,s)
- c is classification, e.g. unclassified, secret, top secret
- s is category set, e.g. nuclear, crypto
- (c1,s1) dominates (c2, s2) iff c1 ≥ c2 and s2 ⊆ s1
Information can only flow up the lattice
- System enforces "no read up, no write down"
- e.g. a process with security level (secret, {nuclear}) cannot read a file with label (top-securet, {nuclear}).
a process tainted with label (secret, {nuclear}) cannot write to a file with label (unclassified, \empty).
Many recent efforts to make MAC practical for non-miliary systems: LOMAC, Aesbestos, HiStar