使用LD_PRELOAD和单个入口点处理系统调用

在LLVM上重新实现QInst时,遇到了以下问题:在一个进程的仿真模式下,QEMU自然会拦截所有“来宾”系统调用。 因此,检测插件具有一个用于预处理的单个入口点,您可以在其中通过SYS_*数字和参数值进行决策。 这很方便。 问题在于,所有系统调用主要是由libc并且静态地重写代码,在大多数情况下,我们根本不会涉及到这一部分。 当然,也可以使用ptrace ,它也是为此而设计的。 但是,我不确定如果没有单独的过程是否可能做得到,并且QInst语义暗示了一个微不足道的“同步”拦截-您将不得不以某种方式将调用注入处理程序,这比通常的LD_PRELOAD复杂得多。 您可以包装每个系统调用-但这至少不方便(此外,我们可以跳过某些内容,因为在这种情况下,我们不会拦截系统调用本身,而是拦截其特定的包装器)。


削减成本-一种与LLVM无关的解决方案,但是针对x86_64上的Linux进行了改进(但适用于其他体系结构上的Linux)。


注意:本文不提供通用的现成解决方案-仅适用于相当广泛的案例。 但是这篇文章可以被认为是周五的复习:有趣的(希望)新的(对于大多数?)信息,大量的暴力编程和可行的例子。 而且不要让我们的星期五甚至被今天是星期四的事实所笼罩!


首先,让我们决定:在本文中,我们的目标不是绕过反调试机制,并且通常假定该程序不抵抗系统调用的拦截。 另一方面,手动重写源代码以使该程序我们有帮助,纯粹就劳动强度而言也是如此。 因此LD_PRELOAD 。 但是,如果要将这种机制静态编译到自己的程序中,则LD_PRELOAD在这里绝对不是必需的。


抒情离题:如何在Linux中进行系统调用? 有几种方法可以做到这一点。 一次,一个进程(在x86上)只需将系统调用号放在eax ,将第一个参数放在ebx依此类推,之后将int 0x80拉入。 在某个时候,他们认为它不是非常快,或者对缓存不友好,或者其他原因,然后重做。 然后再说一次。 目前,使用了vDSO-这是一个注入到每个进程中的诚实共享对象,您可以拉出函数以进行频繁的系统调用,而无需进行上下文切换(例如time )。 看来您可以在此结束本文,但没有结束:在那里描述了大约四个单独的系统调用(确切的数目很可能取决于内核版本),并且在全局入口点没有观察到任何东西。


可以进一步搜索一个共同点,选择在本机系统上通过哪些指令进行调用( int 0x80 / sysenter / ...)-也许根本不存在-让我们将其留给读者。 让我们更好地注意seccomp机制,该机制提供了另一个用于过滤系统调用的标准接口。


Seccomp代表安全计算,旨在处理不太可信的代码。 引用man seccomp (2)


 Strict secure computing mode is useful for number-crunching applications that may need to execute untrusted byte code, perhaps obtained by reading from a pipe or socket. 

好吧,在Meltdown&Co之后,人们已经害怕在多个线程中运行JavaScript-我不知道不受信任的二进制代码的效果如何。 但是,部分受信任的环境中的安全性是一个单独的问题,我只能说,尽管seccomp可以在单个流级别工作,例如,我自然不敢坐在运行不受信任的机器代码的同一个地址空间中。 通常,恶意软件的安全“准备”也不是本文的主题。


在这种情况下,我对拦截系统调用感兴趣,而不是从检测的角度来看。 幸运的是,除了SECCOMP_SET_MODE_STRICT模式之外,当进行除readwrite_exitsigreturn之外的任何调用时,该过程都将强制终止进程,此外还有SECCOMP_SET_MODE_FILTER它允许您指定一个BPF程序,该程序将仅过滤感兴趣的系统调用, SECCOMP_SET_MODE_FILTER被过滤的程序决定处理方式。 在这里,选择已经足够大了,但是现在SECCOMP_RET_TRAPSECCOMP_RET_TRAP感兴趣:发出此判决后, SIGSYS特定的流发送SIGSYS ,即确切需要的流:您可以同步处理请求并返回控制,就像系统调用已正常发生一样。


准备工作


对于我们的处理程序,创建syscall-handler.c文件


 #include <linux/seccomp.h> #include <linux/filter.h> #include <linux/audit.h> #include <linux/signal.h> #include <sys/ptrace.h> uint64_t handle_syscall(uint32_t num, uint32_t *drop_syscall, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6); void initialize_handler(void) { } static void __attribute__((constructor))constr(void) { initialize_handler(); } 

让我们描述处理系统调用的函数-这非常清楚:该函数接受系统调用的数目,(最多)六个参数,以及(返回的)符号,该标志不仅考虑了系统调用,而且模拟了系统调用,实际上并不需要执行它。 其余的甚至更简单: initialize_handler函数将配置所有这一切的调度。


这个神秘的constr函数是什么? 它仅调用initialize_handler ,但是由于它带有constructor属性标记,因此将在包含此函数的库(或主要可执行文件)初始化期间调用它。 如果要在启动程序后启用拦截,则可以设置constr并手动调用initialize_handler


编写BPF程序


现在,您需要编写一个BPF字节码,通过发出SECCOMP_RET_TRAP可以简单地响应所需的系统调用号。 程序格式的文档尤其位于Documentation / networking / filter.txt的内核源代码中,而对于seccomp,您需要查看旧版本,而不是eBPF。 linux / seccomp.hlinux / filter.h文件本身以及它所指向的linux / bpf_common.h也将非常有用。 如果您将这些源收集到堆中( man seccomp的示例)并将其摇晃,则会得到以下内容:


 struct sock_filter filt[] = { BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, args[5]))), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K , MARKER, 0, 1), BPF_STMT(BPF_RET | BPF_K , SECCOMP_RET_ALLOW), BPF_STMT(BPF_RET | BPF_K , SECCOMP_RET_TRAP), }; 

自从我几周前写这本书以来,即便如此,它还是来自一个示例的代码,然后按照旧的传统 假设这很明显 让读者作为练习。 原则上,操作码(偏移量为0和1 / RET LD / JMP ),条件( JEQ ),使用立即数操作数的指令( BPF_K )在此处清晰可见- 有关更多详细信息,请参见BPF_K 。 宏使您不必考虑用团队的话包装所有东西。


为什么我们需要MARKER常数? 如果我们的userspace-filter决定这样做的话,这将使您仍然可以跳过系统调用。 马虎的,ed紧的-但是我没有保证展示通用的解决方案。 然而,所示的解决方案在大多数情况下也很成功,而且安排得很简单。


我们将相同的MARKER放在系统调用的第六个参数中,希望这是一个“多余的细节”,并且很少使用所有六个参数。 我们使用BPF程序的第一条指令减去它:从这里开始是一个神秘的表达式offsetof(struct seccomp_data, args[5]) -内核将seccomp_data结构传递给seccomp_data (请参见man seccomp ):


 struct seccomp_data { int nr; /* System call number */ __u32 arch; /* AUDIT_ARCH_* value (see <linux/audit.h>) */ __u64 instruction_pointer; /* CPU instruction pointer */ __u64 args[6]; /* Up to 6 system call arguments */ }; 

...,然后从所需的偏移量处减去变量: offsetof(struct seccomp_data, args[5])本段由aol-nnov赞助


它以某种方式使用:


 uint64_t handle_syscall(uint32_t num, uint32_t *drop_syscall, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6) { return 0; } #define MARKER 0x12345678 static int in_handler; static void handle_sigsys(int num, siginfo_t *si, void *arg) { ucontext_t *ctx = arg; greg_t *gregs = ctx->uc_mcontext.gregs; uint32_t drop = 0; uint64_t res; if (!in_handler) { in_handler = 1; res = handle_syscall(gregs[REG_RAX], &drop, gregs[REG_RDI], gregs[REG_RSI], gregs[REG_RDX], gregs[REG_R10], gregs[REG_R8], gregs[REG_R9]); in_handler = 0; } if (!drop) { res = syscall(gregs[REG_RAX], gregs[REG_RDI], gregs[REG_RSI], gregs[REG_RDX], gregs[REG_R10], gregs[REG_R8], MARKER); } gregs[REG_RAX] = res; } void initialize_handler(void) { //  BPF-  struct sock_filter filt[] = { BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, args[5]))), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K , MARKER, 0, 1), BPF_STMT(BPF_RET | BPF_K , SECCOMP_RET_ALLOW), BPF_STMT(BPF_RET | BPF_K , SECCOMP_RET_TRAP), }; struct sock_fprog prog = { sizeof(filt) / sizeof(filt[0]), filt }; //  userspace- struct sigaction sig; memset(&sig, 0, sizeof(sig)); sig.sa_sigaction = handle_sigsys; sig.sa_flags = SA_SIGINFO; sigaction(SIGSYS, &sig, NULL); // ,   prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER, 0, &prog); } 

handle_sigsys是可以与sigaction函数一起使用的新型信号处理程序。 关于他的第三个参数, man sigaction说:


  ucontext This is a pointer to a ucontext_t structure, cast to void *. The structure pointed to by this field contains signal context information that was saved on the user-space stack by the kernel; for details, see sigreturn(2). Further information about the ucontext_t structure can be found in getcontext(3). Commonly, the handler function doesn't make any use of the third argument. 

好吧,我们没有一个非常普遍的情况,因此 为了改变 我们将不使用第二个参数-也有很多有趣的事情,但是系统调用没有参数。 从手鼓开始跳舞,从正确的结构中就需要手鼓。 libseccomp很有可能成功地整合了这些架构细节,并仅产生了一个参数数组-如果现在不这样做,那么可能会晚一些-但由于我们有介绍性文章,因此我们假定如此低的水平不是错误,还有一个功能...因此,只需检查man syscall的第二个表以了解所需的体系结构,在我的情况下就是x86_64。


在同一个处理程序中,我们看到了另一个有趣的功能: syscall实际上,正是我们从她那里读了man。 她只是获得系统调用号和参数,然后执行它。 在某些体系结构上,存在各种棘手的ABI,它们在32位寄存器中“对齐” 64位值(所有内容均在同一手册页中进行了读取)-希望这与x86_64无关,否则我们将不得不根据数量对其进行解析通过减去寄存器进行syscall() ,因为syscall()已经在自身中隐藏了此逻辑。 除了这种奇怪的情况之外,当动态确定电话号码时,如果由于某种原因我们没有用于系统调用的libc-wrapper,则可以使用它。 例如,这正是我在以下函数中调用seccomp的方式:


  syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER, 0, &prog); 

出于安全性原因,需要此奇怪的prctl :在man seccomp一个示例,没有此要求,您可以将不幸的set-user-ID二进制文件放入虚拟现实中,其中setuid将返回零,但什么也不做,从角度来看这将是非常危险的特权提升视图。


我们编译并使用我们的库:


 $ gcc -fPIC --shared syscall-handler.c -o syscall-handler.so $ LD_PRELOAD=syscall-handler.so ls ERROR: ld.so: object 'syscall-handler.so' from LD_PRELOAD cannot be preloaded (cannot open shared object file): ignored. article.md example.c syscall-handler.c syscall-handler.so $ LD_PRELOAD=./syscall-handler.so ls article.md example.c syscall-handler.c syscall-handler.so 

如您所见,至少在我的系统上,您需要指定库的路径。 虽然相对,但是方式。 引导加载程序警告该错误很好。 在第二种情况下,一切似乎正常。


侦错


我们如何调试系统调用? 当然,您可以通过gdb中的catch syscall ,但是在这种情况下(老实说,在大多数情况下),出色的strace工具将帮助我们:


 strace -E LD_PRELOAD=./syscall-handler.so ls 

-E参数指示您需要为正在研究的过程设置指定的变量。 否则,有必要将调试后的库加载到调试器本身中(从一般角度来看)。


输出轨迹
 $ strace -E LD_PRELOAD=./syscall-handler.so ls execve("/bin/ls", ["ls"], 0x5652b17024d0 /* 61 vars */) = 0 brk(NULL) = 0x55a2f556d000 arch_prctl(0x3001 /* ARCH_??? */, 0x7fffe8e949b0) = -1 EINVAL ( ) openat(AT_FDCWD, "./syscall-handler.so", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0 \21\0\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0775, st_size=16504, ...}) = 0 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f29f6baf000 getcwd("/home/trosinenko/some/path", 128) = 63 mmap(NULL, 16480, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f29f6baa000 mmap(0x7f29f6bab000, 4096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1000) = 0x7f29f6bab000 mmap(0x7f29f6bac000, 4096, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7f29f6bac000 mmap(0x7f29f6bad000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7f29f6bad000 close(3) = 0 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (    ) openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=254851, ...}) = 0 mmap(NULL, 254851, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f29f6b6b000 close(3) = 0 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300p\0\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0644, st_size=163240, ...}) = 0 mmap(NULL, 174640, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f29f6b40000 mprotect(0x7f29f6b46000, 135168, PROT_NONE) = 0 mmap(0x7f29f6b46000, 102400, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6000) = 0x7f29f6b46000 mmap(0x7f29f6b5f000, 28672, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1f000) = 0x7f29f6b5f000 mmap(0x7f29f6b67000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x26000) = 0x7f29f6b67000 mmap(0x7f29f6b69000, 6704, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f29f6b69000 close(3) = 0 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360r\2\0\0\0\0\0"..., 832) = 832 lseek(3, 64, SEEK_SET) = 64 read(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784) = 784 lseek(3, 848, SEEK_SET) = 848 read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32 lseek(3, 880, SEEK_SET) = 880 read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0!U\364U\255V\275\207\34\202%\274\312\205\356%"..., 68) = 68 fstat(3, {st_mode=S_IFREG|0755, st_size=2025032, ...}) = 0 lseek(3, 64, SEEK_SET) = 64 read(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784) = 784 lseek(3, 848, SEEK_SET) = 848 read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32 lseek(3, 880, SEEK_SET) = 880 read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0!U\364U\255V\275\207\34\202%\274\312\205\356%"..., 68) = 68 mmap(NULL, 2032984, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f29f694f000 mmap(0x7f29f6974000, 1540096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7f29f6974000 mmap(0x7f29f6aec000, 303104, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19d000) = 0x7f29f6aec000 mmap(0x7f29f6b36000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e6000) = 0x7f29f6b36000 mmap(0x7f29f6b3c000, 13656, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f29f6b3c000 close(3) = 0 openat(AT_FDCWD, "/usr/lib/x86_64-linux-gnu/libpcre2-8.so.0", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\200!\0\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0644, st_size=539176, ...}) = 0 mmap(NULL, 541448, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f29f68ca000 mmap(0x7f29f68cc000, 376832, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7f29f68cc000 mmap(0x7f29f6928000, 151552, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x5e000) = 0x7f29f6928000 mmap(0x7f29f694d000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x82000) = 0x7f29f694d000 close(3) = 0 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0 \22\0\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0644, st_size=18816, ...}) = 0 mmap(NULL, 20752, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f29f68c4000 mmap(0x7f29f68c5000, 8192, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1000) = 0x7f29f68c5000 mmap(0x7f29f68c7000, 4096, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3000) = 0x7f29f68c7000 mmap(0x7f29f68c8000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3000) = 0x7f29f68c8000 close(3) = 0 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360\201\0\0\0\0\0\0"..., 832) = 832 lseek(3, 824, SEEK_SET) = 824 read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\09V\4W\221\35\226\215\236\6\10\215\240\25\227\v"..., 68) = 68 fstat(3, {st_mode=S_IFREG|0755, st_size=158288, ...}) = 0 lseek(3, 824, SEEK_SET) = 824 read(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\09V\4W\221\35\226\215\236\6\10\215\240\25\227\v"..., 68) = 68 mmap(NULL, 140448, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f29f68a1000 mmap(0x7f29f68a8000, 69632, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x7000) = 0x7f29f68a8000 mmap(0x7f29f68b9000, 20480, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x18000) = 0x7f29f68b9000 mmap(0x7f29f68be000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c000) = 0x7f29f68be000 mmap(0x7f29f68c0000, 13472, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f29f68c0000 close(3) = 0 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f29f689f000 mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f29f689c000 arch_prctl(ARCH_SET_FS, 0x7f29f689c800) = 0 mprotect(0x7f29f6b36000, 12288, PROT_READ) = 0 mprotect(0x7f29f68be000, 4096, PROT_READ) = 0 mprotect(0x7f29f68c8000, 4096, PROT_READ) = 0 mprotect(0x7f29f694d000, 4096, PROT_READ) = 0 mprotect(0x7f29f6b67000, 4096, PROT_READ) = 0 mprotect(0x7f29f6bad000, 4096, PROT_READ) = 0 mprotect(0x55a2f4670000, 4096, PROT_READ) = 0 mprotect(0x7f29f6bdd000, 4096, PROT_READ) = 0 munmap(0x7f29f6b6b000, 254851) = 0 set_tid_address(0x7f29f689cad0) = 31949 set_robust_list(0x7f29f689cae0, 24) = 0 rt_sigaction(SIGRTMIN, {sa_handler=0x7f29f68a8c50, sa_mask=[], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7f29f68b6540}, NULL, 8) = 0 rt_sigaction(SIGRT_1, {sa_handler=0x7f29f68a8cf0, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART|SA_SIGINFO, sa_restorer=0x7f29f68b6540}, NULL, 8) = 0 rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0 prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0 statfs("/sys/fs/selinux", 0x7fffe8e94900) = -1 ENOENT (    ) statfs("/selinux", 0x7fffe8e94900) = -1 ENOENT (    ) brk(NULL) = 0x55a2f556d000 brk(0x55a2f558e000) = 0x55a2f558e000 openat(AT_FDCWD, "/proc/filesystems", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0 read(3, "nodev\tsysfs\nnodev\ttmpfs\nnodev\tbd"..., 1024) = 425 read(3, "", 1024) = 0 close(3) = 0 access("/etc/selinux/config", F_OK) = -1 ENOENT (    ) rt_sigaction(SIGSYS, {sa_handler=0x7f29f6bab1ff, sa_mask=[], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7f29f6995470}, NULL, 8) = 0 prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) = 0 seccomp(SECCOMP_SET_MODE_FILTER, 0, {len=4, filter=0x7fffe8e94930}) = 0 openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 257 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a6579c, si_syscall=__NR_openat, si_arch=AUDIT_ARCH_X86_64} --- openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 rt_sigreturn({mask=[]}) = 3 fstat(3, {st_mode=000, st_size=0, ...}) = 5 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a5f7b9, si_syscall=__NR_fstat, si_arch=AUDIT_ARCH_X86_64} --- fstat(3, {st_mode=S_IFREG|0644, st_size=8994080, ...}) = 0 rt_sigreturn({mask=[]}) = 0 mmap(NULL, 8994080, PROT_READ, MAP_PRIVATE, 3, 0) = 0x9 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a6aaf6, si_syscall=__NR_mmap, si_arch=AUDIT_ARCH_X86_64} --- mmap(NULL, 8994080, PROT_READ, MAP_PRIVATE, 3, 0x12345678) = -1 EINVAL ( ) rt_sigreturn({mask=[]}) = -1 EPERM (  ) close(3) = 3 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a655bb, si_syscall=__NR_close, si_arch=AUDIT_ARCH_X86_64} --- close(3) = 0 rt_sigreturn({mask=[]}) = 0 openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 257 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a6579c, si_syscall=__NR_openat, si_arch=AUDIT_ARCH_X86_64} --- openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3 rt_sigreturn({mask=[]}) = 3 fstat(3, {st_mode=037, st_size=0, ...}) = 5 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a5f7b9, si_syscall=__NR_fstat, si_arch=AUDIT_ARCH_X86_64} --- fstat(3, {st_mode=S_IFREG|0644, st_size=2995, ...}) = 0 rt_sigreturn({mask=[]}) = 0 read(3, "", 4096) = 0 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a658d8, si_syscall=__NR_read, si_arch=AUDIT_ARCH_X86_64} --- read(3, "# Locale name alias data base.\n#"..., 4096) = 2995 rt_sigreturn({mask=[]}) = 2995 read(3, "", 4096) = 0 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a658d8, si_syscall=__NR_read, si_arch=AUDIT_ARCH_X86_64} --- read(3, "", 4096) = 0 rt_sigreturn({mask=[]}) = 0 close(3) = 3 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a655bb, si_syscall=__NR_close, si_arch=AUDIT_ARCH_X86_64} --- close(3) = 0 rt_sigreturn({mask=[]}) = 0 openat(AT_FDCWD, "/usr/lib/locale/ru_RU.UTF-8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = 257 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a6579c, si_syscall=__NR_openat, si_arch=AUDIT_ARCH_X86_64} --- openat(AT_FDCWD, "/usr/lib/locale/ru_RU.UTF-8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = -1 ENOENT (    ) rt_sigreturn({mask=[]}) = -1 EPERM (  ) openat(AT_FDCWD, "/usr/lib/locale/ru_RU.utf8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = 257 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a6579c, si_syscall=__NR_openat, si_arch=AUDIT_ARCH_X86_64} --- openat(AT_FDCWD, "/usr/lib/locale/ru_RU.utf8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = -1 ENOENT (    ) rt_sigreturn({mask=[]}) = -1 EPERM (  ) openat(AT_FDCWD, "/usr/lib/locale/ru_RU/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = 257 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a6579c, si_syscall=__NR_openat, si_arch=AUDIT_ARCH_X86_64} --- openat(AT_FDCWD, "/usr/lib/locale/ru_RU/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = -1 ENOENT (    ) rt_sigreturn({mask=[]}) = -1 EPERM (  ) openat(AT_FDCWD, "/usr/lib/locale/ru.UTF-8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = 257 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a6579c, si_syscall=__NR_openat, si_arch=AUDIT_ARCH_X86_64} --- openat(AT_FDCWD, "/usr/lib/locale/ru.UTF-8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = -1 ENOENT (    ) rt_sigreturn({mask=[]}) = -1 EPERM (  ) openat(AT_FDCWD, "/usr/lib/locale/ru.utf8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = 257 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a6579c, si_syscall=__NR_openat, si_arch=AUDIT_ARCH_X86_64} --- openat(AT_FDCWD, "/usr/lib/locale/ru.utf8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = -1 ENOENT (    ) rt_sigreturn({mask=[]}) = -1 EPERM (  ) openat(AT_FDCWD, "/usr/lib/locale/ru/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = 257 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a6579c, si_syscall=__NR_openat, si_arch=AUDIT_ARCH_X86_64} --- openat(AT_FDCWD, "/usr/lib/locale/ru/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = -1 ENOENT (    ) rt_sigreturn({mask=[]}) = -1 EPERM (  ) ioctl(1, TCGETS, {B4000000 opost -isig icanon -echo ...}) = 16 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a65cea, si_syscall=__NR_ioctl, si_arch=AUDIT_ARCH_X86_64} --- ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0 rt_sigreturn({mask=[]}) = 0 ioctl(1, TIOCGWINSZ, {ws_row=45567, ws_col=63162, ws_xpixel=32553, ws_ypixel=0}) = 16 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a6667b, si_syscall=__NR_ioctl, si_arch=AUDIT_ARCH_X86_64} --- ioctl(1, TIOCGWINSZ, {ws_row=58, ws_col=271, ws_xpixel=0, ws_ypixel=0}) = 0 rt_sigreturn({mask=[]}) = 0 openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 257 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a6579c, si_syscall=__NR_openat, si_arch=AUDIT_ARCH_X86_64} --- openat(AT_FDCWD, ".", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = 3 rt_sigreturn({mask=[]}) = 3 fstat(3, {st_mode=037777777777, st_size=139818209035479, ...}) = 5 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a5f7b9, si_syscall=__NR_fstat, si_arch=AUDIT_ARCH_X86_64} --- fstat(3, {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0 rt_sigreturn({mask=[]}) = 0 getdents64(3, /* d_reclen < offsetof(struct dirent64, d_name) */ /* 0 entries */, 32768) = 217 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a3007b, si_syscall=__NR_getdents64, si_arch=AUDIT_ARCH_X86_64} --- getdents64(3, /* 7 entries */, 32768) = 232 rt_sigreturn({mask=[]}) = 232 getdents64(3, /* 7 entries */, 32768) = 217 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a3007b, si_syscall=__NR_getdents64, si_arch=AUDIT_ARCH_X86_64} --- getdents64(3, /* 0 entries */, 32768) = 0 rt_sigreturn({mask=[]}) = 0 close(3) = 3 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a655bb, si_syscall=__NR_close, si_arch=AUDIT_ARCH_X86_64} --- close(3) = 0 rt_sigreturn({mask=[]}) = 0 fstat(1, {st_mode=000, st_size=0, ...}) = 5 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a5f7b9, si_syscall=__NR_fstat, si_arch=AUDIT_ARCH_X86_64} --- fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(0x88, 0x7), ...}) = 0 rt_sigreturn({mask=[]}) = 0 write(1, "article.md example.c syscall-h"..., 61) = 1 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a60317, si_syscall=__NR_write, si_arch=AUDIT_ARCH_X86_64} --- write(1, "article.md example.c syscall-h"..., 61article.md example.c syscall-handler.c syscall-handler.so ) = 61 rt_sigreturn({mask=[]}) = 61 close(1) = 3 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a655bb, si_syscall=__NR_close, si_arch=AUDIT_ARCH_X86_64} --- close(1) = 0 rt_sigreturn({mask=[]}) = 0 close(2) = 3 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a655bb, si_syscall=__NR_close, si_arch=AUDIT_ARCH_X86_64} --- close(2) = 0 rt_sigreturn({mask=[]}) = 0 exit_group(0) = 231 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a34fe6, si_syscall=__NR_exit_group, si_arch=AUDIT_ARCH_X86_64} --- exit_group(0) = ? +++ exited with 0 +++ 

(-, userspace), - , ...


 ... rt_sigaction(SIGSYS, {sa_handler=0x7f29f6bab1ff, sa_mask=[], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7f29f6995470}, NULL, 8) = 0 prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) = 0 seccomp(SECCOMP_SET_MODE_FILTER, 0, {len=4, filter=0x7fffe8e94930}) = 0 openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 257 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a6579c, si_syscall=__NR_openat, si_arch=AUDIT_ARCH_X86_64} --- openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 rt_sigreturn({mask=[]}) = 3 fstat(3, {st_mode=000, st_size=0, ...}) = 5 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a5f7b9, si_syscall=__NR_fstat, si_arch=AUDIT_ARCH_X86_64} --- fstat(3, {st_mode=S_IFREG|0644, st_size=8994080, ...}) = 0 rt_sigreturn({mask=[]}) = 0 mmap(NULL, 8994080, PROT_READ, MAP_PRIVATE, 3, 0) = 0x9 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a6aaf6, si_syscall=__NR_mmap, si_arch=AUDIT_ARCH_X86_64} --- mmap(NULL, 8994080, PROT_READ, MAP_PRIVATE, 3, 0x12345678) = -1 EINVAL ( ) rt_sigreturn({mask=[]}) = -1 EPERM (  ) close(3) = 3 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a655bb, si_syscall=__NR_close, si_arch=AUDIT_ARCH_X86_64} --- close(3) = 0 rt_sigreturn({mask=[]}) = 0 openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 257 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a6579c, si_syscall=__NR_openat, si_arch=AUDIT_ARCH_X86_64} --- openat(AT_FDCWD, "/usr/share/locale/locale.alias", O_RDONLY|O_CLOEXEC) = 3 rt_sigreturn({mask=[]}) = 3 fstat(3, {st_mode=037, st_size=0, ...}) = 5 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a5f7b9, si_syscall=__NR_fstat, si_arch=AUDIT_ARCH_X86_64} --- fstat(3, {st_mode=S_IFREG|0644, st_size=2995, ...}) = 0 rt_sigreturn({mask=[]}) = 0 read(3, "", 4096) = 0 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f29f6a658d8, si_syscall=__NR_read, si_arch=AUDIT_ARCH_X86_64} --- read(3, "# Locale name alias data base.\n#"..., 4096) = 2995 ... 

, , — SIGSYS , . , , fstat : — !


...


, - . - : openat , libc : handle_syscall


  if (num == SYS_openat) { fprintf(stderr, "openat: %s\n", (const char *)arg2); } 

:


 $ gcc -fPIC --shared syscall-handler.c -o syscall-handler.so $ LD_PRELOAD=./syscall-handler.so ls    $ strace -E LD_PRELOAD=./syscall-handler.so ls ... rt_sigaction(SIGSYS, {sa_handler=0x7f55ef2cb24e, sa_mask=[], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7f55ef0b5470}, NULL, 8) = 0 prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) = 0 seccomp(SECCOMP_SET_MODE_FILTER, 0, {len=4, filter=0x7ffca47b36e0}) = 0 openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 257 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f55ef18579c, si_syscall=__NR_openat, si_arch=AUDIT_ARCH_X86_64} --- write(2, "openat: /usr/lib/locale/locale-a"..., 39) = 1 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7f55ef180317, si_syscall=__NR_write, si_arch=AUDIT_ARCH_X86_64} --- +++ killed by SIGSYS +++    

: SA_NODEFER , SIGSYS , deadlock. initialize_handler :


  sig.sa_flags = SA_SIGINFO | SA_NODEFER; 

 $ LD_PRELOAD=./syscall-handler.so ls openat: /usr/lib/locale/locale-archive openat: /usr/share/locale/locale.alias openat: /usr/lib/locale/ru_RU.UTF-8/LC_IDENTIFICATION openat: /usr/lib/locale/ru_RU.utf8/LC_IDENTIFICATION openat: /usr/lib/locale/ru_RU/LC_IDENTIFICATION openat: /usr/lib/locale/ru.UTF-8/LC_IDENTIFICATION openat: /usr/lib/locale/ru.utf8/LC_IDENTIFICATION openat: /usr/lib/locale/ru/LC_IDENTIFICATION openat: . article.md example.c syscall-handler.c syscall-handler.so 

...


, . mmap :) , , - .


example.c:


 #include <stdio.h> #include <stdlib.h> int main() { fprintf(stderr, "Allocating 1MB of memory\n"); void *ptr = malloc(1 << 20); fprintf(stderr, "Allocated: %p\n", ptr); } 

 $ LD_PRELOAD=./syscall-handler.so ./example Allocating 1MB of memory Allocated: 0x564fc07012a0 

… ?!?


 $ strace -E LD_PRELOAD=./syscall-handler.so ./example ... rt_sigaction(SIGSYS, {sa_handler=0x7fd7065cd24e, sa_mask=[], sa_flags=SA_RESTORER|SA_NODEFER|SA_SIGINFO, sa_restorer=0x7fd7063e2470}, NULL, 8) = 0 prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) = 0 seccomp(SECCOMP_SET_MODE_FILTER, 0, {len=4, filter=0x7fff8ea97810}) = 0 write(2, "Allocating 1MB of memory\n", 25) = 1 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7fd7064ad317, si_syscall=__NR_write, si_arch=AUDIT_ARCH_X86_64} --- write(2, "Allocating 1MB of memory\n", 25Allocating 1MB of memory ) = 25 rt_sigreturn({mask=[]}) = 25 brk(NULL) = 0xc --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7fd7064b355b, si_syscall=__NR_brk, si_arch=AUDIT_ARCH_X86_64} --- brk(NULL) = 0x55e31f74f000 rt_sigreturn({mask=[]}) = 94433973694464 brk(0x55e31f770000) = 0xc --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7fd7064b355b, si_syscall=__NR_brk, si_arch=AUDIT_ARCH_X86_64} --- brk(0x55e31f770000) = 0x55e31f770000 rt_sigreturn({mask=[]}) = 94433973829632 mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x9 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7fd7064b7af6, si_syscall=__NR_mmap, si_arch=AUDIT_ARCH_X86_64} --- mmap(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0x12345678) = -1 EINVAL ( ) rt_sigreturn({mask=[]}) = -1 EPERM (  ) brk(0x55e31f870000) = 0xc --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7fd7064b355b, si_syscall=__NR_brk, si_arch=AUDIT_ARCH_X86_64} --- brk(0x55e31f870000) = 0x55e31f870000 rt_sigreturn({mask=[]}) = 94433974878208 write(2, "Allocated: 0x55e31f74f2a0\n", 26) = 1 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7fd7064ad317, si_syscall=__NR_write, si_arch=AUDIT_ARCH_X86_64} --- write(2, "Allocated: 0x55e31f74f2a0\n", 26Allocated: 0x55e31f74f2a0 ) = 26 rt_sigreturn({mask=[]}) = 26 exit_group(0) = 231 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0x7fd706481fe6, si_syscall=__NR_exit_group, si_arch=AUDIT_ARCH_X86_64} --- exit_group(0) = ? +++ exited with 0 +++ 

: mmap , libc brk . ...


 #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <stdio.h> #include <stdlib.h> int main() { fprintf(stderr, "Allocating 1MB of memory\n"); void *ptr = malloc(1 << 20); fprintf(stderr, "Allocated: %p\n", ptr); const char *fname = "test.bin"; int fd = open(fname, O_RDONLY); fprintf(stderr, "Mapping first 1MB of %s\n", fname); void *ptr2 = mmap(NULL, 1 << 20, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, fd, 0); fprintf(stderr, "Mapped: %p\n", ptr2); return 0; } 

 $ gcc example.c -o example $ ./example Allocating 1MB of memory Allocated: 0x7f1aa7d09010 Mapping first 1MB of test.bin Mapped: 0x7f1aa7c09000 $ LD_PRELOAD=./syscall-handler.so ./example Allocating 1MB of memory Allocated: 0x556a51df52a0 openat: test.bin Mapping first 1MB of test.bin Mapped: 0xffffffffffffffff 

«! — ...» 0xffffffffffffffff , -1 , MAP_FAILED .


, mmap , :


 #define ALLOW(sys) \ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), \ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K , sys, 0, 1), \ BPF_STMT(BPF_RET | BPF_K , SECCOMP_RET_ALLOW), struct sock_filter filt[] = { BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, args[5]))), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K , MARKER, 0, 1), BPF_STMT(BPF_RET | BPF_K , SECCOMP_RET_ALLOW), ALLOW(SYS_mmap) BPF_STMT(BPF_RET | BPF_K , SECCOMP_RET_TRAP), }; 

:


 $ LD_PRELOAD=./syscall-handler.so ./example Allocating 1MB of memory Allocated: 0x7fad45a6f010 openat: test.bin Mapping first 1MB of test.bin Mapped: 0x7fad4596f000 

 #define _GNU_SOURCE #include <errno.h> #include <stddef.h> #include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <unistd.h> #include <linux/audit.h> #include <linux/filter.h> #include <linux/seccomp.h> #include <sys/prctl.h> #include <unistd.h> #include <syscall.h> #include <signal.h> #include <string.h> uint64_t handle_syscall(uint32_t num, uint32_t *drop_syscall, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6) { if (num == SYS_openat) { fprintf(stderr, "openat: %s\n", (const char *)arg2); } return 0; } #define MARKER 0x12345678 static int in_handler; static void handle_sigsys(int num, siginfo_t *si, void *arg) { ucontext_t *ctx = arg; greg_t *gregs = ctx->uc_mcontext.gregs; uint32_t drop = 0; uint64_t res; if (!in_handler) { in_handler = 1; res = handle_syscall(gregs[REG_RAX], &drop, gregs[REG_RDI], gregs[REG_RSI], gregs[REG_RDX], gregs[REG_R10], gregs[REG_R8], gregs[REG_R9]); in_handler = 0; } if (!drop) { res = syscall(gregs[REG_RAX], gregs[REG_RDI], gregs[REG_RSI], gregs[REG_RDX], gregs[REG_R10], gregs[REG_R8], MARKER); } gregs[REG_RAX] = res; } void initialize_handler(void) { #define ALLOW(sys) \ BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), \ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K , sys, 0, 1), \ BPF_STMT(BPF_RET | BPF_K , SECCOMP_RET_ALLOW), struct sock_filter filt[] = { BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, args[5]))), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K , MARKER, 0, 1), BPF_STMT(BPF_RET | BPF_K , SECCOMP_RET_ALLOW), ALLOW(SYS_mmap) BPF_STMT(BPF_RET | BPF_K , SECCOMP_RET_TRAP), }; struct sock_fprog prog = { sizeof(filt) / sizeof(filt[0]), filt }; struct sigaction sig; memset(&sig, 0, sizeof(sig)); sig.sa_sigaction = handle_sigsys; sig.sa_flags = SA_SIGINFO | SA_NODEFER; sigaction(SIGSYS, &sig, NULL); prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER, 0, &prog); } static void __attribute__((constructor))constr(void) { initialize_handler(); } 

Source: https://habr.com/ru/post/zh-CN469267/


All Articles