J’essaie d’écrire un outil sur Linux CentOS pour suivre tous les processus générés et ce qui est exécuté. En gros, je suis intéressé à parcourir tous les fork / clones et à émettre toutes les lignes de commande de execve()
. Strace le fait déjà (en partie), mais il tronque également les appels et les arguments. Je voulais aussi mieux comprendre comment fonctionne ptrace()
.
Ainsi, le premier obstacle consistait à déterminer comment utiliser ptrace()
pour parcourir un fork / clone sans que le programme de suivi ne nécessite de copier une copie de lui-même. J’ai creusé et découvert comment strace fait cela. Puisque fork est implémenté avec clone sous Linux, j’ai remarqué que strace pesait quelques bits dans le syscall du clone pour permettre le traçage des enfants sans aucun mal de tête supplémentaire.
Donc, le code est essentiellement un gros:
while (1) { int pid = wait3(-1,...); /* process what happened */ ptrace(PTRACE_SYSCALL, pid,...); }
Cela fonctionne très bien pour des processus relativement simples comme /bin/sh
, cependant, certains processus entraînent le blocage indéfini de l’ wait()
. La seule chose que j’ai été capable de déterminer, c’est que le processus que je suis en train de faire consiste à exécuter un sys_rt_sigsuspend()
sur son enfant (donc, le petit-enfant du traceur) et ensuite les choses se calent.
J’étais curieux de savoir s’il était possible de déboguer ce qui pourrait arriver. Quelque chose empêche clairement l’arborescence des processus d’avancer
Voici le code source du programme en question:
#include #include #include #include #include #include /* For the clone flags */ #include /* #include */ #include #include /* Defines our syscalls like */ #include #include #include #include #include #include
Il existe des drapeaux du sous-ensemble ptrace PTRACE_SETOPTIONS: PTRACE_O_TRACEFORK, PTRACE_O_TRACEEXEC et PTRACE_O_TRACEEXIT. Plus est à la page de manuel de ptrace.
Au fait. strace -f -s99999 -e trace=clone,execve
semble donner des résultats de bonne qualité. Pour voir une trace des propres actions de strace, vous pouvez essayer systemtap, c.-à-d.
# stap -e 'probe syscall.ptrace {if (execname()=="strace") log(argstr)}' -c 'strace COMMAND'
(Le systemtap actuel n’imprime pas correctement les arguments de ptrace.)
Ou vous pouvez strace strace:
strace -e trace=ptrace strace -f -s99999 -e trace=clone,execve COMMAND