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