Commit | Line | Data |
---|---|---|
2117e02e MW |
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 | ||
212b6f5d MW |
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 | ||
2117e02e MW |
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 | ||
212b6f5d | 46 | Of the twenty most recent sendmail security holes, eleven worked only |
2117e02e MW |
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 | |
212b6f5d | 103 | Majordomo injection security hole. Even a simple parser like getopt is |
2117e02e MW |
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 | ||
2117e02e MW |
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 | |
212b6f5d MW |
130 | getln() make it very easy to avoid buffer overruns, memory leaks, and |
131 | artificial line length limits. |