Системный вызов Linux из-за сбоя ядра (странное смещение) - PullRequest
3 голосов
/ 18 марта 2012

Я пытаюсь вызвать системный вызов из модуля ядра, у меня есть этот код:

    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 

Мне интересно ... Почему в 49-Rx_x86_64_PC32 path-0x4 есть смещение -0x4?1009 *

Я имею в виду: mode и dev должны разрешаться автоматически без проблем, но как насчет пути?Почему смещение -0x4?

Я пытался "компенсировать это" с помощью

lea 0x0 (% rip),% rdi // это как-то добавляет смещение -0x4, добавляет $ 0x4,% rdi....

но код все еще не работает.

Где я ошибаюсь?

Ответы [ 2 ]

0 голосов
/ 19 марта 2012

Мое предположение относительно того, что здесь происходит, является проблемой стека. В отличие от int $0x80, инструкция syscall не будет устанавливать стек для ядра. Если вы посмотрите на реальный код из system_call:, вы увидите что-то вроде SWAPGS_UNSAFE_STACK. В основе этого макроса лежит инструкция SwapGS - см. Стр. 152 здесь . При входе в режим ядра ядру необходим способ получить указатель на его структуры данных, и эта инструкция позволяет ему сделать именно это. Это происходит путем замены пользовательского регистра %gs на значение, сохраненное в регистре конкретной модели, из которого он может затем извлечь стек режима ядра.

Вы можете себе представить, что как только точка входа syscall вызвана, этот своп производит неправильное значение, так как вы уже были в режиме ядра, и ядро ​​начинает пытаться использовать поддельный стек. Вы могли бы попытаться вызвать SwapGS вручную, чтобы ядро ​​получило результат SwapGS, что и ожидалось, и посмотреть, работает ли это.

0 голосов
/ 18 марта 2012

Кажется, что вы не можете сделать это таким образом. См. комментарий до system_call:

 /*
  * Register setup:
  * rax  system call number
  * rdi  arg0
  * rcx  return address for syscall/sysret, C arg3
  * rsi  arg1
  * rdx  arg2
  * r10  arg3    (--> moved to rcx for C)
  * r8   arg4
  * r9   arg5
  * r11  eflags for syscall/sysret, temporary for C
  * r12-r15,rbp,rbx saved by C code, not touched.
  *
  * Interrupts are off on entry.
  * Only called from user space.
  *
  * XXX  if we had a free scratch register we could save the RSP into the stack frame
  *      and report it properly in ps. Unfortunately we haven't.
  *
  * When user can change the frames always force IRET. That is because
  * it deals with uncanonical addresses better. SYSRET has trouble
  * with them due to bugs in both AMD and Intel CPUs.
  */

Итак, вы не можете вызвать syscall из ядра. Но вы можете попытаться использовать int $0x80 для этих целей. На мой взгляд, заглушка kernel_execve использует этот трюк

...