Dale Hagglund ist genau richtig. Also werde ich nur dasselbe sagen, aber auf andere Weise, mit einigen Einzelheiten und Beispielen. ☺
Das Richtige in der Unix- und Linux-Welt ist:
- ein kleines, einfaches, leicht überprüfbares Programm zu haben, das als Superuser ausgeführt wird und den Listening-Socket bindet;
- ein weiteres kleines, einfaches, leicht zu überprüfendes Programm zu haben, das Privilegien fallen lässt, die vom ersten Programm erzeugt wurden;
- Damit der Service in einem separaten dritten Programm ausgeführt werden kann, muss er unter einem Nicht-Superuser-Konto ausgeführt und vom zweiten Programm geladen werden, wobei erwartet wird, dass ein offener Dateideskriptor für den Socket geerbt wird.
Sie haben die falsche Vorstellung, wo das hohe Risiko liegt. Das hohe Risiko besteht darin , aus dem Netzwerk zu lesen und auf das zu reagieren, was gelesen wird, und nicht darin, einen Socket zu öffnen, ihn an einen Port zu binden und anzurufen listen()
. Es ist der Teil eines Dienstes, der die eigentliche Kommunikation durchführt, der das hohe Risiko darstellt. Die Teile, die sich öffnen, bind()
und listen()
(bis zu einem gewissen Grad) der Teil , der sich öffnet, accepts()
sind nicht das hohe Risiko und können unter der Ägide des Super-Benutzers ausgeführt werden. Sie verwenden und verarbeiten keine accept()
Daten (mit Ausnahme der Quell-IP-Adressen in diesem Fall), die der Kontrolle nicht vertrauenswürdiger Fremder über das Netzwerk unterliegen.
Dafür gibt es viele Möglichkeiten.
inetd
Wie Dale Hagglund sagt, macht das der alte "Netzwerk-Superserver" inetd
. Das Konto, unter dem der Serviceprozess ausgeführt wird, ist eine der Spalten in inetd.conf
. Es trennt den Listening-Teil und den Drop-Privileg-Teil nicht in zwei separate Programme, die klein und leicht zu überwachen sind, sondern trennt den Hauptdienstcode in ein separates Programm, das exec()
in einem Dienstprozess erstellt wird, der mit einem offenen Dateideskriptor erstellt wird für die Steckdose.
Die Schwierigkeit der Prüfung ist nicht so problematisch, da nur das eine Programm geprüft werden muss. inetd
Das Hauptproblem ist nicht die Überwachung, sondern, dass es im Vergleich zu neueren Tools keine einfache, fein abgestimmte Laufzeitdienststeuerung bietet.
UCSPI-TCP und Daemontools
Daniel J. Bernsteins UCSPI-TCP- und daemontools- Pakete wurden dafür zusammen entwickelt. Alternativ kann Bruce Guenters weitgehend gleichwertiges daemontools-encore- Toolset verwendet werden.
Das Programm zum Öffnen des Socket-Dateideskriptors und zum Binden an den privilegierten lokalen Port wird tcpserver
über UCSPI-TCP ausgeführt. Es macht sowohl die listen()
als auch die accept()
.
tcpserver
Anschließend wird entweder ein Dienstprogramm erstellt, das die Root-Berechtigungen selbst löscht (da das bereitgestellte Protokoll darin besteht, als Superuser zu beginnen und sich dann "anzumelden", wie dies beispielsweise bei einem FTP- oder einem SSH-Dämon der Fall ist) oder setuidgid
a in sich geschlossenes kleines und leicht zu überprüfendes Programm, das nur Berechtigungen verwirft und dann das eigentliche Dienstprogramm lädt (von dem also kein Teil jemals mit Superuser-Berechtigungen ausgeführt wird, wie dies beispielsweise der Fall ist qmail-smtpd
).
Ein Service- run
Skript wäre also zum Beispiel (dieses für dummyidentd zur Bereitstellung eines Null-IDENT-Dienstes):
#!/bin/sh -e
exec 2>&1
exec \
tcpserver 0 113 \
setuidgid nobody \
dummyidentd.pl
Leckereien
Mein nosh-Paket wurde dafür entwickelt. Es hat einen kleinen setuidgid
Nutzen, genau wie die anderen. Ein systemd
kleiner Unterschied besteht darin, dass es sowohl mit "LISTEN_FDS" -Diensten als auch mit UCSPI-TCP-Diensten verwendet werden kann. Daher wird das herkömmliche tcpserver
Programm durch zwei separate Programme ersetzt: tcp-socket-listen
und tcp-socket-accept
.
Auch hier spawnen und laden sich die Mehrzweck-Dienstprogramme gegenseitig. Eine interessante Besonderheit des Designs ist, dass man Superuser-Privilegien nach, listen()
aber schon vor, fallen lassen kann accept()
. Hier ist ein run
Skript qmail-smtpd
, das genau das tut:
#!/bin/nosh
fdmove -c 2 1
clearenv --keep-path --keep-locale
envdir env/
softlimit -m 70000000
tcp-socket-listen --combine4and6 --backlog 2 ::0 smtp
setuidgid qmaild
sh -c 'exec \
tcp-socket-accept -v -l "${LOCAL:-0}" -c "${MAXSMTPD:-1}" \
ucspi-socket-rules-check \
qmail-smtpd \
'
Die Programme , die unter der Schirmherrschaft der Superuser sind die kleinen Service-agnostisch Kettenlade Tools fdmove
, clearenv
, envdir
, softlimit
, tcp-socket-listen
, und setuidgid
. Ab dem Startpunkt sh
ist der Socket geöffnet und an den smtp
Port gebunden , und der Prozess verfügt nicht mehr über Superuser-Berechtigungen.
s6, s6-networking und execline
Die s6- und s6-Netzwerkpakete von Laurent Bercot wurden dazu in Verbindung entwickelt. Die Befehle sind strukturell denen von daemontools
und UCSPI-TCP sehr ähnlich .
run
Skripte wären ähnlich, mit Ausnahme der Substitution von s6-tcpserver
for tcpserver
und s6-setuidgid
for setuidgid
. Man kann sich jedoch auch dafür entscheiden, gleichzeitig das Execline- Toolset von M. Bercot zu verwenden .
Hier ist ein Beispiel eines FTP-Dienstes, der geringfügig von Wayne Marshalls Original geändert wurde und Execline, S6, S6-Networking und das FTP-Server-Programm von publicfile verwendet :
#!/command/execlineb -PW
multisubstitute {
define CONLIMIT 41
define FTP_ARCHIVE "/var/public/ftp"
}
fdmove -c 2 1
s6-envuidgid pubftp
s6-softlimit -o25 -d250000
s6-tcpserver -vDRH -l0 -b50 -c ${CONLIMIT} -B '220 Features: a p .' 0 21
ftpd ${FTP_ARCHIVE}
ipsvd
Gerrit Papes ipsvd ist ein weiteres Toolset, das mit ucspi-tcp und s6-networking vergleichbar ist. Die Tools sind chpst
und tcpsvd
dieses Mal, aber sie tun dasselbe, und der Code mit hohem Risiko, der das Lesen, Verarbeiten und Schreiben von Dingen übernimmt, die von nicht vertrauenswürdigen Clients über das Netzwerk gesendet werden, befindet sich immer noch in einem separaten Programm.
Hier ist das Beispiel von M. Pape, wie man fnord
ein run
Skript ausführt:
#!/bin/sh
exec 2>&1
cd /public/10.0.5.4
exec \
chpst -m300000 -Uwwwuser \
tcpsvd -v 10.0.5.4 443 sslio -v -unobody -//etc/fnord/jail -C./cert.pem \
fnord
systemd
systemd
Das neue Dienstüberwachungs- und Init-System, das in einigen Linux-Distributionen zu finden ist, soll das tun, was es inetd
kann . Es werden jedoch keine kleinen eigenständigen Programme verwendet. Man muss systemd
leider in vollem Umfang prüfen .
Mit systemd
erstellt man Konfigurationsdateien, um einen Socket zu definieren, der systemd
lauscht, und einen Dienst, der systemd
startet. Die Service "Unit" -Datei enthält Einstellungen, mit denen Sie den Serviceprozess in hohem Maße steuern können, einschließlich des Benutzers, unter dem er ausgeführt wird.
Wenn dieser Benutzer als Nicht-Superuser festgelegt ist, systemd
erledigt er die gesamte Arbeit, indem er den Socket öffnet, an einen Port bindet listen()
und accept()
in Prozess 1 den Superuser und den zugehörigen Dienstprozess aufruft (und, falls erforderlich, aufruft ) Spawns werden ohne Superuser-Rechte ausgeführt.