Может ли ptrace сказать, использовал ли системный вызов x86 64-битный или 32-битный ABI? - PullRequest
0 голосов
/ 24 ноября 2018

Я пытаюсь использовать ptrace для отслеживания всех системных вызовов, выполненных отдельным процессом, будь то 32-разрядный (IA-32) или 64-разрядный (x86-64).Мой трассировщик будет работать на 64-битной установке x86 с включенной эмуляцией IA-32, но в идеале сможет отслеживать как 64-битные, так и 32-битные приложения, в том числе, если 64-битное приложение разветвляется и исполняет 32-битный процесс.

Проблема в том, что, поскольку 32-разрядные и 64-разрядные номера системных вызовов различаются, мне нужно знать, является ли процесс 32-разрядным или 64-разрядным, чтобы определить, какой системный вызов он использовал, даже если у меня естьномер системного вызова.Кажется, есть несовершенные методы , такие как проверка /proc/<pid>/exec или (как это делает strace) размер структуры регистров, но ничего надежного.

Сложность в том, что 64-битныйпроцессы могут переключаться из длинного режима для непосредственного выполнения 32-битного кода.Они также могут делать 32-битные int $0x80 системные вызовы , которые, конечно, используют 32-битные числа системных вызовов.Я не «доверяю» процессам, которые отслеживаю, чтобы не использовать эти уловки, поэтому я хочу правильно их обнаружить.И я независимо проверил, что, по крайней мере, в последнем случае, ptrace видит 32-битные числа системных вызовов и назначения регистров аргументов, а не 64-битные.

Я покопался в исходном коде ядра и наткнулся нафлаг TS_COMPAT в arch/x86/include/asm/processor.h, который представляется установленным всякий раз, когда 32-битный системный вызов выполняется 64-битным процессом.Единственная проблема в том, что я понятия не имею, как получить доступ к этому флагу из пользовательского пространства, или если это вообще возможно.

Я также думал о чтении %cs и сравнении его с $0x23 или $0x33Вдохновленный этим методом для переключения битности в работающем процессе.Но это только обнаруживает 32-битные процессы , не обязательно 32-битные системные вызовы (те, которые сделаны с int $0x80) из 64-битного процесса.Он также хрупок, поскольку полагается на недокументированное поведение ядра.

Наконец, я заметил, что в архитектуре x86 есть немного для длинного режима в MSR регистра расширенных возможностей.Но ptrace не может прочитать MSR из трассировки, и я чувствую, что чтение изнутри моего трассировщика будет неадекватным, потому что мой трассировщик всегда работает в длинном режиме.

Я в растерянности.Возможно, я мог бы попытаться использовать один из этих хаков - на данный момент я склоняюсь к %cs или к /proc/<pid>/exec методу - но я хочу что-то долговечное, что на самом деле будет отличать 32-битные и 64-битные системные вызовы. Как процесс, использующий ptrace под x86-64, который обнаружил, что его трассировка сделала системный вызов, надежно определяет, был ли этот системный вызов выполнен с 32-разрядным (int $0x80) или 64-разрядным (syscall)ABI? Есть ли какой-то другой способ для пользовательского процесса получить эту информацию о другом процессе, для которого он авторизован ptrace?

1 Ответ

0 голосов
/ 24 ноября 2018

Интересно, я не осознавал, что не было очевидного более умного способа, которым strace мог бы использовать для правильного декодирования int 0x80 из 64-битных процессов.( Это работает, см. этот ответ для ссылок на предложенный патч ядра для добавления PTRACE_GET_SYSCALL_INFO в API ptrace. strace 4.26 уже поддерживает его в патченных ядрах.)


В качестве обходного пути, я думаю, вы можете разобрать код в RIP и проверить, была ли это инструкция syscall (0F 05) или нет, потому что ptrace позволяет читать память целевого процесса.

Но для случая использования безопасности, такого как , запрещающего некоторые системные вызовы , это будет уязвимо для состояния гонки: еще один поток в процессе системного вызова.может переписать байты syscall в int 0x80 после их выполнения, но прежде чем вы сможете просмотреть их с помощью ptrace.


Это необходимо сделать только в том случае, если процесс запущенв 64-битном режиме, в противном случае доступен только 32-битный ABI .Если это не так, вам не нужно проверять.(Страница vdso потенциально может использовать 32-битный режим syscall на процессорах AMD, которые поддерживают его, но не sysenter. Если вы не проверяете 32-битные процессы в первую очередь, это исключает этот угловой случай.) Я думаю, вы говоритеесть надежный способ обнаружить , что, по крайней мере, .

(Я не использовал API ptrace напрямую, только инструменты, такие как strace, которые его используют. Поэтому я надеюсь, что этот ответ поможетчувство.)

...