Xref: utzoo comp.unix.wizards:25361 alt.security:2416 Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!crdgw1!uunet!ogicse!ucsd!sdcc6!sdcc10!muller From: muller@sdcc10.ucsd.edu (Keith Muller) Newsgroups: comp.unix.wizards,alt.security Subject: Re: BSD tty security, part 3: How to Fix It Message-ID: <18953@sdcc6.ucsd.edu> Date: 3 May 91 09:59:55 GMT References: <7299:Apr2510:22:2091@kramden.acf.nyu.edu> <18924@sdcc6.ucsd.edu> <15369:May219:46:0491@kramden.acf.nyu.edu> Sender: news@sdcc6.ucsd.edu Followup-To: comp.unix.wizards,alt.security Lines: 148 In article <15369:May219:46:0491@kramden.acf.nyu.edu>, brnstnd@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@ucsd.edu