Je travaille actuellement sur un projet où j'ai un processus parent qui configure un socketpair, des fourches et utilise ensuite ce socketpair pour communiquer. L'enfant, s'il veut ouvrir un fichier (ou toute autre ressource basée sur un descripteur de fichier) doit toujours aller vers le parent, demander la ressource et obtenir l' fd
envoi via le socketpair. De plus, je veux empêcher l'enfant d'ouvrir un descripteur de fichier par lui-même.
Je suis tombé sur setrlimit
ce qui empêche avec succès l'enfant d'ouvrir de nouveaux descripteurs de fichiers, mais cela semble également invalider tous les descripteurs de fichiers envoyés via la connexion socket initiale. Existe-t-il une méthode sous Linux qui permet à un seul processus d'ouvrir un fichier, d'envoyer son descripteur de fichier à d'autres processus et de les laisser les utiliser sans autoriser ces autres processus à ouvrir eux-mêmes un descripteur de fichier?
Pour mon cas d'utilisation, cela peut être n'importe quelle configuration de noyau, appel système, etc. tant qu'il peut être appliqué après fork et tant qu'il s'applique à tous les descripteurs de fichiers (pas seulement les fichiers mais aussi les sockets, les paires de sockets, etc.).
la source
Réponses:
Ce que vous avez ici est exactement le cas d'utilisation de seccomp .
En utilisant seccomp, vous pouvez filtrer les appels système de différentes manières. Ce que vous voulez faire dans cette situation, c'est, juste après
fork()
, installer unseccomp
filtre qui interdit l'utilisation deopen(2)
,openat(2)
,socket(2)
(et plus). Pour ce faire, vous pouvez effectuer les opérations suivantes:seccomp_init(3)
le comportement par défaut deSCMP_ACT_ALLOW
.seccomp_rule_add(3)
pour chaque appel système que vous souhaitez refuser. Vous pouvez utiliserSCMP_ACT_KILL
pour arrêter le processus en cas de tentative d'appel système,SCMP_ACT_ERRNO(val)
pour empêcher l'échec de l'appel système de renvoyer le paramètre spécifié.errno
valeur ou toute autreaction
valeur définie dans la page de manuel.seccomp_load(3)
pour le rendre efficace.Avant de continuer, NOTEZ qu'une approche de liste noire comme celle-ci est en général plus faible qu'une approche de liste blanche. Il autorise tout appel système qui n'est pas explicitement interdit, et pourrait entraîner un contournement du filtre . Si vous pensez que le processus enfant que vous souhaitez exécuter pourrait essayer de manière malveillante d'éviter le filtre, ou si vous savez déjà quels appels système seront nécessaires aux enfants, une approche de liste blanche est meilleure et vous devez faire le contraire de ce qui précède: créer un filtre avec l'action par défaut de
SCMP_ACT_KILL
et autoriser les appels système nécessaires avecSCMP_ACT_ALLOW
. En termes de code, la différence est minime (la liste blanche est probablement plus longue, mais les étapes sont les mêmes).Voici un exemple de ce qui précède (je fais
exit(-1)
en cas d'erreur juste pour des raisons de simplicité):Maintenant, dans votre programme, vous pouvez appeler la fonction ci-dessus pour appliquer le filtre seccomp juste après
fork()
, comme ceci:Quelques notes importantes sur seccomp:
fork(2)
ouclone(2)
sont autorisés par le filtre, tout processus enfant sera contraint par le même filtre.execve(2)
est autorisé, le filtre existant sera conservé lors d'un appel àexecve(2)
.prctl(2)
appel système est autorisé, le processus peut appliquer d'autres filtres.la source
socket(2)
peut aussi créer unfd
, donc ça devrait être bloqué aussi. Si vous connaissez le processus enfant, une approche de liste blanche est meilleure.creat()
,dup()
etdup2()
sont tous les appels système Linux que les descripteurs de fichier de retour. Il y a beaucoup de façons de contourner une liste noire ...