BSD tty security, part 3: How to Fix It
Keith Muller
muller at sdcc10.ucsd.edu
Fri May 3 19:59:55 AEST 1991
In article <15369:May219:46:0491 at kramden.acf.nyu.edu>, brnstnd at kramden.acf.nyu.edu (Dan Bernstein) writes:
>The only unusual aspect of my solution is TIOCOPENCT, which is
>sufficient to simulate dynamic ttys with static ttys. Making the tty
>files inaccessible and making programs setuid is a standard technique.
>Replacing /dev/tty with my /dev/stdtty is necessary (on systems without
>u_ttyvp, anyway) to close the avenue that gets around most ``fixes.''
>Together these changes *do* solve the underlying problems of statically
>allocated ttys, though I would prefer that ptys be as dynamic as pipes
>in the first place.
You missed the point. Your method boils down to avoiding using ptys (and only
works for ptys it will not work for real hardware ttys) that have background
jobs still using them. my discussion was to outline a technique to deal
with background jobs access to ttys in general to make people
think about what to do about background jobs that still have
access to real ttys once a user logs out or the master side process terminates
on a pty. Better solutions are gained when alternative solutions are
investigated.
->Remember your article title was BSD tty security (not sunos pty security).<-
>I address this in the comments after step 12. You can, for instance,
>arrange for each process to skip a tty during allocation if TIOCOPENCT
>indicates that the file is in use. However, this added complexity is not
>strictly necessary, and on most machines the servers really don't crash.
>If you have the time and energy, by all means add TIOCOPENCT checks at
>the beginning of each session.
On very active system with lots of background (or hung jobs) you eventually
run out of ptys. Without your {sleep, TIOCOPENCT ... loop} the service denial
hole is still present. This is something that is fairly important in
many environments. Legitimate background jobs deny service to that pty
in your scheme (unless you go the vahangup() route you suggested in you
comments (resulting is doing a similar action as revoke()... ah but then your
allocation would have to run as root....)
>The complexity is already there! A typical BSD system has a dozen
>programs managing the pseudo-tty resources. This type of decentralized
>management is stupid, and it makes any tty fix much harder to apply, but
>my fixes certainly don't make the situation any worse.
Again you need to address both hardware and ptys. My point is there a
an alternative to pty allocation that is less complex (the revoke()
suggestion encased in "exclusive use" ioctls is a lot simplier than the
complex setup and cleanup you are suggesting. It is easily stuck in
a library routine also and is a lot less code).
>Your solution requires many more changes than mine, and most of them in
>the kernel. It does not provide or simulate a simple model like dynamic
>ttys. It is not spelled out in sufficient detail for someone to
>implement, and the effects of each change are not explained.
The number of changes is not a lot of code nor is it any more complex.
Tracking down all those references to a pty (or tty) is the SAME for
both your TIOCOPENCT and the revoke(). Clearing and/or setting a flag
once you have found the references is trival.
Most of the framework for revoke() is in the kernel already exists as most
i/o related system calls already make an access check on the open file table
flags at each entry into the kernel (at least 4.3 tahoe and earlier does).
Code (a small amount) is added to handle sleeping processes (a failure of
vhangup()) I wasn't giving a "cookbook" but drafting an alternative to
provoke discussion on the topic (of access rights to ttys). The discussion
simply addresses the protection of ttys from prior reference attacks and not
how to implement what you call "dynamic" ttys. (Do you mean dynamic creation
of ptys....????). Again I was addressing (p)tys as they current exisist in
BSD unix (a static device).
>Most importantly, your changes don't close the holes on anything but
>Suns and very recent BSD releases. Should I explain this? All your
>revoke() does is stop access through the open file table (and it's not
>entirely clear that it will work any better than vhangup() for that).
>But p_ttyd (or u_ttyd) doesn't *go* through the open file table. Poof,
>there goes your security.
Neither p_ttyd (or u_ttyd) are in 4.3 RENO or earlier (and you did call
this a BSD tty security fix). I did state this concept was only tried on a
4.3 tahoe system. The difference from vhangup() is that the checks are
carried down into those routines that sleep(). vhangup() fails to protect
due to the fact that it removes read/write access in another process context.
Jobs that sleep through this in the tty routines can complete when they
run (performing a single I/O that should NOT occur). You may not need
the extra flag if you simply want to kill off access the way vhangup()
does. Of course this destroys access right state you may want to consider on
future operations by that process (like what kind of errno to return etc).
>You also require that a flag be added to the file structure and that
>every single tty I/O operation be changed to pay attention to that flag
>and take special action if it is set. So far (not to mention replacing
>u_ttyd with u_ttyvp or the equivalent) we're talking about some hundreds
>of extra lines of kernel code---far more than required to implement
>/dev/fd/3 (to replace /dev/tty) or TIOCOPENCT.
As stated above access rights are already checked on i/o ops, adding
a check for the revoke flag (or if you have revoke strip off read/write flags
like vhangup() then there is little extra code besides revoke() itself).
On 4.3 RENO and earlier there is only u_ttyvp, so that replacement
is not needed.
>You require that all tty-handling programs be setuid root. Setuid to
>some other uid would be much safer---but you can't do that without
>letting unprivileged users abuse revoke().
It is as easy (or easier) to make a setuid() program safe as it is to
preventing a server from crashing before it cleans up (so you state).
Having a pty "allocation" running as non-root causes problems. It this case the
slave side would be owned by pty and not the user. This eliminates redirects
to/from the tty by the valid user of the pty. Things like mesg etc would
have to be setuid() pty to work. What about movement of data between two
ptys owned by the same user? A single user would be unable to access
another pty he was assigned by pty. This is asymmetric to the allocation
of real ttys (and the allocation or actions by setuid root clients that
use ptys... rlogind). Running as nonroot also eliminates the use of
vhangup() which you suggest using under those conditions where ptys are
held up by background jobs. Besides vhangup is easily spoofed and also
works only on the open file table. What about REAL ttys....???
They also are subject to the similar attacks, how do you protect them?
>I'm sorry to criticize your changes in such harsh terms, but they remind
>me too much of the kludge upon kludge that vendors like Convex have
>tried. You don't stop the problems at their source; you let two
>independent user programs have a tty simultaneously open; your changes
>don't even work as advertised on most machines, because you missed a
>fundamental avenue around your revoke(). Even if your fix were simpler
>or less fragile than mine, these flaws would condemn it.
>
Sorry you are so sensitive about your design (I suspect many people
consider your proposal a kludge...). On BSD (not SunOS based
machines) up to 4.3 RENO (which do not have p_ttyd (or u_ttyd))
the basic revoke() works with simple client mods and simple
kernel mods. In the environment BSD prior to 4.3 RENO revoke() works as
advertised (no process remains with any access after the revoke()),
so your objections are misdirected. If you read my discussion more carefully
you would have seen that I was careful to state this was an idea tested on
4.3 tahoe only as a proof of concept. My only goal was to show an alternative
to your user mode based allocation could work and not stomp on your ego...
This is why i dicussed the topic rather than casting a single solution
in concrete as THE ONLY WAY.
What your solution fails to address are problems with real ttys which
have problems similar to ptys (And the title IS security of BSD ttys...)
and should have the benefit of similar protections.
Keith Muller
University of California
kmuller at ucsd.edu
More information about the Comp.unix.wizards
mailing list