#c #linux #ptrace
#c #linux #ptrace
Вопрос:
Итак, у меня есть хорошая совместная PTRACE_TRACEME
дочерняя программа, обрабатываемая PTRACE
программой-оболочкой.
Проблема в том, что если администратор (или другой) решает SIGSTOP
дочернюю программу, как я могу с этим справиться? И SIGCONT
, конечно, забрать позже.
Ответ может быть «вы не можете»? Это PTRACE
в конце концов!
Я вижу, что PTRACE_LISTEN
(начиная с Linux 3.4) играет определенную роль, переводя дочернюю программу в остановленное состояние, но это документировано, чтобы работать только тогда, когда дочерний элемент подключен PTRACE_SEIZE
.
Я попробовал тривиальную вещь вызова PTRACE_LISTEN
в PTRACE_TRACEME
режиме групповой остановки, и, как задокументировано, я получаю старую ошибку McDonald — EIO
.
У меня есть мысль, что я мог бы ввести код для выполнения a sigsuspend
, но, конечно, это приостановит только 1 поток дочерней программы. Мне пришлось бы вводить сигнал в каждый поток, чтобы затем остановить их все? А затем перезапустить?
Или, возможно, реализация redelivered SIGSTOP
уже остановила их все? В каком случае мой sigsuspend
действительно сработает? Думаю, я мог бы запустить его напрямую, если бы другой поток сообщил SIGCONT
.
Хотя это звучит очень забавно для кода, мне интересно, не пропустил ли я трюк в PTRACE
документации? Возможно, есть способ перейти в PTRACE_SEIZE
режим совместимости, который мне не хватает?
[дополнительные замечания]
почему бы просто не использовать PTRACE_SEIZE в первую очередь?
- Для PTRACE_TRACEME требуется меньше привилегий безопасности;
- мы используем seccomp для фильтрации перехватов системных вызовов, которые являются основным моментом;
- мы хотим быть в начале выполнения дочернего EXE-файла.
Итак, в заключение: существует ли механизм для перехода в PTRACE_SEIZE
режим или для имитации SIGSTOP
поведения в API в его нынешнем виде?
Ответ №1:
Ниже приведен пример тестовой программы PTRACE_SEIZE, которая имитирует поведение SIGSTOP.
#define PTRACE_SEIZE 0x4206
#define PTRACE_SEIZE_DEVEL 0x80000000
static const struct timespec ts100ms = { .tv_nsec = 100000000 };
static const struct timespec ts1s = { .tv_sec = 1 };
static const struct timespec ts3s = { .tv_sec = 3 };
int main(int argc, char **argv)
{
pid_t tracee;
tracee = fork();
if (tracee == 0) {
nanosleep(amp;ts100ms, NULL);
while (1) {
printf("tracee: aliven");
nanosleep(amp;ts1s, NULL);
}
}
if (argc > 1)
kill(tracee, SIGSTOP);
nanosleep(amp;ts100ms, NULL);
ptrace(PTRACE_SEIZE, tracee, NULL,
(void *)(unsigned long)PTRACE_SEIZE_DEVEL);
waitid(P_PID, tracee, NULL, WSTOPPED);
ptrace(PTRACE_CONT, tracee, NULL, NULL);
nanosleep(amp;ts3s, NULL);
printf("tracer: exitingn");
return 0;
}
Когда приведенный выше код вызывается без аргумента, трассировка выводится из
состояния выполнения и продолжается. Когда трассировщик завершает работу, трассировка возвращается в
рабочее состояние и продолжает распечатку.
# ./test-seize
tracee: alive
tracee: alive
tracee: alive
tracer: exiting
# tracee: alive
tracee: alive
tracee: alive
При вызове с аргументом трассировка перехватывается из состояния stopped и
продолжается, и возвращается в состояние stopped при завершении трассировки.
# ./test-seize
tracee: alive
tracee: alive
tracee: alive
tracer: exiting
# ps -el|grep test-seize
1 T 0 4720 1 0 80 0 - 941 signal ttyS0 00:00:00 test-seize
Вы можете прочитать больше в этой теме
Комментарии:
1. Да, действительно, я вижу, что PTRACE_SEIZE предоставляет такую возможность. Я отметил это в вопросе, и это обсуждается в общедоступной документации PTRACE . Но если я правильно прочитал, для использования любого из механизмов взлома, отличных от PTRACE_TRACEME, помимо прочего, требуются дополнительные привилегии безопасности. Также вопрос о том, можно ли остановить трассировку с момента ее создания?