Nachdem Anfang Mai 2021 mehrere Sicherheitslücken in Exim bekannt wurden, habe ich mich daran gemacht und mit den Möglichkeit von Systemd und AppArmor den Exim-Prozess weiter eingeschränkt. Dabei ist anzumerken, dass Exim auf dem Server nur eine Durchgangsstation ist: Er nimmt E‑Mails per Netzwerk für lokale Systeme entgegen und schreibt diese als Batched-SMTP in eine Datei in /srv/mail-relay oder liefert E‑Mails an externe Systeme aus, die lokal per /usr/sbin/sendmail abgegeben werden. Daher brauche ich keine komplexe Filterung für lokale Benutzer oder andere Hilfsprozesse wie Spamfilter.

Systemd-Beschränkungen für Exim

Ausgehend von meiner Grundeinstellungen zur Härtung mit Systemd musste ich folgende Beschränkungen lockern, damit Exim funktioniert:

[Service]
# Grundeinstellungen von https://jo-so.de/2021-05/H%C3%A4rtung-Systemd.html
…

CapabilityBoundingSet=CAP_CHOWN CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH \
  CAP_FOWNER CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID
NoNewPrivileges=false
# /var muss schreibbar sein
ProtectSystem=full
RestrictAddressFamilies=AF_INET AF_INET6
SystemCallFilter=@chown @setuid

AppArmor-Profil für Exim

Für AppArmor habe ich wieder mit einem Minimalprofil im complain-Modus begonnen und mich Stück für Stück durch die audit-Meldungen vom Kernel gearbeitet und die Regeln erstellt. Wer das Profil übernimmt, sollte auch für einige Tage das Profil mit profile … flags=(complain) { nutzen, um nur zu beobachten, wo es Abweichungen gibt und es danach scharf (also in den enforce-Modus) schalten.

include <tunables/global>

profile exim4 /{usr/,}sbin/exim4 {
  include <abstractions/base>
  include <abstractions/nameservice>

  capability chown dac_override dac_read_search fowner setgid setuid,

  /run/exim4/ r,
  owner /run/exim4/exim.pid rw,

  # Config
  /etc/{aliases,email-addresses} r,
  /etc/exim4/** r,
  /var/lib/exim4/config.autogenerated{,.tmp} r,
  /etc/letsencrypt/archive/jo-so.de/privkey*.pem r,

  # Log
  /var/log/exim4/{mainlog,paniclog,rejectlog} rw,

  # Mail delivery
  /var/mail/* rwkl,
  /var/spool/exim4/ r,
  /var/spool/exim4/** rw,
  /var/spool/exim4/db/retry.lockfile k,
  /var/spool/exim4/input/* k,

  owner /srv/mail-relay/* rwkl,

  # sub-processes
  /usr/sbin/exim4 ix,
  /{,usr/}bin/{dash,uname} ix,
  /usr/bin/spfquery.mail-spf-perl ix,

  # This is used by spfquery.mail-spf-perl
  /usr/bin/spfquery.mail-spf-perl r,
  /usr/share/perl{,5}/**.pm r,
}

Da ich für Systemd die Einstellung NoNewPrivileges=true nutze, lassen sich leider keine Subprofile für die Unterprozesse verwenden; sonst kommt man die Meldung apparmor="DENIED" operation="exec" info="no new privs". Daher müssen alle entsprechenden Rechte im Hauptprofil definiert werden und die Unterprozesse dieses Profil erben; Option ix. Leider konnte ich nicht die Stelle ausfindig machen, die den Aufruf von /bin/sh -c uname verursacht, weshalb ich diesen Zugriff nur zulassen konnte.