Системно извикване на 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 

Чудя се.. защо има отместване -0x4 в 49: R_X86_64_PC32 path-0x4?

Искам да кажа: режимът и разработката трябва да се разрешават автоматично без проблеми, но какво да кажем за пътя? Защо отместването -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
сегментационна грешка, по дяволите. Както и да е, мисля, че си прав, случват се много неща и трябва да прочета цялата рутина на syscall, за да разбера какво не е наред. Наистина много време. - person paulAl; 19.03.2012
comment
съжалявам, дадох ти грешен линк по-горе. трябва да се коригира сега. Също така бих погледнал псевдокода в спецификацията на AMD за инструкцията за syscall тук на страница 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 stub използва този трик

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