Системный вызов Linux из-за сбоя ядра (странное смещение)

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

    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: R_X86_64_PC32-0x4 есть смещение -0x4?

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

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

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

но код все равно завис.

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


person paulAl    schedule 18.03.2012    source источник
comment
Вы не можете вызвать системный вызов из ядра. Ядро обеспечивает системные вызовы приложений. Что вы хотите сделать на самом деле? Разве вы не можете избежать работы в стране ядра?   -  person Basile Starynkevitch    schedule 18.03.2012
comment
Вот почему я поставил set_fs(get_ds()); это должно увеличить лимит сегмента, который может вызывать системные вызовы. Это упражнение для экзамена (cs.usfca.edu/~cruse/cs635) поэтому мне нужно выяснить, как это сделать с amd64   -  person paulAl    schedule 18.03.2012
comment
Из комментария к соглашению о вызовах syscall: rcx return address for syscall/sysret, C arg3.   -  person Ilya Matveychikov    schedule 19.03.2012


Ответы (2)


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

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

person kch    schedule 19.03.2012
comment
ошибка сегментации, блин. В любом случае, я думаю, что вы правы, происходит много всего, и я должен прочитать всю подпрограмму системных вызовов, чтобы понять, что не так. Действительно много времени. - person paulAl; 19.03.2012
comment
Извините, я дал вам неправильную ссылку выше. должно быть исправлено сейчас. Я бы также посмотрел на псевдокод в спецификации AMD для инструкции системного вызова здесь на стр. 345. По крайней мере, это поможет вам понять, что linux делает в подпрограмме system_call. Кстати, что именно происходило, когда вы сказали, что он падает? Это заставило машину зависнуть? ядро напечатал опа? и т. д. Если это не зависание машины, вы можете попробовать запустить dmesg и найти что-то странное - person kch; 20.03.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 заглушка использует этот трюк

person Ilya Matveychikov    schedule 18.03.2012
comment
Могу ли я вызвать int 0x80 из 64-битной программы? Будет ли это работать? И мне нужно поместить 32-битный индекс системных вызовов в rax, не так ли? - person paulAl; 19.03.2012
comment
Оказывается, я НЕ МОГУ использовать int 0x80 в 64-битном модуле ядра. Мне интересно, есть ли какой-нибудь механизм защиты VA-откуда.. - person paulAl; 19.03.2012
comment
Зачем нужно делать syscall? Можешь попробовать позвонить sys_mknod напрямую?.. - person Ilya Matveychikov; 19.03.2012
comment
нет, sys_mknod не задокументирован, вы не должны использовать его, если вы не в пользовательском режиме - person paulAl; 19.03.2012
comment
Считаете ли вы, что вызов системного вызова из ядра — это хороший и задокументированный способ? - person Ilya Matveychikov; 19.03.2012