¿Por qué la matanza sin compartir solo funciona de manera confiable con –fork?

A partir de esta respuesta , hemos aprendido que puede implementar la eliminación confiable de subtreees de processs completos con espacios de nombres PID de Linux a través de unshare -p .

Aquí hay un problema que no entiendo:

  • Solo funciona cuando uso la opción -f / --fork para dejar de compartir.

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

    Cuando ejecuto esto, y kill -9 el PID de ese bash , luego miro, duermo, etc., estoy muerto, como deseo.

  • Pero cuando lo uso sin -f :

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

    y kill -9 el PID de bash, luego el watch se vuelve a PID 1 (en mi Ubuntu que está systemd), por lo que no tengo el efecto deseado de matar a todos los niños.

Preguntas:

  • ¿Por qué es necesario --fork el efecto deseado? ¿Por qué no es suficiente el uso unshare exec() sin fork?
  • ¿Hay una solución para esto? Preferiría si pudiera enviar kill -9 al PID creado al comenzar a unshare de unshare para matar todo debajo de él. Pero cuando uso --fork , matar el pid devuelto cuando comencé a unshare , bueno, simplemente mato a unshare y tengo bash reparented a PID 1, porque no unshare en mi espacio de nombres PID.

Tenga en count que el && echo hi es necesario porque si le da solo un command a bash -c , lo exec() y, por lo tanto, el process bash desaparecerá (replaceá) y no podrá eliminar su PID.

Solutions Collecting From Web of "¿Por qué la matanza sin compartir solo funciona de manera confiable con –fork?"

Como se describe en esta útil respuesta, los efectos de -n ( unshare(CLONE_NEWPID) ) solo entran en vigencia para el primer process hijo bifurcado.

En particular, man 2 unshare says dice sobre CLONE_NEWPID :

Dejar de compartir el espacio de nombres PID, de modo que el process de llamada tenga un nuevo espacio de nombres PID para sus hijos, que no se comparte con ningún process existente previamente.

El process de llamada no se mueve al nuevo espacio de nombres.

El primer hijo creado por el process de llamada tendrá el ID de process 1 y asumirá el rol de init(1) en el nuevo espacio de nombres.


Aplicar unshare para unshare de unshare para que el trabajo de matar sea confiable

Desde que hice mi pregunta, en las últimas dos horas escribí un parche para util-linux ( request de extracción aquí ) que agrega una bandera --kill-child para unshare de unshare .

Puedes usarlo así:

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

y matar a no unshare destruirá todo el tree de process como se esperaba.

Sin root

Incluso puede usarlo sin privilegios de root si su kernel tiene habilitados los espacios de nombres de usuario ( CONFIG_USER_NS=y ) pasando el indicador -U :

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