内核模块中的异常处理

时间:2015-07-26 20:55:40

标签: exception-handling linux-kernel ubuntu-14.04 kernel-module

在我的Linux 3.16模块代码中,在某些时候,我想转到错误处理例程,例如do_invalid_op [Linux codeline]。通过在内核模块中直接调用do_invalid_op,它会立即崩溃整个Linux系统,即使没有/var/log/kern.log中的跟踪(我也可以调试)。例如,

void module_begin(){
    ...
    if(error_found){
        do_invalid_op(reg, error_code); //expected to return control to user space without running "a=1" line.
    }
    int a = 1;
    ...
}

module_init(module_begin());

我的一般问题是如何在内核模块中转换为错误处理代码(中断处理程序)?

更新1:更新示例代码以反映我打算让模块执行的操作;一旦error_found,内核执行应该跳转到某个地方(例如用户空间)而不运行其余的模块初始化代码。

更新2:跟踪有关崩溃的信息,希望它有用

Entering the yyy!
Meaning of life: 41
Value of tcs: 0x19e5010
00400000-00401000 r-xp 00000000 08:01 304369                             /home/tom/workspace/coding/xxx-emulator-v2/TR/client/bin/a.out
00601000-00602000 r--p 00001000 08:01 304369                             /home/tom/workspace/coding/xxx-emulator-v2/TR/client/bin/a.out
00602000-00603000 rw-p 00002000 08:01 304369                             /home/tom/workspace/coding/xxx-emulator-v2/TR/client/bin/a.out
019e5000-01a07000 rw-p 00000000 00:00 0                                  [heap]
7f767aed5000-7f767aed6000 r-xp 00000000 08:01 304337                     /home/tom/workspace/coding/xxx-emulator-v2/TR/client/bin/yyy.so
7f767aed6000-7f767b0d5000 ---p 00001000 08:01 304337                     /home/tom/workspace/coding/xxx-emulator-v2/TR/client/bin/yyy.so
7f767b0d5000-7f767b0d6000 r--p 00000000 08:01 304337                     /home/tom/workspace/coding/xxx-emulator-v2/TR/client/bin/yyy.so
7f767b0d6000-7f767b0d7000 rw-p 00001000 08:01 304337                     /home/tom/workspace/coding/xxx-emulator-v2/TR/client/bin/yyy.so
7f767b0d7000-7f767b292000 r-xp 00000000 08:01 791296                     /lib/x86_64-linux-gnu/libc-2.19.so
7f767b292000-7f767b492000 ---p 001bb000 08:01 791296                     /lib/x86_64-linux-gnu/libc-2.19.so
7f767b492000-7f767b496000 r--p 001bb000 08:01 791296                     /lib/x86_64-linux-gnu/libc-2.19.so
7f767b496000-7f767b498000 rw-p 001bf000 08:01 791296                     /lib/x86_64-linux-gnu/libc-2.19.so
7f767b498000-7f767b49d000 rw-p 00000000 00:00 0 
7f767b49d000-7f767b4a0000 r-xp 00000000 08:01 791313                     /lib/x86_64-linux-gnu/libdl-2.19.so
7f767b4a0000-7f767b69f000 ---p 00003000 08:01 791313                     /lib/x86_64-linux-gnu/libdl-2.19.so
7f767b69f000-7f767b6a0000 r--p 00002000 08:01 791313                     /lib/x86_64-linux-gnu/libdl-2.19.so
7f767b6a0000-7f767b6a1000 rw-p 00003000 08:01 791313                     /lib/x86_64-linux-gnu/libdl-2.19.so
7f767b6a1000-7f767b6c4000 r-xp 00000000 08:01 791272                     /lib/x86_64-linux-gnu/ld-2.19.so
7f767b8aa000-7f767b8ad000 rw-p 00000000 00:00 0 
7f767b8c0000-7f767b8c3000 rw-p 00000000 00:00 0 
7f767b8c3000-7f767b8c4000 r--p 00022000 08:01 791272                     /lib/x86_64-linux-gnu/ld-2.19.so
7f767b8c4000-7f767b8c5000 rw-p 00023000 08:01 791272                     /lib/x86_64-linux-gnu/ld-2.19.so
7f767b8c5000-7f767b8c6000 rw-p 00000000 00:00 0 
7fff85cb4000-7fff85cd5000 rw-p 00000000 00:00 0                          [stack]
7fff85ce5000-7fff85ce7000 r-xp 00000000 00:00 0                          [vdso]
7fff85ce7000-7fff85ce9000 r--p 00000000 00:00 0                          [vvar]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
note: sections in order: .text, .rodata, .bss 
Inside Enclave now 
Killed


@dmesg
[   87.913346] Local XXX Handler Called from PID: 2877 EIP: 0x    400bfd
[   87.913349] Hooked an EENTER instruction.
[   87.913350] TT: Done hooking EENTER: rbx:00000000019e5010, rdx:00000000019e6020 
[   87.913353] Syscall inside Enclave hooked! NR=1, i=5 
[   87.913355]   Caller process: pid: 2877, tid: 2877, comm: a.out, 
[   87.913355]                           uid: 1000, gid: 1000, euid: 18446744069414585320 
[   87.913355]                           suid: 140144782869480, sgid: 1000, fsuid: 140144782869480, fsgid: 1000, user: 1000, 
[   87.913357]   Caller context: ret_addr: 00007f767b8aa740, filename to open():/proc/self/maps
[   87.913360] Syscall inside Enclave hooked! NR=2, i=6 
[   87.913362]   Caller process: pid: 2877, tid: 2877, comm: a.out, 
[   87.913362]                           uid: 1000, gid: 1000, euid: 18446612132314219496 
[   87.913362]                           suid: 18446744069414585320, sgid: 1000, fsuid: 1000, fsgid: 1000, user: 140144782869480, 
[   87.913364]   Caller context: ret_addr: 00007fff85cd35e8, filename to open():temp.txt
[   87.913378] invalid opcode: 0000 [#1] SMP 
[   87.913380] Modules linked in: xxx(OE) nls_utf8 isofs vboxsf(OE) snd_intel8x0 snd_ac97_codec ac97_bus snd_pcm snd_seq_midi snd_seq_midi_event hid_generic snd_rawmidi joydev snd_seq snd_seq_device snd_timer usbhid hid snd rfcomm bnep bluetooth 6lowpan_iphc serio_raw vboxvideo(OE) i2c_piix4 vboxguest(OE) soundcore drm parport_pc mac_hid ppdev lp parport psmouse ahci libahci e1000 pata_acpi
[   87.913401] CPU: 0 PID: 2877 Comm: a.out Tainted: G           OE 3.16.0-30-generic #40~14.04.1-Ubuntu
[   87.913402] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[   87.913404] task: ffff88002cf67010 ti: ffff88002bd94000 task.ti: ffff88002bd94000
[   87.913405] RIP: 03e8:[<ffffffffc01d342a>]  [<ffffffffc01d342a>] hook+0x12a/0x134 [xxx]
[   87.913409] RSP: 03e8:00000000000003e8  EFLAGS: ffffffff000003e8
[   87.913410] RAX: 0000000000000049 RBX: ffff88002cf67010 RCX: 0000000000000006
[   87.913411] RDX: 0000000000000007 RSI: 0000000000000046 RDI: 0000000000000246
[   87.913412] RBP: ffff88002bd97f50 R08: 0000000000000082 R09: 0000000000000214
[   87.913413] R10: 0000000000000000 R11: ffff88002bd97c2e R12: 0000000000000241
[   87.913414] R13: 00000000000001b6 R14: 0000000000000000 R15: 0000000000000000
[   87.913416] FS:  00007f767b8aa740(0000) GS:ffff88003fc00000(0000) knlGS:0000000000000000
[   87.913417] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   87.913419] CR2: 00007f767b24eee4 CR3: 0000000036cb7000 CR4: 00000000000006f0
[   87.913423] Stack:
[   87.913426] BUG: unable to handle kernel NULL pointer dereference at 00000000000003e8
[   87.913428] IP: [<ffffffff81015a29>] show_stack_log_lvl+0x109/0x180
[   87.913434] PGD 3ab9a067 PUD 2ed84067 PMD 0 


[   87.913437] Oops: 0000 [#2] SMP 
[   87.913438] Modules linked in: xxx(OE) nls_utf8 isofs vboxsf(OE) snd_intel8x0 snd_ac97_codec ac97_bus snd_pcm snd_seq_midi snd_seq_midi_event hid_generic snd_rawmidi joydev snd_seq snd_seq_device snd_timer usbhid hid snd rfcomm bnep bluetooth 6lowpan_iphc serio_raw vboxvideo(OE) i2c_piix4 vboxguest(OE) soundcore drm parport_pc mac_hid ppdev lp parport psmouse ahci libahci e1000 pata_acpi
[   87.913452] CPU: 0 PID: 2877 Comm: a.out Tainted: G           OE 3.16.0-30-generic #40~14.04.1-Ubuntu
[   87.913453] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[   87.913454] task: ffff88002cf67010 ti: ffff88002bd94000 task.ti: ffff88002bd94000
[   87.913455] RIP: 0010:[<ffffffff81015a29>]  [<ffffffff81015a29>] show_stack_log_lvl+0x109/0x180
[   87.913457] RSP: 0018:ffff88002bd97c60  EFLAGS: 00010046
[   87.913458] RAX: 00000000000003f0 RBX: 00000000000003e8 RCX: 0000000000000000
[   87.913459] RDX: ffff88003fc03fc0 RSI: ffff88002bd97e88 RDI: 0000000000000000
[   87.913460] RBP: ffff88002bd97cb0 R08: ffff88003fbfffc0 R09: 0000000000000224
[   87.913461] R10: 0000000000000000 R11: ffff88002bd979de R12: ffff88002bd97e88
[   87.913462] R13: 0000000000000000 R14: ffffffff81a64864 R15: 0000000000000000
[   87.913464] FS:  00007f767b8aa740(0000) GS:ffff88003fc00000(0000) knlGS:0000000000000000
[   87.913465] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   87.913466] CR2: 00000000000003e8 CR3: 0000000036cb7000 CR4: 00000000000006f0
[   87.913466] Stack:
[   87.913467]  ffffffff8175b59b ffff880000000008 ffff88002bd97cc0 ffff88002bd97c80
[   87.913469]  00000000000003e8 ffff88002bd97e88 00000000000003e8 0000000000000040
[   87.913471]  0000000000000000 0000000000000006 ffff88002bd97cf0 ffffffff81015b2a
[   87.913473] Call Trace:
[   87.913478]  [<ffffffff8175b59b>] ? printk+0x67/0x69
[   87.913480]  [<ffffffff81015b2a>] show_regs+0x8a/0x200
[   87.913482]  [<ffffffff810169bf>] __die+0x9f/0xe0
[   87.913484]  [<ffffffff81016e48>] die+0x38/0x70
[   87.913486]  [<ffffffff81013400>] do_trap+0xb0/0x150
[   87.913489]  [<ffffffff81013ac7>] do_error_trap+0x97/0x150
[   87.913491]  [<ffffffffc01d342a>] ? hook+0x12a/0x134 [xxx]
[   87.913496]  [<ffffffff810c8bb4>] ? wake_up_klogd+0x34/0x50
[   87.913498]  [<ffffffff810c8dc8>] ? console_unlock+0x1f8/0x440
[   87.913500]  [<ffffffff81014140>] do_invalid_op+0x20/0x30
[   87.913503]  [<ffffffffc01d32f2>] intr_handler+0x12/0x20 [xxx]
[   87.913505]  [<ffffffffc01d3465>] intr_stub+0x15/0x20 [xxx]
[   87.913507]  [<ffffffffc01d342a>] ? hook+0x12a/0x134 [xxx]
[   87.913509]  [<ffffffffc01d3493>] new_sys_open+0x23/0x40 [xxx]
[   87.913512]  [<ffffffff8176aced>] system_call_fastpath+0x1a/0x1f
[   87.913513] Code: 4d b8 4c 89 45 c0 48 89 55 c8 48 8b 5b f8 e8 23 5b 74 00 48 8b 55 c8 4c 8b 45 c0 8b 4d b8 85 c9 74 05 f6 c1 03 74 4c 48 8d 43 08 <48> 8b 33 48 c7 c7 5c 48 a6 81 89 4d b4 4c 89 45 b8 48 89 45 c8 
[   87.913531] RIP  [<ffffffff81015a29>] show_stack_log_lvl+0x109/0x180
[   87.913534]  RSP <ffff88002bd97c60>
[   87.913535] CR2: 00000000000003e8
[   87.913537] ---[ end trace 38675fa903317736 ]---

1 个答案:

答案 0 :(得分:1)

你想要做的事情是非常不寻常的,它会使操作系统崩溃并不奇怪。

中断处理程序不能直接从其他代码调用。首先,它们不会以普通C函数返回的方式返回。在x86上,中断处理程序返回RETI指令,该指令希望在堆栈上找到已保存的寄存器值。 (这不能在C中完成并且需要汇编语言代码。请参阅arch/x86/kernel/entry_32.S以查看低级中断处理并返回x86-32的代码。)如果您尝试从其他C代码调用中断处理程序,当处理程序返回时,它将获取它在堆栈中找到的任何“垃圾”并将其加载到寄存器中,包括堆栈指针和指令指针。

如果你解释为什么要这样做,也许有人可以帮助你找到另一种方法来完成你真正想要完成的事情。

修改

我以为你直接调用了一个中断处理程序,但现在我看到do_invalid_op只是一个从中断处理程序调用的C函数。但是,你为什么不用args来调用它呢?以下是它在边缘Linux中的定义:

#define DO_ERROR(trapnr, signr, str, name)              \
dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \
{                                   \
    do_error_trap(regs, error_code, str, trapnr, signr);        \
}

DO_ERROR(X86_TRAP_UD,     SIGILL,  "invalid opcode",        invalid_op)

所以你必须传递2个参数,struct pt_regs*long。如果你这样做,它仍会崩溃吗?