| 1 | Background: Every few months CERT announces Yet Another Security Hole In |
| 2 | Sendmail---something that lets local or even remote users take complete |
| 3 | control of the machine. I'm sure there are many more holes waiting to be |
| 4 | discovered; sendmail's design means that any minor bug in 46000 lines of |
| 5 | code is a major security risk. Other popular mailers, such as Smail, and |
| 6 | even mailing-list managers, such as Majordomo, seem nearly as bad. |
| 7 | |
| 8 | Note added in 1998: I wrote the above paragraph in December 1995, when |
| 9 | the latest version of sendmail was 8.6.12 (with 41000 lines of code). |
| 10 | Fourteen security holes were discovered from sendmail 8.6.12 through |
| 11 | 8.8.5. See http://pobox.com/~djb/docs/maildisasters/sendmail.html. |
| 12 | |
| 13 | I started working on qmail because I was sick of this cycle of doom. |
| 14 | Here are some of the things I did to make sure that qmail will never let |
| 15 | an intruder into your machine. |
| 16 | |
| 17 | |
| 18 | 1. Programs and files are not addresses. Don't treat them as addresses. |
| 19 | |
| 20 | sendmail treats programs and files as addresses. Obviously random people |
| 21 | can't be allowed to execute arbitrary programs or write to arbitrary |
| 22 | files, so sendmail goes through horrendous contortions trying to keep |
| 23 | track of whether a local user was ``responsible'' for an address. This |
| 24 | has proven to be an unmitigated disaster. |
| 25 | |
| 26 | In qmail, programs and files are not addresses. The local delivery |
| 27 | agent, qmail-local, can run programs or write to files as directed by |
| 28 | ~user/.qmail, but it's always running as that user. (The notion of |
| 29 | ``user'' is configurable, but root is never a user. To prevent silly |
| 30 | mistakes, qmail-local makes sure that neither ~user nor ~user/.qmail is |
| 31 | group-writable or world-writable.) |
| 32 | |
| 33 | Security impact: .qmail, like .cshrc and .exrc and various other files, |
| 34 | means that anyone who can write arbitrary files as a user can execute |
| 35 | arbitrary programs as that user. That's it. |
| 36 | |
| 37 | |
| 38 | 2. Do as little as possible in setuid programs. |
| 39 | |
| 40 | A setuid program must operate in a very dangerous environment: a user is |
| 41 | under complete control of its fds, args, environ, cwd, tty, rlimits, |
| 42 | timers, signals, and more. Even worse, the list of controlled items |
| 43 | varies from one vendor's UNIX to the next, so it is very difficult to |
| 44 | write portable code that cleans up everything. |
| 45 | |
| 46 | Of the twenty most recent sendmail security holes, eleven worked only |
| 47 | because the entire sendmail system is setuid. |
| 48 | |
| 49 | Only one qmail program is setuid: qmail-queue. Its only purpose is to |
| 50 | add a new mail message to the outgoing queue. |
| 51 | |
| 52 | |
| 53 | 3. Do as little as possible as root. |
| 54 | |
| 55 | The entire sendmail system runs as root, so there's no way that its |
| 56 | mistakes can be caught by the operating system's built-in protections. |
| 57 | In contrast, only two qmail programs, qmail-start and qmail-lspawn, |
| 58 | run as root. |
| 59 | |
| 60 | |
| 61 | 4. Move separate functions into mutually untrusting programs. |
| 62 | |
| 63 | Five of the qmail programs---qmail-smtpd, qmail-send, qmail-rspawn, |
| 64 | qmail-remote, and tcp-env---are not security-critical. Even if all of |
| 65 | these programs are completely compromised, so that an intruder has |
| 66 | control over the qmaild, qmails, and qmailr accounts and the mail queue, |
| 67 | he still can't take over your system. None of the other programs trust |
| 68 | the results from these five. |
| 69 | |
| 70 | In fact, these programs don't even trust each other. They are in three |
| 71 | groups: tcp-env and qmail-smtpd, which run as qmaild; qmail-rspawn and |
| 72 | qmail-remote, which run as qmailr; and qmail-send, the queue manager, |
| 73 | which runs as qmails. Each group is immune from attacks by the others. |
| 74 | |
| 75 | (From root's point of view, as long as root doesn't send any mail, only |
| 76 | qmail-start and qmail-lspawn are security-critical. They don't write any |
| 77 | files or start any other programs as root.) |
| 78 | |
| 79 | |
| 80 | 5. Don't parse. |
| 81 | |
| 82 | I have discovered that there are two types of command interfaces in the |
| 83 | world of computing: good interfaces and user interfaces. |
| 84 | |
| 85 | The essence of user interfaces is _parsing_---converting an unstructured |
| 86 | sequence of commands, in a format usually determined more by psychology |
| 87 | than by solid engineering, into structured data. |
| 88 | |
| 89 | When another programmer wants to talk to a user interface, he has to |
| 90 | _quote_: convert his structured data into an unstructured sequence of |
| 91 | commands that the parser will, he hopes, convert back into the original |
| 92 | structured data. |
| 93 | |
| 94 | This situation is a recipe for disaster. The parser often has bugs: it |
| 95 | fails to handle some inputs according to the documented interface. The |
| 96 | quoter often has bugs: it produces outputs that do not have the right |
| 97 | meaning. Only on rare joyous occasions does it happen that the parser |
| 98 | and the quoter both misinterpret the interface in the same way. |
| 99 | |
| 100 | When the original data is controlled by a malicious user, many of these |
| 101 | bugs translate into security holes. Some examples: the Linux login |
| 102 | -froot security hole; the classic find | xargs rm security hole; the |
| 103 | Majordomo injection security hole. Even a simple parser like getopt is |
| 104 | complicated enough for people to screw up the quoting. |
| 105 | |
| 106 | In qmail, all the internal file structures are incredibly simple: text0 |
| 107 | lines beginning with single-character commands. (text0 format means that |
| 108 | lines are separated by a 0 byte instead of line feed.) The program-level |
| 109 | interfaces don't take options. |
| 110 | |
| 111 | All the complexity of parsing RFC 822 address lists and rewriting |
| 112 | headers is in the qmail-inject program, which runs without privileges |
| 113 | and is essentially part of the UA. |
| 114 | |
| 115 | |
| 116 | 6. Keep it simple, stupid. |
| 117 | |
| 118 | See BLURB for some of the reasons that qmail is so much smaller than |
| 119 | sendmail. There's nothing inherently complicated about writing a mailer. |
| 120 | (Except RFC 822 support; but that's only in qmail-inject.) Security |
| 121 | holes can't show up in features that don't exist. |
| 122 | |
| 123 | |
| 124 | 7. Write bug-free code. |
| 125 | |
| 126 | I've mostly given up on the standard C library. Many of its facilities, |
| 127 | particularly stdio, seem designed to encourage bugs. A big chunk of |
| 128 | qmail is stolen from a basic C library that I've been developing for |
| 129 | several years for a variety of applications. The stralloc concept and |
| 130 | getln() make it very easy to avoid buffer overruns, memory leaks, and |
| 131 | artificial line length limits. |