「呼び出し元のプロセスイメージでatexit()によって登録された関数は、新しいプロセスイメージに登録されていません」。
コードは次のとおりです。
pid = fork();
if (pid == 0) {
atexit(check_mem);
return execv(...);
}
check_mem関数がexecv()の後に呼び出されません。上記の「線」のため。execv呼び出し後に関数を登録するためのハックはありますか?
よろしくお願いします。
何かを実行*すると、atexitハンドラーは実行されません。
execvは、登録したatexitハンドラーを含む現在のプロセスイメージを置き換えるため、実際にできることは多くありません。コードはなくなります。
少しトリッキーですが実行可能です-次のような関数を使用して共有ライブラリ(check_mem.soと呼びましょう)を作成します。
__attribute__((constructor)) void runs_first(void) {
atexit(check_mem);
};
check_memは、プログラムではなく、ライブラリで定義する必要があることに注意してください。
ここでexecveで、LD_PRELOAD = / path / to / check_mem.soをプログラムに渡される環境変数に入れます(execveの最後の引数)。
新しいプログラムが実行されると、check_memライブラリがロードされ、(ほぼ)他のすべてのコードの前にruns_first関数が実行されます。
実行しているプログラムが動的にリンクされている場合にのみ機能しますが、それが唯一の制限です。
編集:コメントが正しく述べているように、それはsetuidプログラムでも機能しません。それでも、ユースケースをカバーできる可能性は十分にあると思います。
nosが言ったように、execがプロセスを置き換えます。代わりに、 <stdlib.h>のint system (char *s)
関数を使用して、argsを使用してプログラムを開始してみてください。execveとは異なり、システムは、生成されたプロセスが終了すると戻ります。
pid = fork();
if (pid == 0) {
atexit(check_mem);
system ("program arg1 arg2 ...");
exit (0); /* Calls atexit handlers. */
}
完璧な解決策は、以下のようにptrace()を使用することです。
pid = fork();
if (pid == 0) {
ptrace(PTRACE_TRACEME, 0, 0, 0);
return execve(...);
}
wait(NULL);
ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACEEXIT);
ptrace(PTRACE_CONT, pid, 0, (void*)0);
while(1){
waitpid(pid, &status, 0);
if((WSTOPSIG(status) == SIGTRAP) && (status & (PTRACE_EVENT_EXIT << 8)))
break;
ptrace(PTRACE_CONT, pid, 0, WSTOPSIG(status));
}
check_mem();
ptrace(PTRACE_CONT, pid, 0, 0);