Pourquoi le meurtre fondé sur le partage ne fonctionne-t-il que de manière fiable avec –fork?

A partir de cette réponse, nous avons appris que vous pouvez implémenter une mise à mort fiable de sous-arborescences de process entières avec des namespaces PID Linux via unshare -p .

Voici un problème avec cela que je ne comprends pas:

  • Cela ne fonctionne que lorsque j'utilise l'option -f / --fork pour annuler le partage.

     unshare -fp -- bash -c "watch /bin/sleep 10000 && echo hi" 

    Quand j'exécute ceci, et que je kill -9 le PID de ce bash , alors regarde, dors, etc. sont tous morts, comme je le désire.

  • Mais quand je l'utilise sans -f :

     unshare -p -- bash -c "watch /bin/sleep 10000 && echo hi" 

    et kill -9 le bash PID, puis la watch se reparented à PID 1 (sur mon Ubuntu qui est systemd), donc je n'ai pas l'effet désiré de tuer tous les enfants.

Des questions:

  • Pourquoi est --fork nécessaire pour get l'effet désiré? Pourquoi le unshare avec exec() sans fork n'est-il pas suffisant?
  • Y a-t-il une solution de contournement pour cela? Je préférerais que je puisse facilement envoyer kill -9 au PID créé en démarrant unshare pour tuer tout en dessous. Mais quand j'utilise --fork , --fork tue le pid returnné quand j'ai démarré le unshare , eh bien, il suffit de tuer unshare et de se unshare sur PID 1, car le unshare ne se trouve pas dans mon espace de noms PID.

Notez que le && echo hi est nécessaire car si vous ne donnez qu'une seule command à bash -c , il exec() et donc le process bash est remplacé et vous ne pouvez pas tuer son PID.

    Comme décrit dans cette réponse utile, les effets de -n ( unshare(CLONE_NEWPID) ) n'entrent en action que pour le premier process enfant forké.

    En particulier, man 2 unshare dit dit à propos de CLONE_NEWPID :

    Démarquez l'espace de noms PID pour que le process appelant ait un nouvel espace-noms PID pour ses enfants qui n'est partagé avec aucun process existant.

    Le process appelant n'est pas déplacé dans le nouvel espace de noms.

    Le premier enfant créé par le process appelant aura l'ID de process 1 et assumera le rôle de init(1) dans le nouvel espace de noms.


    Patching unshare pour faire le travail de tuer de façon fiable

    Depuis que j'ai posé ma question, au cours des dernières heures, j'ai écrit un patch à util-linux ( request de pull ici ) qui ajoute un drapeau --kill-child pour unshare .

    Vous pouvez l'utiliser comme ceci:

     unshare -fp --kill-children -- bash -c "watch /bin/sleep 10000 && echo hi" 

    et tuer unshare va déchirer toute l'arborescence du process comme expeted.

    Sans root

    Vous pouvez même l'utiliser sans privilèges root si votre kernel a des namespaces d'users activés ( CONFIG_USER_NS=y ) en passant le drapeau -U :

     unshare -Ufp --kill-children -- bash -c "watch /bin/sleep 10000 && echo hi"