COMMAND
open()
SYSTEMS AFFECTED
FreeBSD 2.1.*, FreeBSD 2.2.*, FreeBSD-stable and FreeBSD-current,
NetBSD, OpenBSD
PROBLEM
In FreeBSD, the open() system call is used in normal file
operations. When calling open(), the caller should specify if the
file is to be opened for reading, for writing or for both. The
right to reading from and/or writing to a file is controlled by
the file's mode bits in the filesystem. In FreeBSD, open() is
also used to obtain the right to do privileged io instructions.
A problem exists in the open() syscall that allows processes
to obtain a valid file descriptor without having read or write
permissions on the file being opened. This is normally not a
problem. The FreeBSD way of obtaining the right to do io
instructions however, is based on the right to open a specific
file (/dev/io). The problem can be used by any user on the
system to do unauthorised io instructions.
This is a pretty serious hole in open() and permissions... Note,
in the following, open() succeeds, and ioctls are probably
executed... This was posted by explorer.
/*
* This will give you a file descriptor on a device you should not
* have access to. This seems really, really screwed up, since
* holding a fd lets you do a lot of ioctls that you should not be
* able to do...
*/
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <err.h>
int
main(int argc, char **argv)
{
int fd;
fd = open("/dev/rsd0a", -1, 0);
if (fd < 0)
err(1, "open");
}
This is a variant of a bug Theo de Raadt found in SunOS back in
the 1980s. The basic issue is that the code that guards access
to the device-specific open() routine checks explicitly for FREAD,
FWRITE, and O_TRUNC, and passes the call through if none of these
are set. Theo's bug involved using "3" for the open() flag.
The problem here is that before calls to open() are even passed to
the vnode open() routine (after the vnode is looked up by the
generic vfs_syscalls open() syscall handler), the flags field is
incremented by one:
vfs_syscalls.c:open()
...
flags = FFLAGS(uap->flags);
...
where FFLAGS() is:
./sys/fcntl.h:#define FFLAGS(oflags) ((oflags) + 1)
As you can see, passing a "-1" to open() will result in "flags"
becoming "0" - open() ordinarily never passes "0" to the vnode
code, since "0" becomes "1" after being converted to fflags
format.
A fun game you can play with practically no programming ability is
to exploit the fact that some devices will initialize themselves
immediately upon being opened - particularly amusing is the SCSI
tape driver, sys/scsi/st.c, which will rewind itself when opened.
Simply run the previously posted example code on /dev/rst0 and
destroy tonight's backup.
SOLUTION
You may want to get closer look ar FreeBSD patch:
ftp://freebsd.org/pub/CERT/patches/SA-97:05/