Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!iuvax!rutgers!njin!princeton!phoenix!bernsten From: bernsten@phoenix.Princeton.EDU (Dan Bernstein) Newsgroups: comp.unix.wizards Subject: Enforcing Permissions Message-ID: <8134@phoenix.Princeton.EDU> Date: 4 May 89 15:06:19 GMT Reply-To: bernsten@phoenix.Princeton.EDU (Dan Bernstein) Distribution: usa Organization: Hmph. Lines: 49 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