BSD tty security, part 3: How to Fix It

Keith Muller muller at sdcc10.ucsd.edu
Sun May 5 08:46:15 AEST 1991


In article <1237:May321:05:0191 at kramden.acf.nyu.edu>, brnstnd at kramden.acf.nyu.edu (Dan Bernstein) writes:
> 
> (It will work for hardwired ttys if you make the outlined changes to
> getty's initialization routine. But without a secure break key [as you
> can implement with my suggestion #24], hardwired ttys are completely
> insecure anyway.)

Why should hardwire ttys be insecure? Login session terminal termination
occurs when either the login shell exits or dcd drops (assuming -nohang
is set). Preventing login just because a background job is referencing a
tty is not acceptable.

If I read #24 correctly you want to force ttys through ptys? (connecting
the master side with a pipe through the hardwire port). So ptys are
the only thing used for login sessions.... Sure is a lot
of overhead (in and out of user mode multiple times to move data). 

> And once you have included special treatment of that flag in every
> single tty operation. This is a lot of kernel work. Why do you refuse to
> write out these changes at a sufficiently low level of detail that
> people can implement them? If it's so few lines of code, why don't you
> write out the code?

I am not trying to promote a fix, but promote a discussion on how to 
address tty semantics . The only reason I even answer your postings is to
point out that other METHODS exsist.

The code to check access is simple and the majority of the tests are already
is in the kernel. 

I am looking at the code (4.3 reno) right now.  On entry point in the
kernel for read() for example we see:

	if (((unsigned)uap->fdes) >= NOFILE ||
		    (fp = u.u_ofile[uap->fdes]) == NULL ||
			(fp->f_flag & FREAD) == 0)
			return (EBADF);

Now tell me the open file table access rights for the read isn't being
done here....

Traversing the open file table on device deallocation
is not a lot of code. Vhangup() (aka forceclose()) does it already (from
4.3 tahoe):

forceclose(dev)
	dev_t dev;
{
	register struct file *fp;
	register struct inode *ip;

	for (fp = file; fp < fileNFILE; fp++) {
		if (fp->f_count == 0)
			continue;
		if (fp->f_type != DTYPE_INODE)
			continue;
		ip = (struct inode *)fp->f_data;
		if (ip == 0)
			continue;
		if ((ip->i_mode & IFMT) != IFCHR)
			continue;
		if (ip->i_rdev != dev)
			continue;
		fp->f_flag &= ~(FREAD|FWRITE);
	}
}

So even by revoking access the way vhangup does (by removind read/write
access and not using an additional flag) the code is small. Deallocation
of ttys is not a very highly called occurance to consider the above loop
"intensive". (it is certainly a lot less load than what I think you
want to do to the data flow on herdware ttys). Actually in both this and
your method the case where multiple (v)(i)nodes reference the same device
probably should be addressed (even if it is a questionable thing to do)..

> ttyd is standard BSD, and is on the vast majority of BSD-derived
> systems. ttyvp only appears on Suns, very recent (i.e. non-production)
> BSD releases, and possibly some obscure or extremely recently released
> systems that I'm not familiar with.

Looking at the source for 4.3 tahoe there is no p_ttyd or u_ttyd.  All tty
references use the open file table. Access removed there terminates access
to the tty. If f_flag permissions (or a revoked flag if you want to do it
that way) (or even more strongly if f_data does not reference the
active inode in the kernel), that fd cannot do i/o.

In the 4.3 reno you get from CSRG, ttyvp does exsist (see kern/tty_tty.c).

> I repeat my claim: your changes don't close the holes on anything but
> Suns and very recent BSD releases (such as Reno). In fact, unless you
> know you've changed every single tty operation to check that flag and
> behave properly, including when coming out of sleep, your changes are
> insecure even on those systems.

There about 17 places where you sleep on read/write and ioctl for
tty ops. All in tty.c and tty_pty.c (all have  similar code fragments,
many of which relate to hanging background operations). In most places
the sleep is followed by a goto to the top (entry point) of the routine.
At the top is one place the check could be done. For example the
sleep() fragment in ttread() (from 4.3 tahoe) looks like:

 if (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
	 if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
	    (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
		u.u_procp->p_flag&SVFORK)
			return (EIO);
	  gsignal(u.u_procp->p_pgrp, SIGTTIN);
	  sleep((caddr_t)&lbolt, TTIPRI);
	  goto loop;
	}

Now loop is at the top of the routine. Adding the following line (assuming
you pass the tty struct to the routines) does the check for read for
example. (the if statement after the loop: is what is added).This uses
a access restriction scheme like vhangup (not an added flag but removing the
read/write flags as demonstrated in forceclose() above.

loop:
	if ((fp->f_flag & FREAD) == 0)
		return(EBADF);

> 
> But you want people to add an extra check, plus have it handled for
> blocking processes. I repeat my claim.

This is the only check added. Not a significant consumption of time.
(You could just make it a macro and put it after each sleep if you want
to trade space for time).

>> On 4.3 RENO and earlier there is only u_ttyvp, so that replacement
>> is not needed.

> This statement is simply incorrect. On BSD 4.3 Reno and LATER there is
> u_ttyvp. I believe that they took the name and idea from SunOS, though
> I'll have to check this with Marc Teitelbaum.

Yes a typo on my part. (The earlier should be later, the surrounding
paragraphs did support the corrected statement).

> 
> Damn it, I can't stay polite about this. You obviously aren't familiar
> with a wide range of machines---your statements about u_ttyvp prove
> that. Your fixes do not work on most machines, but you say they do
> because you don't know what you're doing. This is exactly the kind of
> sheer idiocy that has let to the current situation: nobody fixes the
> .... 
  
Excuse me but I am only illustrating a different technique does exsist
and never stated I was providing a fix to all variants of UNIX..
I simply used BSD as a counter example in my posting as an alternate
to what you start out saying when you descibe your fixes:

>Here's one way to fix the BSD 4.[234] tty system, i.e., to provide some

And thats what I desribed, a technique for the BSD 4.[234] tty system.
If some vendor adds a tty device or tty access method in THEIR operating
system that does not use the open file table like 4.[234] does then
they should rethink the reasons why it was done. (maybe throwing
out the open file table is a reasonable thing and should be done, but that
is not what this discussion is about).

Unless you are looking at a different BSD kernel source than I, your
statements about tty i/o access in BSD (tahoe or reno) is in error.
Please look at the actual kernel code before "shooting from the hip".

Keith Muller
University of California



More information about the Comp.unix.wizards mailing list