Re: Possible SERIOUS bug in open()?

Aleph One (aleph1@DFW.NET)
Thu, 23 Oct 1997 10:05:27 -0500

---------- Forwarded message ----------
Date: 23 Oct 1997 06:36:36 -0000
From: tqbf@joshua.enteract.com
To: dima@best.net, freebsd-security@FreeBSD.ORG
Subject: Re: BoS: Possible SERIOUS bug in open()? (fwd)

In muc.lists.freebsd.security, you wrote:
> fd = open("/dev/rsd0a", -1, 0);

Yep. This definitely works on {Free,Net,Open}BSD.

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.

If you want to hack this fixed in FreeBSD, you can apply the enclosed diff
to your kernel; this is a total hack, and someone else will provide a
"correct" fix soon enough.

Incidentally, this is yet another piece of evidence supporting the
presence of another systemic secure-coding problem - sanity checking
integer arguments and guarding against overflow. This is far from the only
place that I've seen problems with unexpected interactions owing to
surprise negative arguments. Anyone want to take a guess as to what
strncpy() does when it gets a negative "count" argument? Think that can't
happen? Think pointer arithmetic.

--
-----------------------------------------------------------------------------
Thomas H. Ptacek                                        Secure Networks, Inc.
-----------------------------------------------------------------------------
                                                     "mmm... sacrilicious..."

--- vfs_syscalls.c-orig Thu Oct 23 01:21:58 1997 +++ vfs_syscalls.c Thu Oct 23 01:21:19 1997 @@ -690,6 +690,9 @@ return (error); fp = nfp; flags = FFLAGS(uap->flags); + if(!flags) + flags++; + cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, p); p->p_dupfd = -indx - 1; /* XXX check for fdopen */