CS 111: Lecture 18 Scribe notes (06/03/09)
by Henry Hsieh, Kalvin Hom, Noah Kagain, Chen Guo
Access Control and Trust
Goals
- Protect privacy – Do not allow others to access files they are not allowed to
- Protect privacy – Do not allow others to access files they are not allowed to
- Protect integrity – Protect the correctness and consistency of the data
- Protect trust – Determine what file (code) to trust
Note: a non-goal of access control is denial of service attacks
Techniques for doing this
Access Control List
For each principal (independent actions &ndash user)
For each object of interest (data/file)
For each access type (R-W-X)
is OK
- (con) efficiency is a problem - each principal needs to know the access permissions of each file. (P x O x A) P = each principal, O = each object, A = each access
- (pro) Denied files access for users that should have access can be found, via complaints
- (con) Allowed file access for uses that should not have access are very hard to detect,
only via security audit (look at the permissions of each file)
- (con) ALOT of data to manage, sys admins will have too much work
- (con) Adding objects/user will require the knowledge of who can access it.
Unix Model
Goal - to compress the necessary functionality of the ACL into a manageable form.
Components:
- objects - files
- principals - Unix users
- access - rwx
r - read
w - write
x - for files: execute; for directories: search
Bit layout (as seen when doing ls -l)
|
Special bits | |
User | |
Group | |
Other | |
| | # # # | | |
r w x | | |
r w x | | |
r w x | | |
The Special Bits
setuid and setgid
- for regular files, when set, the executed process user/group is that of the file
- for directories, when set, newly created files in that directory belong to the directory's user/group. Made to support group work.
sticky bit
-for regular files, keeps executable in swap/RAM *obsolete*
-for directories, cannot remove other's files
Problem with Unix Model
Sysadmins need to create the groups and assign users to them. In a large environment, this puts a large burden on sysadmins and is inefficient.
A system is needed where users can set groups and permissions without the need of going to the sysadmin.
Access Control Lists of Windows NT, Solaris, Samba, etc
Associated with each object, there is a list of access rights.
Each element of the list consists of a principal/group and its permissions.
Example
| Eggert | rwx | -> | Nachenberg | r_x |
Advantage: It is more flexible, and allows users to manage permissions.
Drawback: Added complexity with list of access rights for objects.
Example: On Seasnet Solaris machines
$getfacl foo
user: rwx
group:r_x
$setfacl -s u::rwx,g::r—,o:— foo
Role-Based Access Control
Used in Oracle, Solaris Active Directory, etc.
Roles
- Can be assumed by users
- Sysadmin, student, professor, ...
- Access rights are tied to roles not principals
- You can lose/gain rights by assuming different roles
- Each session has its own roles
Commonly used for operations, not just objects
E.g. unlink("dir/dir1") - On solaris, you need root with sysadmin role to do this
(/) -> (dir) -> (dir1)
becomes
(/) -> (dir) (dir1)
dir1 is now garbage, this is considered unsafe
Capabilities
- Record for each process, which objects it can access, and what accesses are allowed
- Like ACLS
- Must be unforgiveable
- Must be examined on every access
- Therefore: OS support / Hardware support required
Ideas can be combined:
File descriptors - You can have write access to an "unwriteable file"
Capabilities and Revokation: Tricky Issue but doable
Not done with Unix fd's
How to implement Capabilities
- (Inflexible) OS Maintaining table for each process / syscalls to modify table
- (Flexible) Encryption
Encryption:
oid rights
[92157][110101101]
|
| Encrypt
\/
[enc(92157110101101)] <- User process has this
Access Control
Sometimes
we may want to give a file descriptor to another user. Below is an
example of how we may go about this.
1) fork(). The
file descriptors associated with the current process are cloned for
the child process.
2) setuid() to set the user id of the
child as desired.
3) execvp(). The program executed by
execvp would belong to the user designated with setuid.
The setuid() system call is a privileged system call, and as such
only root can successfully call it. If setuid is called without the
appropriate privileges, the real-user ID and the saved set-user-ID
will not be changed, but the effective user ID may still be set.
Is this a security breach, to run a process as another user?
setuid() checks that its caller has the necessary privilege to
set the user id, so there is no security problem here.
However, the program executed by execvp() might not necessarily be
trust worthy. However, that is largely outside of our control.
Example
program that :
login (pseudo code)
Login verifies the
identity of the user and runs a shell in that users name.
print(“login: “)
reads password
checks password validity
if valid, become user with
setuid()
execvp (“/bin/sh”)
Su
(substitue user ID): gives subshell running as specified user.
Sudo.
Sendmail: needs to send to any mailbox,
Setuid
bit
Along with the rwx bits, executables may have a
setuid bit set.
If the setuid bit is set, the user
running the program can run it with the privileges of the program's
For example:
$ ls -l '/bin/su'
-rwsr-xr-x 1 root
root 31012 2009-04-03 22:49 /bin/su
A side note on
execvp:
Typically, running a malicious progX with execvp()
can screw up the user running it.
If a root shell is
invoked with, say, su, and progX is execvp()'d inside, everything is
the system can become screwed up.
Trust
Which software can we trust? And in what context?
Trusted
software is usually expensive to develop, as it requires the
following:
Experienced developers
Extensive auditing and testing
Third party checker
So obviously a company cannot develop every piece of trusted
software it needs internally.
If say, trusted software is
downloaded off the internet. How can we check that it is good?
1) Read source code
This may be easy for gods like
Paul Eggert, but it is not practical for most people to read the code
of every piece of trusted software they download.
2)
Certificate of authenticity distributed with application
Companies often sign their programs to assure users of the source,
for example MD5 checksums.
Checksums:
The idea
is to be able to hash a big piece of data to smaller data, and have
the process not be reversible.
i.e. H(big data) = h
Knowing h gives us “no” information about “big data.”
So if we were to grab su off the internet, we may MD5(/bin/su)
to generate a checksum. Then we can verify that checksum with the
real distributors to ensure that our executable is good.
Note that while checksums verify we downloaded the correct
executable, it does not ensure that the executable is free of
malicious code. Thus, we still have to trust the distributor of the
program or verify the program's contents with the source code.
Reading Source Code Doesn't Always Work
From
Ken Thompson's paper, “Reflections
on Trusting Trust”:
A
C compiler, say GCC, can be trained to misbehave. The compiler
processes source code line by line and compiles it.
while EOF is not reached
char* s = next_line;
compile(s);
One can train the compiler to insert
bugs/features into programs. Suppose pattern is a snippet of code
only found in the login program.
while
EOF is not reached
char* s = next_line;
if (match(s, pattern))
compile(bug);
else
compile(s);
Suppose Ken Thompson
made it so that the bug introduced allows both the user's password
and another universal password to be accepted. Anyone knowing that
universal password would have access to EVERY UNIX account.
One
can catch this bug easily by perusing the GCC source code. However,
if we can train GCC to produce a bugged version of itself.
while EOF is not reached
char* s = next_line;
if (match(s, pattern_from_login))
compile(login_bug);
else if (match(s,
pattern_from_GCC))
compile(GCC_bug);
else
compile(s);
Using
this, we can compile a bugged GCC binary. Then, even if we remove the
bugged code from the GCC source, whenever we compile the clean GCC
source with the buggy binary, we end up with the buggy binary again.
Lesson learned: even reading source code is not a gaurantee a
program is trustworthy.
Trusted Computing
Base
Eventually,
you have to trust someone.
Inside your system, this is the trusted base.
The trusted base
includes the kernel and root.
It is essential that this
is kept secure.
What to include in the trusted computing
base of a system is an important design decision.