c - 来自内核崩溃的 Linux 系统调用(奇怪的偏移量)

标签 c linux assembly linux-kernel att

我正在尝试从内核模块调用系统调用,我有以下代码:

    set_fs( get_ds() );    // lets our module do the system-calls 


    // Save everything before systemcalling

    asm ("     push    %rax     "); 
    asm  ("     push    %rdi     "); 
    asm  ("     push    %rcx     "); 
    asm  ("     push    %rsi     "); 
    asm  ("     push    %rdx     "); 
    asm  ("     push    %r10     "); 
    asm  ("     push    %r8      "); 
    asm  ("     push    %r9      "); 
    asm  ("     push    %r11     "); 
    asm  ("     push    %r12     "); 
    asm  ("     push    %r15     "); 
    asm  ("     push    %rbp     "); 
    asm  ("     push    %rbx     "); 


    // Invoke the long sys_mknod(const char __user *filename, int mode, unsigned dev);

    asm volatile ("     movq    $133, %rax     "); // system call number

    asm volatile ("    lea    path(%rip), %rdi     "); // path is char path[] = ".."

    asm volatile ("     movq    mode, %rsi     "); // mode is S_IFCHR | ...

    asm volatile ("     movq    dev, %rdx     ");  // dev is 70 >> 8

    asm volatile ("     syscall     "); 


      // POP EVERYTHING 

    asm ("     pop     %rbx     "); 
    asm ("     pop        %rbp     "); 
    asm ("     pop     %r15     "); 
    asm ("     pop        %r12     "); 
    asm ("     pop        %r11     "); 
    asm ("     pop        %r9      "); 
    asm ("     pop        %r8      "); 
    asm ("     pop        %r10     "); 
    asm ("     pop        %rdx     "); 
    asm ("     pop        %rsi     "); 
    asm ("     pop        %rcx     "); 
    asm ("     pop        %rdi     "); 
    asm ("     pop     %rax     "); 



    set_fs( savedFS );    // restore the former address-limit value 

此代码无法正常工作并导致系统崩溃(这是一个内核模块)。

带有重定位信息的那段代码的转储是:

  2c:    50                      push  %rax 
  2d:    57                      push  %rdi 
  2e:    51                      push  %rcx 
  2f:    56                      push  %rsi 
  30:    52                      push  %rdx 
  31:    41 52                    push  %r10 
  33:    41 50                    push  %r8 
  35:    41 51                    push  %r9 
  37:    41 53                    push  %r11 
  39:    41 54                    push  %r12 
  3b:    41 57                    push  %r15 
  3d:    55                      push  %rbp 
  3e:    53                      push  %rbx 
  3f:    48 c7 c0 85 00 00 00     mov    $0x85,%rax 
  46:    48 8d 3d 00 00 00 00     lea    0x0(%rip),%rdi        # 4d <init_module+0x4d> 
            49: R_X86_64_PC32    path-0x4 
  4d:    48 83 c7 04              add    $0x4,%rdi 
  51:    48 8b 34 25 00 00 00     mov    0x0,%rsi 
  58:    00 
            55: R_X86_64_32S    mode 
  59:    48 8b 14 25 00 00 00     mov    0x0,%rdx 
  60:    00 
            5d: R_X86_64_32S    dev 
  61:    0f 05                    syscall 
  63:    5b                      pop    %rbx 
  64:    5d                      pop    %rbp 
  65:    41 5f                    pop    %r15 
  67:    41 5c                    pop    %r12 
  69:    41 5b                    pop    %r11 
  6b:    41 59                    pop    %r9 
  6d:    41 58                    pop    %r8 
  6f:    41 5a                    pop    %r10 
  71:    5a                      pop    %rdx 
  72:    5e                      pop    %rsi 
  73:    59                      pop    %rcx 
  74:    5f                      pop    %rdi 
  75:    58                      pop    %rax 

我想知道.. 为什么有一个 -0x4 的偏移量 49: R_X86_64_PC32 路径-0x4 ?

我的意思是:mode和dev应该是自动解析的,没有问题,但是路径呢?为什么偏移量为 -0x4?

我试图用

来“补偿它”

lea 0x0(%rip),%rdi//这会以某种方式添加一个 -0x4 偏移量 添加 $0x4, %rdi ....

但代码仍然崩溃。

我哪里错了?

最佳答案

我猜这里发生的是堆栈问题。与 int $0x80 不同,syscall 指令不会为内核设置堆栈。如果您查看 system_call: 中的实际代码,您会看到类似于 SWAPGS_UNSAFE_STACK 的内容。该宏的核心是 SwapGS 指令 - 请参见第 152 页 here .当进入内核模式时,内核需要一种方法来拉取指向其数据结构的指针,而这条指令正是让它做到这一点。它通过将用户 %gs 寄存器与保存在模型特定寄存器中的值交换来实现,然后它可以从中提取内核模式堆栈。

您可以想象,一旦 syscall 入口点被调用,此交换将产生错误的值,因为您已经处于内核模式,并且内核开始尝试使用伪造的堆栈。您可以尝试手动调用 SwapGS,使内核的 SwapGS 结果达到预期的结果,然后看看是否有效。

关于c - 来自内核崩溃的 Linux 系统调用(奇怪的偏移量),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9758869/

相关文章:

c - 给定 C 代码的堆栈图

assembly - 我无法在链接描述文件中指定 Rust 程序的起始偏移量是有原因的吗?

将结构转换为字节数组并存储在数据库中。读取 db 并获取字节数组以在 C 中重新创建结构

C 中的常量值

linux - CentOS 上 Proftpd 登录失败

linux - kubernetes 服务在大约后暴露 shellinabox 超时。 60秒

assembly - 如何从 4 位十六进制转换为 7 位 ASCII?

c - 使用 sigaction() 实现 siginterrupt()?

命令行参数可用于其他函数吗?

linux - 如何在clearcase vob中实现 "cp -u"功能?