Enforcing Permissions

Dan Bernstein bernsten at phoenix.Princeton.EDU
Fri May 5 01:06:19 AEST 1989


There is a fundamental problem with UNIX security that alone prevents
acceptance of UNIX at the B1 security classification or above: It is
not possible to cure a security violation, only to prevent it. There
is no way for a user to close a hole that is being used.

For example, access permissions on a file are only checked at the time
of an open(). Once a process has a file open, there is no way to force
it to give up the file descriptor.

Fortunately, this problem is easy to solve, with a single added system
call: enforce(char *name). Here name must be some item owned by the user
in some namespace; enforce() re-checks all u areas of all processes for
any violation of the *current* permissions on name, and revokes any
permission that is not currently allowed. Note that the current working
directory is one u area entry where enforce() cannot reasonably function.

enforce() should return EPERM if the current uid is neither root nor the
owner of name. If it succeeds, any file descriptors or sockets where
access is revoked should give EPERM to further I/O operations; if CPU
time limits become a name space item and they are then downgraded and
enforce()d, the process should immediately receive SIGXCPU; etc.

This differs from so-called ``opaque'' file systems, where permission is
checked on every read() or write(), in four ways: 1. Opaque file systems
are slightly less efficient because they check on every system call.
2. Opaque file systems put the burden of the wasted time for security upon
every system call, rather than just upon the enforcer. 3. Opaque file
systems reduce functionality in that they simply don't allow situations
where you only want permissions checked at the open() only; e.g., redirect
output to a file and then change the file mode to 000 to prevent other
processes from accidentally overwriting the file. 4. enforce() can be
put into the kernel with a minimum of effort, doesn't require changes
to any other system calls, and won't break programs that don't use it.

One interesting point must be mentioned. enforce() is obviously along
the lines of vhangup() and other revoke-tty-permissions systems calls,
though it is far more general. vhangup() doesn't work because of its
misfeature of ignoring /dev/tty; enforce() should do a better job.
Indeed, enforce() is specified above as checking through all appropriate
entries in the u area; if name is a tty, enforce() not only imitates
vhangup() but also dissociates the control terminal of processes that
are no longer permitted access. After all, control tty is in the u area
too!

The applications of this are obvious; /bin/enforce and chmod -e come
to mind, and finally mesg n can have some effect. So, UNIX systems
designers, how interested are you in security?

---Dan Bernstein, bernsten at phoenix.princeton.edu



More information about the Comp.unix.wizards mailing list