[comp.unix.wizards] Enforcing Permissions

bernsten@phoenix.Princeton.EDU (Dan Bernstein) (05/04/89)

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@phoenix.princeton.edu

campbell@redsox.bsw.com (Larry Campbell) (05/05/89)

Who cares?  Why would you ever want to revoke, quickly, access you had once
granted?  What's wrong with just shutting down the system?
-- 
Larry Campbell                          The Boston Software Works, Inc.
campbell@bsw.com                        120 Fulton Street
wjh12!redsox!campbell                   Boston, MA 02146

sukthnkr@phoenix.Princeton.EDU (Rahul Sukthankar) (05/06/89)

In article <746@redsox.bsw.com> campbell@redsox.UUCP (Larry Campbell) writes:
>Who cares?  Why would you ever want to revoke, quickly, access you had once
>granted?  What's wrong with just shutting down the system?
>-- 

There are many times I can see this as a problem -- here are just 2:
a) I turn my mesg y; Obnoxious user starts a cat > /dev/ttya; I get
     annoyed; I do mesg n; nothing happens; I stay annoyed.
b) I accidentally give write permission to ~.  Alert badguy starts a
     process which accesses ~.  I can do NOTHING about it.
     
P.S. Shut down the system??  I am *not* the super-user.

Not all UNIX users are nice people.

>Larry Campbell                          The Boston Software Works, Inc.
>campbell@bsw.com                        120 Fulton Street
>wjh12!redsox!campbell                   Boston, MA 02146

Rahul Sukthankar
sukthnkr@phoenix.princeton.edu

bill@twwells.uucp (T. William Wells) (05/06/89)

In article <8134@phoenix.Princeton.EDU> bernsten@phoenix.Princeton.EDU (Dan Bernstein) writes:
: 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.

Kill -9 might be overkill, but it certainly would do the job.

---
Bill                            { uunet | novavax } !twwells!bill

dlnash@ut-emx.UUCP (Donald L. Nash) (05/08/89)

In article <8134@phoenix.Princeton.EDU>, bernsten@phoenix.Princeton.EDU (Dan Bernstein) writes:
> 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.
> [...]
> 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.
                                                       ^^^^^^^^^^

Depends on your definition of "reasonable".  Have you ever tried the
following:

mkdir /tmp/foo
cd /tmp/foo
rmdir /tmp/foo
pwd

The results are interesting.  Since the reference count on the inode for
/tmp/foo is 1, the inode and disk blocks of the file are not freed.  However,
the link ".." is removed, so this directory is cut off from the rest of the
filesystem.  Many of your favorite system calls fail, so utilities like pwd,
ls, cd all start to behave very strangely.  The only way out is to cd to an
absolute path.  A similar thing could be done when your current directory
is enforce()'ed out from under you.  If you try to do some operation on the
current directory and you no longer have permission, then system calls just
start failing and the only way out may be to cd to an absolute pathname.

I don't know, but it sounds reasonable to me...


				Don Nash

				The University of Texas System
				Office of Telecommunication Services

SMTP:    dlnash@emx.utexas.edu, don@nic.the.net
BITNET:  DON@THENIC
UUCP:    ...!cs.utexas.edu!emx!dlnash

dsill@relay.nswc.navy.mil (05/09/89)

>Kill -9 might be overkill, but it certainly would do the job.

Yeah, it certainly would.  If everyone was the superuser.  I like
Dan's suggestion of a system call that would allow one revoke
previously granted access.

-Dave (dsill@relay.nswc.navy.mil)