Postfix NoNewPrivileges support


Introduction

This document describes how Postfix uses set-gid privilege elevation to gate access from an unprivileged process to the Postfix queue and to core daemon processes. It then presents an alternative privilege elevation mechanism for systems that disable set-gid privilege elevation.

This guide assumes that Postfix uses the default settings: "mail_owner = postfix" and "setgid_group = postdrop".

Postfix user request architecture

Historically, a user request travels through three security zones on its way to a Postfix core daemon process:

Architectural properties with set-gid privilege elevation

The setgid-based, three-zone, architecture has several key benefits. These will need to be preserved on systems that don't support set-gid privileges:

Alternative privilege elevation with postlift(8)

Some systems disable set-gid privilege elevation, for example using "NoNewPrivileges=yes" or the "nosuid" file system mount option. On these systems, Postfix may use an alternative privilege elevation method that is implemented with the postlift(8) service, changing the architecture as shown below. As of Postfix 3.12, this alternative method is supported only on Linux environments using systemd.

Zone 1
user UID
user GID
Zone 2
"postdrop" UID
"postdrop" GID
Zone 3
"postfix" UID
"postfix" GID
mail(1)
mailx(1)
sendmail(1)
mailq(1)
-> postdrop(1)
postlog(1)
postqueue(1)
-> postlift(8) -> postdrop(1)
postlog(1)
postqueue(1)
-> pickup(8)
postlogd(8)
qmgr(8)
flush(8)
showq(8)

When set-gid privileges are disabled, a postdrop(1), postlog(1), or postqueue(1) client process with Zone 1 privileges will connect to the Zone 2 postlift(8) service, requesting that postlift(8) runs the same command (postdrop(1) etc.) in a process with Zone 2 privileges. This allows the elevated process to add a message to the protected maildrop queue, or to interact with a Zone 3 core daemon process. postlift(8) propagates the exit status from the elevated process back to the Zone 1 client process.

The super-user ("root") is excluded from postlift(8) privilege elevation. Because root already has sufficient privileges, its Zone 1 postdrop(1), postlog(1), or postqueue(1) processes can directly access the maildrop queue or a Zone 3 process. This eliminates a postlift(8) start-up dependency and avoids some implementation complexity.

Architectural properties with postlift(8) privilege elevation

The architecture above can provide most of the benefits from the architecture based on set-gid privilege elevation:

Systemd integration

To run postlift(8) under systemd, follow the steeps below:

Future work: spawn(8) integration

On systems without systemd, partial functionality can be implemented using the Postfix spawn(8) service. This service accepts connections on a private or public (but still protected) socket, and executes a configured program with specific privileges. However, making this work with postlift(8) requires two additional Postfix features:

A down-side is that spawn(8) daemons remain unavailable until Postfix starts. Consequently, Zone 1 email submissions from non-root processes will fail to enter the queue before Postfix is running. Because Postfix typically launches with a "network" or "multi-user" start-up target, early boot-time email messages from non-root users may be dropped.

Credits