3

カーネル モジュールからシステム コールを呼び出そうとしています。次のコードがあります。

    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 path-0x4 に -0x4 オフセットがあるのはなぜですか?

つまり、mode と dev は問題なく自動的に解決されるはずですが、パスはどうでしょうか。なぜ -0x4 オフセットなのですか?

私はそれを「補う」ことを試みました

lea 0x0(%rip),%rdi // これはどういうわけか -0x4 オフセットを追加します add $0x4, %rdi ....

しかし、コードはまだクラッシュしました。

どこが間違っていますか?

4

2 に答える 2

0

ここで何が起こっているかについての私の推測は、スタックの問題です。とは異なりint $0x80syscall命令はカーネルのスタックをセットアップしません。からの実際のコードを見ると、のsystem_call:ようなものが表示されますSWAPGS_UNSAFE_STACK。このマクロの要点は、SwapGS命令です。152ページを参照してください。カーネルモードに入ると、カーネルはそのデータ構造へのポインタをプルする方法を必要とします。この命令により、カーネルはこれを正確に実行できます。これは、ユーザー%gsレジスタをモデル固有のレジスタに保存されている値と交換することによって行われます。この値から、カーネルモードスタックをプルできます。

syscallエントリポイントが呼び出されると、すでにカーネルモードになっているため、このスワップが間違った値を生成し、カーネルが偽のスタックを使用しようとし始めることを想像できます。SwapGSを手動で呼び出して、カーネルのSwapGSが期待どおりの結果になるようにし、それが機能するかどうかを確認してみてください。

于 2012-03-19T05:38:59.513 に答える
0

そんな風にはできないようです。前のコメントを参照してください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スタブはそのトリックを使用しています

于 2012-03-18T19:48:17.470 に答える