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 | ||
8 | I started working on qmail because I was sick of this cycle of doom. | |
9 | Here are some of the things I did to make sure that qmail will never let | |
10 | an intruder into your machine. | |
11 | ||
12 | ||
13 | 1. Programs and files are not addresses. Don't treat them as addresses. | |
14 | ||
15 | sendmail treats programs and files as addresses. Obviously random people | |
16 | can't be allowed to execute arbitrary programs or write to arbitrary | |
17 | files, so sendmail goes through horrendous contortions trying to keep | |
18 | track of whether a local user was ``responsible'' for an address. This | |
19 | has proven to be an unmitigated disaster. | |
20 | ||
21 | In qmail, programs and files are not addresses. The local delivery | |
22 | agent, qmail-local, can run programs or write to files as directed by | |
23 | ~user/.qmail, but it's always running as that user. (The notion of | |
24 | ``user'' is configurable, but root is never a user. To prevent silly | |
25 | mistakes, qmail-local makes sure that neither ~user nor ~user/.qmail is | |
26 | group-writable or world-writable.) | |
27 | ||
28 | Security impact: .qmail, like .cshrc and .exrc and various other files, | |
29 | means that anyone who can write arbitrary files as a user can execute | |
30 | arbitrary programs as that user. That's it. | |
31 | ||
32 | ||
33 | 2. Do as little as possible in setuid programs. | |
34 | ||
35 | A setuid program must operate in a very dangerous environment: a user is | |
36 | under complete control of its fds, args, environ, cwd, tty, rlimits, | |
37 | timers, signals, and more. Even worse, the list of controlled items | |
38 | varies from one vendor's UNIX to the next, so it is very difficult to | |
39 | write portable code that cleans up everything. | |
40 | ||
41 | Of the twelve most recent sendmail security holes, six worked only | |
42 | because the entire sendmail system is setuid. | |
43 | ||
44 | Only one qmail program is setuid: qmail-queue. Its only purpose is to | |
45 | add a new mail message to the outgoing queue. | |
46 | ||
47 | ||
48 | 3. Do as little as possible as root. | |
49 | ||
50 | The entire sendmail system runs as root, so there's no way that its | |
51 | mistakes can be caught by the operating system's built-in protections. | |
52 | In contrast, only two qmail programs, qmail-start and qmail-lspawn, | |
53 | run as root. | |
54 | ||
55 | ||
56 | 4. Move separate functions into mutually untrusting programs. | |
57 | ||
58 | Five of the qmail programs---qmail-smtpd, qmail-send, qmail-rspawn, | |
59 | qmail-remote, and tcp-env---are not security-critical. Even if all of | |
60 | these programs are completely compromised, so that an intruder has | |
61 | control over the qmaild, qmails, and qmailr accounts and the mail queue, | |
62 | he still can't take over your system. None of the other programs trust | |
63 | the results from these five. | |
64 | ||
65 | In fact, these programs don't even trust each other. They are in three | |
66 | groups: tcp-env and qmail-smtpd, which run as qmaild; qmail-rspawn and | |
67 | qmail-remote, which run as qmailr; and qmail-send, the queue manager, | |
68 | which runs as qmails. Each group is immune from attacks by the others. | |
69 | ||
70 | (From root's point of view, as long as root doesn't send any mail, only | |
71 | qmail-start and qmail-lspawn are security-critical. They don't write any | |
72 | files or start any other programs as root.) | |
73 | ||
74 | ||
75 | 5. Don't parse. | |
76 | ||
77 | I have discovered that there are two types of command interfaces in the | |
78 | world of computing: good interfaces and user interfaces. | |
79 | ||
80 | The essence of user interfaces is _parsing_---converting an unstructured | |
81 | sequence of commands, in a format usually determined more by psychology | |
82 | than by solid engineering, into structured data. | |
83 | ||
84 | When another programmer wants to talk to a user interface, he has to | |
85 | _quote_: convert his structured data into an unstructured sequence of | |
86 | commands that the parser will, he hopes, convert back into the original | |
87 | structured data. | |
88 | ||
89 | This situation is a recipe for disaster. The parser often has bugs: it | |
90 | fails to handle some inputs according to the documented interface. The | |
91 | quoter often has bugs: it produces outputs that do not have the right | |
92 | meaning. Only on rare joyous occasions does it happen that the parser | |
93 | and the quoter both misinterpret the interface in the same way. | |
94 | ||
95 | When the original data is controlled by a malicious user, many of these | |
96 | bugs translate into security holes. Some examples: the Linux login | |
97 | -froot security hole; the classic find | xargs rm security hole; the | |
98 | recent Majordomo security hole. Even a simple parser like getopt is | |
99 | complicated enough for people to screw up the quoting. | |
100 | ||
101 | In qmail, all the internal file structures are incredibly simple: text0 | |
102 | lines beginning with single-character commands. (text0 format means that | |
103 | lines are separated by a 0 byte instead of line feed.) The program-level | |
104 | interfaces don't take options. | |
105 | ||
106 | All the complexity of parsing RFC 822 address lists and rewriting | |
107 | headers is in the qmail-inject program, which runs without privileges | |
108 | and is essentially part of the UA. | |
109 | ||
110 | The only nasty case is .qmail, qmail's answer to .forward. I tried to | |
111 | make this as simple as possible, but unfortunately it still has to be | |
112 | edited by users. As a result, the qlist mailing-list-management program | |
113 | has to be careful to exclude subscriber addresses that contain newlines. | |
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 | getline2() make it very easy to avoid buffer overruns, memory leaks, | |
131 | and artificial line length limits. |