<html> <head> <title>Postfix Overview - Security</title> </head> <body> <h1><a href="big-picture.html"><img src="small-picture.gif" width="115" height="45"></a> Postfix Overview - Security</h1> <hr> <a href="index.html">Up one level</a> | <a href="motivation.html">Introduction</a> | <a href="goals.html">Goals and features</a> | <a href="architecture.html">Global architecture</a> | <a href="queuing.html">Queue Management</a> | Security <h2>Introduction</h2> By definition, mail software processes information from potentially untrusted sources. Therefore, mail software must be written with great care, even when it runs with user privileges, and even when it does not talk directly to a network. <p> Postfix is a complex system. The initial release has about 30,000 lines of code (after deleting the comments). With a system that complex, the security of the system should not depend on a single mechanism. If it did, one single error would be sufficient to compromise the entire mail system. Therefore, Postfix uses multiple layers of defense to control the damage from software and other errors. <h2>Least privilege</h2> Most Postfix daemon programs can be run at fixed low privilege in a chrooted environment. This is especially true for the programs that are exposed to the network: the SMTP server and SMTP client. Although chroot(2), even when combined with low privilege, is no guarantee against system compromise it does add a considerable hurdle. And we all know that every little bit helps. <h2>Insulation</h2> Postfix uses separate processes to insulate activities from each other. In particular, there is no direct path from the network to the security-sensitive local delivery programs. An intruder first has to break through multiple programs. Some parts of the Postfix system are multi-threaded. However, all programs that interact with the outside world are single-threaded. Separate processes give better insulation than multiple threads within a shared address space. <h2>Controlled environment</h2> No Postfix mail delivery program runs under control of a user process. Instead, most Postfix programs run under control of a resident master daemon that runs in a controlled environment, without any parent-child relationship to user processes. This approach eliminates exploits that involve signals, open files, environment variables, and other process attributes that the UNIX system passes on from a possibly-malicious parent to a child. <h2>Set-uid</h2> No Postfix program is <b>set-uid</b>. Introducing the concept was the biggest mistake made in UNIX history. <b>Set-uid</b> (and its weaker cousin, <b>set-gid</b>) causes more trouble than it is worth. Each time a new feature is added to the UNIX system, <b>set-uid</b> causes a security problem: shared libraries, the <b>/proc</b> file system, multi-language support, to mention just a few examples. <b>Set-uid</b> makes it impossible to introduce some of the features that make UNIX successors such as plan9 so attractive, for example, per-process file system name spaces. <p> Initially, the <b>maildrop</b> queue directory was world-writable, so that local processes could submit mail without assistance from a set-uid or set-gid command or from a mail daemon process. The maildrop directory was not used for mail coming in via the network, and its queue files were not readable for unprivileged users. <p> A writable directory opens up opportunities for annoyance: a local user can make hard links to someone else's maildrop files so they don't go away and/or are delivered multiple times; a local user can fill the maildrop directory with garbage and try to make the mail system crash; and a local user can hard link someone else's files into the maildrop directory and try to have them delivered as mail. However, Postfix queue files have a specific format; less than one in 10^12 non-Postfix files would be recognized as a valid Postfix queue file. <p> Because of the potential for misbehavior, Postfix has abandoned the world-writable <b>maildrop</b> directory, and uses a small set-gid <b>postdrop</b> helper program for mail submission. <h2>Trust</h2> As mentioned elsewhere in the overview, Postfix programs do not trust the contents of queue files or of the Postfix internal IPC messages. Queue files have no on-disk record for deliveries to sensitive destinations such as files or commands. Instead, programs such as the local delivery agent attempt to make security-sensitive decisions on the basis of first-hand information. <p> Of course, Postfix programs do not trust data received from the network, either. In particular, Postfix filters sender-provided data before exporting it via environment variables. If there is one lesson that people have learned from Web site security disasters it is this one: <i> don't let any data from the network near a shell</i>. Filtering is the best we can do. <h2>Large inputs</h2> <ul> <li>Memory for strings and buffers is allocated dynamically, in order to prevent buffer overrun problems. <p> <li>Long lines in message input are broken up into sequences of reasonably-sized chunks, and are reconstructed upon delivery. <p> <li>Diagnostics are truncated (in one single place!) before they are passed to the syslog(3) interface, in order to prevent buffer overruns on older platforms. However, no general attempt is made to truncate data before it is passed to system calls or to library routines. On some platforms, the software may still exhibit buffer overrun problems, due to vulnerabilities in the underlying software. <p> <li>No specific attempt is made to defend against unreasonably-long command-line arguments. UNIX kernels impose their own limits, which should be sufficient to deal with runaway programs or with malicious users. </ul> <h2>Other defenses</h2> <ul> <li>The number of in-memory instances of any object type is limited, to prevent the mail system from becoming wedged under heavy load. <p> <li>In case of problems, the software pauses before sending an error response to a client, before terminating with a fatal error, or before attempting to restart a failed program. The purpose is to prevent runaway conditions that only make problems worse. </ul> <hr> <a href="index.html">Up one level</a> | <a href="motivation.html">Introduction</a> | <a href="goals.html">Goals and features</a> | <a href="architecture.html">Global architecture</a> | <a href="queuing.html">Queue Management</a> | Security </body> </html>