home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume25 / pty4 / part05 / NEW next >
Encoding:
Text File  |  1992-02-18  |  8.9 KB  |  164 lines

  1. pty 4.0 (``newpty'' below) is an almost complete rewrite of pty 3.0
  2. (``oldpty''). Some features and misfeatures have been removed:
  3.  
  4. 1. newpty no longer allows for systems without file descriptor passing.
  5. 2. newpty does not go to obscene lengths to ensure non-blocking I/O.
  6. 3. newpty does not worry about the buggy MAXUPRC handling in BSD 4.{2,3}.
  7. 4. newpty no longer maintains an entire hierarchy of special files.
  8. 5. The x* utilities and -xS are gone.
  9. 6. For security reasons, -f is gone.
  10. 7. sessuser is gone, as nobody uses it. In its place is sessmenu (see below).
  11. 8. The semi-automatic INSTALL has been replaced by a sane configuration system.
  12.  
  13. Several new features have been added:
  14.  
  15. 9. You can now disconnect, reconnect, and rename sessions remotely.
  16. 10. newpty performs much better tests than oldpty for tty security.
  17. 11. newpty uses my sigsched library; this greatly simplifies the code.
  18. 12. newpty's random tty searching is not vulnerable to secondary clustering.
  19. 13. newpty supports session and session-connection logs as well as [uw]tmp.
  20. 14. newpty now maintains a single, reliable communications file for each pty.
  21. 15. Internally, the master and signaller are much more cleanly separated.
  22. 16. oldpty's -d served two different functions. newpty's -d is simpler.
  23. 17. When oldpty reaches EOF on input, it loops forever. newpty doesn't.
  24. 18. newpty's error messages are, believe it or not, comprehensible.
  25. 19. newpty lets the user set his host field in utmp (this is configurable).
  26. 20. newpty gives the slave a PTY variable showing its extension (e.g., p7).
  27. 21. A ``sessmenu'' utility can serve as a friendly session-aware login wrapper.
  28. 22. newpty includes ``utmpinit'' to properly initialize /etc/utmp.
  29. 23. A ``nobuf'' utility now provides a completely transparent channel.
  30.  
  31.  
  32. Further notes on these:
  33.  
  34. 1. Large sections of code in oldpty were dedicated to handling systems
  35. without reliable file descriptor passing (i.e., many BSD 4.2 variants).
  36. In newpty this code is gone. I still work around the fd passing bugs
  37. that appear in the latest SunOS and Ultrix releases.
  38.  
  39. 2. In oldpty, I spent a lot of time on non-blocking I/O. There's a long
  40. and sad story behind this; read on.
  41.  
  42. Even though every bit of semantics of read() and write() is drastically
  43. affected by whether the descriptor is non-blocking, UNIX implementors
  44. through the years have always---I mean *always*---provided for
  45. non-blocking I/O on a given open file, rather than on a particular
  46. descriptor. This is fine for programs which open their own descriptors.
  47. But pty has to do I/O on input and output descriptors which someone else
  48. has set up. It can't set NDELAY on those descriptors, because another
  49. innocent program might be reading or writing the same descriptors, and
  50. NDELAY will in all probability make that program go into an infinite
  51. loop!
  52.  
  53. Of course, what most people do is just select() for readability or
  54. writability, then assume the operations won't block. The problem is that
  55. they might block. By the time pty gets around to reading, someone else
  56. could have read the input which caused select() to return. Similarly,
  57. any write of N bytes to a pipe with M bytes free, with N > M > 0, will
  58. block, even though select will return true. So I figured out a way to
  59. achieve true per-process non-blocking I/O: simply arrange for SIGALRM to
  60. be sent every fraction of a second, interrupting any blocking read() or
  61. write(). This works---but not under BSD 4.2, which restarts system
  62. calls. oldpty's configuration process reflected this extra complexity.
  63.  
  64. Now I've seen the light. True non-blocking I/O be damned. I'm just going
  65. to select() and do my operations like everyone else. It's not my fault
  66. that so few implementors understand why non-blocking I/O on an entire
  67. open file, rather than a particular descriptor, is so useless. If emacs
  68. and screen and so many other programs don't care, I won't either. newpty
  69. takes none of oldpty's precautions, and if it ever blocks because a pipe
  70. is too full or because there are multiple readers, don't blame me. Blame
  71. a truly senseless OS design decision.
  72.  
  73. 3. All BSD variants have a maximum process limit, MAXUPRC or maxuprc in
  74. <sys/param.h>. When there are MAXUPRC processes with some uid (other
  75. than 0), the next fork() by that uid will fail. A bit of thought will
  76. convince you that MAXUPRC should apply to the real uid. If it applied to
  77. the effective uid, then it would affect execve() of setuid programs.
  78. Even worse, if you had a program setuid (say) ingres, and MAXUPRC users
  79. ran that program at once, no other users would be able to run it! So
  80. applying MAXUPRC to the effective uid is a really bad idea.
  81.  
  82. Guess what? Almost all vendors have applied MAXUPRC to the effective
  83. uid. On the other hand, few of them have paid any attention to execve()
  84. of setuid programs, so in the ingres case any number of users can run
  85. the program, dragging the process count way above MAXUPRC. If you have
  86. any experience in crashing UNIX systems you'll guess what I'm about to
  87. say: If the process count for a uid does go above MAXUPRC, then as soon
  88. as MAXUPRC of those processes die, the system will panic. (This is true
  89. under, e.g., Ultrix.) Brilliant.
  90.  
  91. As you can imagine, none of this is conducive to safe setuid
  92. programming. System panics aside, pty has to fork twice, and I didn't
  93. want to limit it to MAXUPRC/2 simultaneous invocations. So oldpty swaps
  94. its uid and euid around each fork.
  95.  
  96. This introduces its own set of problems. First, the moment a setuid
  97. program does setreuid(geteuid(),getuid()), it opens itself up to ptraces
  98. by the (original) real uid. Then all security is lost. Second, this
  99. swapping is utterly pointless on systems with a sane MAXUPRC based on
  100. real uids. Finally, I haven't seen anyone else even considering this
  101. issue, let alone implementing workarounds.
  102.  
  103. So once again I've joined the crowd. newpty pretends that process limits
  104. don't exist. If it fails miserably, or your system crashes, just because
  105. too many users run setuid programs at once, blame an OS design decision
  106. as senseless as the lack of per-descriptor non-blocking I/O.
  107.  
  108. 5. The x* utilities and -xS are gone because it was easier in practice
  109. for unprivileged users to install their own copies of pty rather than
  110. use the system copy in some weird mode.
  111.  
  112. 10. With the default settings, oldpty would detect when someone else had
  113. the tty open. (Essentially the same test appeared several months later
  114. in a ``critical'' telnetd/rlogind security patch from Sun.) There were
  115. two problems: first, in a common case, pty would end up dying instead
  116. of simply trying another tty; second, the test can be defeated without
  117. too much trouble (though after these years I'm not sure there are more
  118. than a few dozen people in the world who know how to exploit this).
  119.  
  120. pty 4.0 uses a much more reliable test---it's now more secure than the
  121. tests used by Sun, Convex, DEC, and several other vendors. See the
  122. SECURITY file for further details.
  123.  
  124. 11. Internally, pty 4.0 now uses my signal-schedule (aka non-preemptive
  125. threads) library for multitasking. This makes the master much, much
  126. easier to understand, stops certain race conditions, and removes any
  127. need for explicit variable locks (like flagqwinch in oldpty).
  128.  
  129. 12. oldpty's pseudo-random tty searching started from a random spot, but
  130. searched in a fixed order from that spot. This left it open to secondary
  131. clustering. In newpty I added (in effect) a secondary hash function, and
  132. since tertiary clustering simply doesn't happen in practice, this
  133. problem should be gone.
  134.  
  135. 13. newpty supports the session and session-connection logs described in
  136. my pty paper. I fervently hope that these replace utmp and wtmp, if only
  137. because they have enough space to store full host information!
  138.  
  139. 14. In oldpty, the master process would create a communications file
  140. only while it was disconnected, then remove the file when it was
  141. reconnected. newpty maintains the communications file all the time.
  142. This eliminates some deep races and lets the master maintain certain
  143. information instead of storing it in a file for other processes to read.
  144.  
  145. 15. The roles of the master and signaller are now much more clearly
  146. separated. The master does not know whether the signaller is detached,
  147. or is manipulating a tty, or supports job control. The master does not
  148. attempt to associate itself with the signaller's tty on reconnect.
  149. Instead it always remains associated with the slave's tty.
  150.  
  151. 16. In oldpty, pty -d (detached) combined two functions. One had to do
  152. with the (obsolete) kernel concept of a controlling tty. The other told
  153. pty that it was starting under a tty and should pay attention to that
  154. tty's modes in constructing modes for the pseudo-tty. In newpty, -d
  155. controls only the second function. pty will automatically handle the
  156. kernel's controlling ttys correctly in all situations.
  157.  
  158. 17. newpty now treats true EOF on input as (1) a disconnect, if it's a
  159. session; (2) forcing -R, so that it won't read further input, if it's
  160. not a session. This is a really tricky issue---ever since UNIX supported
  161. ttys it's had two different concepts of EOF, and every program that
  162. handles ttys has to deal with both. If you have any better suggestions,
  163. let me know.
  164.