Я попытался установить фильтр seccomp BPF для работающего процесса Tomcat. После присоединения gdb
к процессу я вызвал функцию dlopen
для загрузки общей библиотеки (файл .so), которая вернула дескриптор. Дескриптор был целым числом, а не нулем. Однако когда я использовал команду gdb x
для проверки содержимого памяти дескриптора, в приглашении gdb появилась ошибка: Cannot access memory at address
. Впоследствии я попытался вызвать dlsym
, используя дескриптор в качестве параметра, но gdb
был прерван, поскольку появился сигнал SIGSEGV
.
Вот иллюстрация:
(gdb) set $handle=dlopen("/opt/seccompfilter.so",1)
(gdb) x $handle
0xffffffffaaef8730: Cannot access memory at address 0xffffffffaaef8730
(gdb) call dlsym((void *)$handle, "install_filter")
[Thread 0x7f6250aed700 (LWP 2069) exited]
Program received signal SIGSEGV, Segmentation fault.
_dl_lookup_symbol_x (undef_name=0x5636aaef81d0 "install_filter",
undef_map=0xffffffffaaef8730, ref=0x7ffe774956a0,
symbol_scope=0xffffffffaaef8ab8, version=0x0, type_class=0,
flags=2, skip_map=0x0) at dl-lookup.c:733
733 while ((*scope)->r_list[i] != skip_map)
The program being debugged was signaled while in a function called
from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on".
Evaluation of the expression containing the function
(__dlsym) will be abandoned.
When the function is done executing, GDB will silently stop.
Я пытаюсь понять, что пошло не так. Вот среда, с которой я работал:
CentOS 7 kernel-3.10.0-1160.90.1.el7.x86_64
gdb 7.6.1-120.el7
glibc 2.17
Интересно, что когда я проделал те же действия на Ubuntu 20.04, все заработало успешно. В чем проблема?
Я попробовал вызвать функцию dlopen, чтобы загрузить общую библиотеку libc.so.6
, и получил тот же результат.
Вы уверены, что процесс был завершен SIGSEGV, а не самим GDB?
gdb 7.6.1
больше 10 лет. Более поздний, вероятно, сказал бы вам dlopen has unknown return type; cast the call to its declared return type
. В этом случае вам, вероятно, придется сделать что-то вроде: set $handle=((void*(*)(char*,int))dlopen)("/opt/seccompfilter.so",1)
@ssbssa Я попробовал ваш подход, но результат тот же. Критическая проблема заключается в том, почему к дескриптору невозможно получить доступ в памяти.
Я пытаюсь понять, что пошло не так.
Значение $handle
0xffffffffaaef8730
неверно. Адреса памяти в пользовательском пространстве x86_64
(и дескриптор, возвращаемый dlopen
, на самом деле указывает на struct link_map
) находятся в диапазоне [0x1000 - 0x7fffffffffff]
, и все, что находится в диапазоне 0xffffffff........
, может быть только адресом ядра.
Итак, почему это произошло?
Скорее всего, GDB неправильно интерпретировал возвращаемый тип dlopen
в $rax
как int32_t
и расширил его до int64_t
.
Возврат dlopen
может выглядеть примерно так: 0x00007ffffaaef8730
, и если вы сделаете неверную интерпретацию выше, вы получите именно то значение, которое получили на самом деле:
(gdb) p/x (long)(int)0x00007ffffaaef8730
$1 = 0xffffffffaaef8730
В старой версии GDB, которую вы используете, может быть ошибка. Другая возможность — что GDB не знает фактический тип возвращаемого значения dlopen
— кажется маловероятной, учитывая, что у него есть отладочная информация для GLIBC.
Возможно, вы захотите установить точку останова на dlopen
, использовать finish
для возврата из нее и непосредственно проверить $rax
.
Может быть, вы могли бы показать, что именно вы сделали, когда получили SIGSEGV?