Dale Hagglund est sur place. Je vais donc simplement dire la même chose, mais d'une manière différente, avec des détails et des exemples. ☺
La bonne chose à faire dans les mondes Unix et Linux est la suivante:
- avoir un petit programme simple, facilement vérifiable, qui fonctionne en tant que superutilisateur et lie le socket en écoute;
- avoir un autre petit programme simple, facilement vérifiable, qui supprime les privilèges créés par le premier programme;
- d'avoir la viande du service, dans un séparé troisième programme, exécuté sous un compte non superutilisateur et une chaîne chargée par le second programme, dans l’espoir d’hériter simplement d’un descripteur de fichier ouvert pour le socket.
Vous avez une mauvaise idée de l'endroit où le risque est élevé. Le risque élevé est en lire sur le réseau et agir sur ce qui est lu pas dans les simples gestes d'ouvrir un socket, de le lier à un port et d'appeler listen()
. C'est la partie d'un service qui fait la communication réelle qui est le risque élevé. Les parties qui s'ouvrent, bind()
, et listen()
et même (dans une certaine mesure) la partie accepts()
, ne sont pas à haut risque et peuvent être exécutés sous l’égide du superutilisateur. Ils n'utilisent pas et n'agissent pas (à l'exception des adresses IP source dans le accept()
cas) des données sous le contrôle d’étrangers non fiables sur le réseau.
Il y a plusieurs façons de le faire.
inetd
Comme le dit Dale Hagglund, l'ancien "super serveur" inetd
est ce que ca. Le compte sous lequel le processus de service est exécuté est l’une des colonnes de inetd.conf
. Il ne sépare pas la partie écoute et la partie suppression des privilèges en deux programmes distincts, petits et faciles à auditer, mais il sépare le code de service principal en un programme séparé. exec()
ed dans un processus de service qu’il génère avec un descripteur de fichier ouvert pour le socket.
La difficulté de l'audit n'est pas un problème, il suffit de vérifier le programme en question. inetd
Le principal problème de l'audit n'est pas tant l'audit, mais plutôt le fait qu'il ne fournit pas un contrôle de service d'exécution à granularité fine, comparé aux outils plus récents.
UCSPI-TCP et daemontools
De Daniel J. Bernstein UCSPI-TCP et Daemon Tools les paquets ont été conçus pour le faire en conjonction. On peut également utiliser l'équivalent de Bruce Guenter daemontools-encore ensemble d'outils.
Le programme pour ouvrir le descripteur de fichier de socket et le lier au port local privilégié est tcpserver
, de UCSPI-TCP. Il fait les deux listen()
et le accept()
.
tcpserver
puis génère un programme de service qui supprime lui-même les privilèges root (car le protocole utilisé implique de démarrer en tant que superutilisateur puis de se "connecter", comme dans le cas, par exemple, d'un démon FTP ou SSH) ou setuidgid
qui est un petit programme autonome facilement vérifiable qui abandonne uniquement les privilèges, puis enchaîne les charges vers le programme de service proprement dit (aucune partie de celui-ci ne s'exécute donc avec des privilèges de superutilisateur, comme c'est le cas avec, par exemple, qmail-smtpd
).
Un service run
script serait donc par exemple (celui-ci pour dummyidentd pour fournir un service nul IDENT):
#!/bin/sh -e
exec 2>&1
exec \
tcpserver 0 113 \
setuidgid nobody \
dummyidentd.pl
bouffe
Mon paquet est conçu pour le faire. Il a un petit setuidgid
utilité, tout comme les autres. Une légère différence est qu’il est utilisable avec systemd
style "LISTEN_FDS" ainsi qu’avec les services UCSPI-TCP, donc le traditionnel tcpserver
programme est remplacé par deux programmes distincts: tcp-socket-listen
et tcp-socket-accept
.
Encore une fois, les utilitaires à but unique apparaissent et se chargent en chaîne. Une particularité intéressante de la conception est que l'on peut supprimer les privilèges de superutilisateur après listen()
mais avant même accept()
. Voici un run
script pour qmail-smtpd
cela fait en effet exactement cela:
#!/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 \
'
Les programmes exécutés sous l’égide du superutilisateur sont les petits outils de chargement en chaîne indépendants du service. fdmove
, clearenv
, envdir
, softlimit
, tcp-socket-listen
, et setuidgid
. Au point que sh
est démarré, le socket est ouvert et lié au smtp
port, et le processus ne dispose plus des privilèges de superutilisateur.
s6, s6-networking et execline
De Laurent Bercot s6 et s6-mise en réseau les paquets ont été conçus pour le faire en conjonction. Les commandes sont structurellement très similaires à celles de daemontools
et UCSPI-TCP.
run
scripts seraient sensiblement les mêmes, sauf pour la substitution de s6-tcpserver
pour tcpserver
et s6-setuidgid
pour setuidgid
. Cependant, on pourrait aussi choisir de faire usage de la méthode de M. Bercot. execline ensemble d'outils en même temps.
Voici un exemple de service FTP légèrement modifié à partir de L'original de Wayne Marshall , qui utilise execline, s6, s6-networking et le programme de serveur FTP de publicfile :
#!/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 Pape ipsvd C’est un autre ensemble d’outils qui va dans le même sens que ucspi-tcp et s6-networking. Les outils sont chpst
et tcpsvd
cette fois-ci, mais ils font la même chose, et le code à haut risque qui lit, traite et écrit les choses envoyées sur le réseau par des clients non fiables fait toujours l’objet d’un programme séparé.
Voici L'exemple de M. Pape de courir fnord
dans un run
scénario:
#!/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
, le nouveau système de supervision de service et init que l'on retrouve dans certaines distributions Linux est destiné à faire quoi inetd
peut faire . Cependant, il n’utilise pas une suite de petits programmes autonomes. Il faut auditer systemd
dans son intégralité, malheureusement.
Avec systemd
on crée des fichiers de configuration pour définir un socket qui systemd
écoute, et un service qui systemd
départs. Le fichier "unité" de service contient des paramètres qui permettent de contrôler le processus de service, y compris son utilisateur.
Avec cet utilisateur défini pour être un non-superutilisateur, systemd
effectue tout le travail consistant à ouvrir le socket, à le lier à un port et à appeler listen()
(et, si nécessaire, accept()
) dans le processus n ° 1 en tant que superutilisateur, et le processus de service qu'il génère est exécuté sans privilèges de superutilisateur.