我正在开发一个软件,它使用ptrace(2)监视其他进程的系统调用。不幸的是,大多数现代操作系统都实现了某种快速的用户模式系统调用,在Linux中称为 vsyscalls。是否有办法对单个进程禁用vsyscalls/vDSO,如果无法禁用,则对整个操作系统禁用?
unguejic1#
尝试echo 0 > /proc/sys/kernel/vsyscall64如果你尝试在gettimeofday调用时使用ptrace,但是它们没有出现,那么系统使用的是什么时间源(pmtimer,acpi,tsc,hpet,等等),我想知道你是否可以试着强迫你的计时器使用像pmtimer这样的老时间,这可能是gtod计时器特定优化中的一个导致了你的ptrace调用被避免,即使vsyscall设置为零。
echo 0 > /proc/sys/kernel/vsyscall64
vs3odd8k2#
是否有办法对单个进程禁用vsyscalls/vDSO,如果无法禁用,则对整个操作系统禁用?事实证明,是一种有效地禁用单个进程的链接vDSO的方法,而不必使用ptrace在系统范围内禁用它!您所要做的就是在跟踪的进程从execve返回之前停止它,并从辅助向量中删除AT_SYSINFO_EHDR条目(它直接位于rsp中指向的内存区域的环境变量之后)。PTRACE_EVENT_EXEC是一个很好的位置。AT_SYSINFO_EHDR是内核用来告诉系统链接器vDSO在进程地址空间中的Map位置的内容。如果此条目不存在,ld的行为就好像系统尚未MapvDSO一样。请注意,这并没有从进程内存中取消vDSO的Map,它只是在链接其他共享库时忽略它。如果作者真的想与它交互,恶意程序仍然可以与它交互。我知道这个答复有点迟,但我希望这个消息能使一些可怜的人免于头痛
ptrace
execve
AT_SYSINFO_EHDR
rsp
PTRACE_EVENT_EXEC
ld
7fyelxc53#
对于较新的系统echo 0 > /proc/sys/kernel/vsyscall64可能不起作用。在Ubuntu 16.04中,可以通过在/etc/default/grub中的以下参数下添加内核参数vdso=0来在系统范围内禁用vDSO:GRUB_CMDLINE_LINUX_DEFAULT.重要提示:参数GRUB_CMDLINE_LINUX_DEFAULT可能会被/etc/default/grub.d/...中的其他配置文件覆盖,因此请仔细检查何时添加自定义配置。
/etc/default/grub
vdso=0
GRUB_CMDLINE_LINUX_DEFAULT
/etc/default/grub.d/...
zkure5ic4#
在Tenders McChiken's approach上,我创建了一个 Package 器,它可以对任意二进制文件禁用vDSO,而不会影响系统的其余部分:https://github.com/danteu/novdso一般程序相当简单:1.使用ptrace等待从execve(2)返回1.查找辅助向量的地址1.用AT_IGNORE覆盖AT_SYSINFO_EHDR条目,告诉应用程序忽略以下值
wd2eg0qa5#
我知道这是一个比较老的问题,但是没有人提到过第三种有用的方法,可以在每个进程的基础上禁用vDSO。您可以用自己的函数覆盖libc函数,该函数使用LD_PRELOAD执行实际的系统调用。例如,用于覆盖gettimeofday和time函数的简单共享库可能如下所示:
LD_PRELOAD
gettimeofday
time
vdso_覆盖.c:
#include <time.h> #include <sys/time.h> #include <unistd.h> #include <sys/syscall.h> int gettimeofday(struct timeval *restrict tv, struct timezone *restrict tz) { return syscall(__NR_gettimeofday, (long)tv, (long)tz, 0, 0, 0, 0); } time_t time(time_t *tloc) { return syscall(__NR_time, (long)tloc, 0, 0, 0, 0, 0); }
这将使用libc Package 器发出一个原始系统调用(请参见syscall(2)),因此vDSO被绕过,您必须以这种方式覆盖vDSO在您的体系结构上导出的所有系统调用(在vdso(7)中列出)。编译
gcc -fpic -shared -o vdso_override.so vdso_override.c
然后运行要禁用VDSO调用的任何程序,如下所示:
LD_PRELOAD=./vdso_override.so <some program>
当然,只有当你运行的程序没有主动尝试绕过这个问题时,这才有效。虽然你可以使用LD_PRELOAD覆盖一个符号,但如果目标程序真的想这样做,有一种方法可以找到原始符号并使用它。
5条答案
按热度按时间unguejic1#
尝试
echo 0 > /proc/sys/kernel/vsyscall64
如果你尝试在gettimeofday调用时使用ptrace,但是它们没有出现,那么系统使用的是什么时间源(pmtimer,acpi,tsc,hpet,等等),我想知道你是否可以试着强迫你的计时器使用像pmtimer这样的老时间,这可能是gtod计时器特定优化中的一个导致了你的ptrace调用被避免,即使vsyscall设置为零。
vs3odd8k2#
是否有办法对单个进程禁用vsyscalls/vDSO,如果无法禁用,则对整个操作系统禁用?
事实证明,是一种有效地禁用单个进程的链接vDSO的方法,而不必使用
ptrace
在系统范围内禁用它!您所要做的就是在跟踪的进程从
execve
返回之前停止它,并从辅助向量中删除AT_SYSINFO_EHDR
条目(它直接位于rsp
中指向的内存区域的环境变量之后)。PTRACE_EVENT_EXEC
是一个很好的位置。AT_SYSINFO_EHDR
是内核用来告诉系统链接器vDSO在进程地址空间中的Map位置的内容。如果此条目不存在,ld
的行为就好像系统尚未MapvDSO一样。请注意,这并没有从进程内存中取消vDSO的Map,它只是在链接其他共享库时忽略它。如果作者真的想与它交互,恶意程序仍然可以与它交互。
我知道这个答复有点迟,但我希望这个消息能使一些可怜的人免于头痛
7fyelxc53#
对于较新的系统
echo 0 > /proc/sys/kernel/vsyscall64
可能不起作用。在Ubuntu 16.04中,可以通过在/etc/default/grub
中的以下参数下添加内核参数vdso=0
来在系统范围内禁用vDSO:GRUB_CMDLINE_LINUX_DEFAULT
.重要提示:参数
GRUB_CMDLINE_LINUX_DEFAULT
可能会被/etc/default/grub.d/...
中的其他配置文件覆盖,因此请仔细检查何时添加自定义配置。zkure5ic4#
在Tenders McChiken's approach上,我创建了一个 Package 器,它可以对任意二进制文件禁用vDSO,而不会影响系统的其余部分:https://github.com/danteu/novdso
一般程序相当简单:
1.使用ptrace等待从execve(2)返回
1.查找辅助向量的地址
1.用AT_IGNORE覆盖AT_SYSINFO_EHDR条目,告诉应用程序忽略以下值
wd2eg0qa5#
我知道这是一个比较老的问题,但是没有人提到过第三种有用的方法,可以在每个进程的基础上禁用vDSO。您可以用自己的函数覆盖libc函数,该函数使用
LD_PRELOAD
执行实际的系统调用。例如,用于覆盖
gettimeofday
和time
函数的简单共享库可能如下所示:vdso_覆盖.c:
这将使用libc Package 器发出一个原始系统调用(请参见syscall(2)),因此vDSO被绕过,您必须以这种方式覆盖vDSO在您的体系结构上导出的所有系统调用(在vdso(7)中列出)。
编译
然后运行要禁用VDSO调用的任何程序,如下所示:
当然,只有当你运行的程序没有主动尝试绕过这个问题时,这才有效。虽然你可以使用
LD_PRELOAD
覆盖一个符号,但如果目标程序真的想这样做,有一种方法可以找到原始符号并使用它。