在Linux内核4.6或更高版本上挂钩sys_execve

时间:2017-11-04 21:27:06

标签: c linux-kernel hook

低于4.6的内核使用程序集存根来加强对关键系统调用的挂钩,例如fork,clone,exec等。特别是对于execve,来自Kernel-4.5的以下片段显示了execve的入口存根:

ENTRY(stub_execve)
    call    sys_execve
return_from_execve:
 ... 
END(stub_execve)

系统call table包含此存根的地址,此存根进一步调用原始execve。因此,要在这个环境中挂钩execve,我们需要在我们的挂钩例程中修补存根中的call sys_execve,并在完成我们想要的事情之后调用原始的execve。这一切都可以在execmon中看到,这是一个用于linux的流程执行监控实用程序。我已经使用内核4.4测试了execmon在Ubuntu 16.04中的成功工作。

从内核4.6开始,关键呼叫保护的上层方案已经改变。现在存根看起来像:

ENTRY(ptregs_\func)
    leaq    \func(%rip), %rax
    jmp     stub_ptregs_64
END(ptregs_\func)

其中\func将扩展为sys_execve以进行execve调用。同样,系统call table包含此存根,此存根调用原始execve,但现在以更安全的方式而不是仅执行call sys_execve。 这个较新的存根,在RAX寄存器中存储调用函数的地址,并跳转到下面显示的另一个存根(删除注释):

 ENTRY(stub_ptregs_64)
     cmpq   $.Lentry_SYSCALL_64_after_fastpath_call, (%rsp)
     jne    1f

     DISABLE_INTERRUPTS(CLBR_NONE)
     TRACE_IRQS_OFF
     popq   %rax
     jmp    entry_SYSCALL64_slow_path

 1:
     jmp    *%rax        /* called from C */
 END(stub_ptregs_64)

请查看this,查看此存根中的注释和其他引用标签。

我努力想出一些逻辑来克服这种保护并用挂钩函数修补原始调用,但还没有成功。 有人愿意和我一起帮忙摆脱它。

1 个答案:

答案 0 :(得分:0)

我完全不明白你从哪里采取安全角度。

func的先前和当前都没有“硬化”。

你从来没有说明为什么要挂钩execve。

标准挂钩机制是使用kprobes,您可以检查systemtap以获取示例消费者。

我看了上面提到的'execmon'代码,我发现它质量很差,不适合学习。例如https://github.com/kfiros/execmon/blob/master/kmod/syscalls.c#L65

  • 直接访问用户空间内存(没有get_user,copy_from_user等)
  • 两次。首先它计算长度(未绑定!),然后复制内容。特别是如果有人在复合后使字符串更长,但在复制之前,这会触发缓冲区溢出。