本文介绍了如何处理Linux内核中的常规保护错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我有一个如下的内核模块,它尝试读取msr寄存器,毫无疑问,由于msr 0x2不存在,它将崩溃,将会发生一般的保护错误.我的问题是,如何像定义GP处理程序那样绕过此错误?如果我看不懂msr,请放手...
I have a piece of kernel module as the following, which tries to read msr register, no doubt it would crash as the msr 0x2 is not exist, a geneal protection fault will happens.My question is how could I bypass this fault, like define my GP handler? if I cannot read a msr, just let it go...
以下是我的模块代码:
#include <linux/init.h>
#include <linux/module.h>
#define LBR 0x2
static unsigned long long x86_get_msr(int msr)
{
unsigned long msrl = -1, msrh = -1;
/* NOTE: rdmsr is always return EDX:EAX pair value */
asm volatile (
"rdmsr;"
: "=a"(msrl), "=d"(msrh)
: "c"(msr));
return ((unsigned long long)msrh << 32) | msrl;
}
static int helloworld_init(void) {
unsigned long long ullRet = -1;
ullRet = x86_get_msr(LBR);
printk(KERN_INFO "msr: 0x%08x, ret: 0x%016llx", LBR, ullRet);
printk(KERN_INFO "hello world!\n");
return 0;
}
static void helloworld_exit(void) {
printk(KERN_INFO "see you.\n");
return;
}
module_init(helloworld_init);
module_exit(helloworld_exit);
以下是消息:
[19353.498488] general protection fault: 0000 [#1] SMP PTI
[19353.498491] Modules linked in: helloworld(POE+) nls_utf8 isofs xt_conntrack ipt_MASQUERADE nf_nat_masquerade_ipv4 nf_conntrack_netlink nfnetlink xfrm_user xfrm_algo xt_addrtype iptable_filter iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack libcrc32c br_netfilter bridge stp llc aufs overlay crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcbc aesni_intel aes_x86_64 crypto_simd glue_helper cryptd input_leds snd_intel8x0 snd_ac97_codec serio_raw ac97_bus joydev snd_pcm snd_seq_midi snd_seq_midi_event snd_rawmidi snd_seq intel_rapl_perf snd_seq_device snd_timer vboxguest(OE) snd soundcore mac_hid binfmt_misc sch_fq_codel parport_pc ppdev sunrpc lp parport ip_tables x_tables autofs4 btrfs xor zstd_compress raid6_pq dm_mirror dm_region_hash dm_log hid_generic usbhid hid vboxvideo(OE)
[19353.498548] ttm drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops drm psmouse pata_acpi pcnet32 mii i2c_piix4 ahci libahci video
[19353.498555] CPU: 1 PID: 7379 Comm: insmod Tainted: P OE 4.15.0-91-generic #92-Ubuntu
[19353.498556] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[19353.498560] RIP: 0010:x86_get_msr+0x25/0x3d [helloworld]
[19353.498561] RSP: 0018:ffffb92e46477c40 EFLAGS: 00010282
[19353.498563] RAX: 0000000000000002 RBX: 0000000000000000 RCX: 0000000000000002
[19353.498564] RDX: 000000000003f8e0 RSI: ffff9e3d4fdba500 RDI: 0000000000000002
[19353.498565] RBP: ffffb92e46477c58 R08: ffff9e3d5fd26080 R09: ffffffff8302c54e
[19353.498566] R10: ffffe11380ccfa40 R11: ffff9e3d5ffd1000 R12: ffffffffc092e03d
[19353.498567] R13: ffff9e3d4fdbaf80 R14: 0000000000000001 R15: ffff9e3ce8adede0
[19353.498569] FS: 00007f6e90008540(0000) GS:ffff9e3d5fd00000(0000) knlGS:0000000000000000
[19353.498571] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[19353.498582] CR2: 000055aabbc97e88 CR3: 00000000b1924006 CR4: 00000000000606e0
[19353.498599] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[19353.498600] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[19353.498601] Call Trace:
[19353.498605] helloworld_init+0x1f/0x4e [helloworld]
[19353.498609] do_one_initcall+0x52/0x19f
[19353.498612] ? _cond_resched+0x19/0x40
[19353.498614] ? kmem_cache_alloc_trace+0x14e/0x1b0
[19353.498617] ? do_init_module+0x27/0x213
[19353.498619] do_init_module+0x5f/0x213
[19353.498621] load_module+0x16bc/0x1f10
[19353.498624] ? ima_post_read_file+0x96/0xa0
[19353.498627] SYSC_finit_module+0xfc/0x120
[19353.498629] ? SYSC_finit_module+0xfc/0x120
[19353.498632] SyS_finit_module+0xe/0x10
[19353.498634] do_syscall_64+0x73/0x130
[19353.498636] entry_SYSCALL_64_after_hwframe+0x3d/0xa2
[19353.498638] RIP: 0033:0x7f6e8fb2f839
[19353.498639] RSP: 002b:00007ffd5b22f348 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[19353.498640] RAX: ffffffffffffffda RBX: 000055aabbc957a0 RCX: 00007f6e8fb2f839
[19353.498641] RDX: 0000000000000000 RSI: 000055aababe6d2e RDI: 0000000000000003
[19353.498642] RBP: 000055aababe6d2e R08: 0000000000000000 R09: 00007f6e8fe02000
[19353.498643] R10: 0000000000000003 R11: 0000000000000246 R12: 0000000000000000
[19353.498644] R13: 000055aabbc95760 R14: 0000000000000000 R15: 0000000000000000
[19353.498646] Code: <0f> 32 48 89 45 f0 48 89 55 f8 48 8b 45 f8 48 c1 e0 20 48 0b 45 f0
[19353.498655] RIP: x86_get_msr+0x25/0x3d [helloworld] RSP: ffffb92e46477c40
推荐答案
我通过添加初始化idt的代码尝试了以下代码,但是即使没有系统日志,Linux也崩溃了...我认为崩溃点应该在指令上的秘密...
I tried the following code, by adding code of initializing the idt, but linux crashed even without any syslog... I think the crash point should be at instruction of lidt...
有任何提示吗?
#include <linux/init.h>
#include <linux/module.h>
#include <linux/delay.h>
#define IDTBASE 0 /* GDT Physical address */
#define IDTSIZE 256 /* Max descriptor count */
#define INTGATE 0x8E00 /* Interruptions */
#define TRAPGATE 0x8F00 /* Syscalls */
#define TASKGATE 0x8500 /* Task switching */
/* segment descriptor */
struct idtdesc {
u16 offset0_15;
u16 select;
u16 type;
u16 offset16_31;
} __attribute__ ((packed));
/* IDTR register */
struct idtr {
u16 limite;
u32 base;
} __attribute__ ((packed));
struct idtr kidtr;
/* IDT table */
struct idtdesc kidt[IDTSIZE] = {{0, 0, 0, 0}};
/* pointer on a free IDT entry */
unsigned int kidtptr = 0;
void default_int(void){printk(KERN_INFO "default_init called\n");}
void k_int0(void){printk(KERN_INFO "k_int0 called\n");}
void k_int1(void){printk(KERN_INFO "k_int1 called\n");}
void k_int2(void){printk(KERN_INFO "k_int2 called\n");}
void k_int3(void){printk(KERN_INFO "k_int3 called\n");}
void k_int4(void){printk(KERN_INFO "k_int4 called\n");}
void k_int5(void){printk(KERN_INFO "k_int5 called\n");}
void k_int6(void){printk(KERN_INFO "k_int6 called\n");}
void k_int7(void){printk(KERN_INFO "k_int7 called\n");}
void k_int8(void){printk(KERN_INFO "k_int8 called\n");}
void k_int9(void){printk(KERN_INFO "k_int9 called\n");}
void k_int10(void){printk(KERN_INFO "k_int10 called\n");}
void k_int11(void){printk(KERN_INFO "k_int11 called\n");}
void k_int12(void){printk(KERN_INFO "k_int12 called\n");}
void k_int13(void){printk(KERN_INFO "k_int13 called\n");}
void k_int14(void){printk(KERN_INFO "k_int14 called\n");}
void k_int15(void){printk(KERN_INFO "k_int15 called\n");}
void k_int16(void){printk(KERN_INFO "k_int16 called\n");}
void k_int17(void){printk(KERN_INFO "k_int17 called\n");}
void k_int18(void){printk(KERN_INFO "k_int18 called\n");}
void k_irq0(void){printk(KERN_INFO "k_irq0 called\n");}
void k_irq1(void){printk(KERN_INFO "k_irq1 called\n");}
void k_irq2(void){printk(KERN_INFO "k_irq2 called\n");}
void k_irq3(void){printk(KERN_INFO "k_irq3 called\n");}
void k_irq4(void){printk(KERN_INFO "k_irq4 called\n");}
void k_irq5(void){printk(KERN_INFO "k_irq5 called\n");}
void k_irq6(void){printk(KERN_INFO "k_irq6 called\n");}
void k_irq7(void){printk(KERN_INFO "k_irq7 called\n");}
void k_irq8(void){printk(KERN_INFO "k_irq8 called\n");}
void init_idt_desc(u32 offset, u16 select, u16 type, struct idtdesc* desc) {
desc->offset0_15 = (offset & 0xffff);
desc->select = select;
desc->type = type;
desc->offset16_31 = (offset & 0xffff0000) >> 16;
return;
}
void add_idt_desc(struct idtdesc desc) {
kidt[kidtptr++] = desc;
return;
}
void init_idt(void) {
struct idtdesc desc;
int i;
for(i=0;i<IDTSIZE;i++) {
init_idt_desc((u32)default_int, 0x08, INTGATE, &desc);
add_idt_desc(desc);
}
init_idt_desc((u32)k_int0, 0x08, INTGATE, &kidt[0]);
init_idt_desc((u32)k_int1, 0x08, INTGATE, &kidt[1]);
init_idt_desc((u32)k_int2, 0x08, INTGATE, &kidt[2]);
init_idt_desc((u32)k_int3, 0x08, INTGATE, &kidt[3]);
init_idt_desc((u32)k_int4, 0x08, INTGATE, &kidt[4]);
init_idt_desc((u32)k_int5, 0x08, INTGATE, &kidt[5]);
init_idt_desc((u32)k_int6, 0x08, INTGATE, &kidt[6]);
init_idt_desc((u32)k_int7, 0x08, INTGATE, &kidt[7]);
init_idt_desc((u32)k_int8, 0x08, INTGATE, &kidt[8]);
init_idt_desc((u32)k_int9, 0x08, INTGATE, &kidt[9]);
init_idt_desc((u32)k_int10, 0x08, INTGATE, &kidt[10]);
init_idt_desc((u32)k_int11, 0x08, INTGATE, &kidt[11]);
init_idt_desc((u32)k_int12, 0x08, INTGATE, &kidt[12]);
init_idt_desc((u32)k_int13, 0x08, INTGATE, &kidt[13]);
init_idt_desc((u32)k_int14, 0x08, INTGATE, &kidt[14]);
init_idt_desc((u32)k_int15, 0x08, INTGATE, &kidt[15]);
init_idt_desc((u32)k_int16, 0x08, INTGATE, &kidt[16]);
init_idt_desc((u32)k_int17, 0x08, INTGATE, &kidt[17]);
init_idt_desc((u32)k_int18, 0x08, INTGATE, &kidt[18]);
init_idt_desc((u32)k_irq0, 0x08, INTGATE, &kidt[32]);
init_idt_desc((u32)k_irq1, 0x08, INTGATE, &kidt[33]);
init_idt_desc((u32)k_irq2, 0x08, INTGATE, &kidt[34]);
init_idt_desc((u32)k_irq3, 0x08, INTGATE, &kidt[35]);
init_idt_desc((u32)k_irq4, 0x08, INTGATE, &kidt[36]);
init_idt_desc((u32)k_irq5, 0x08, INTGATE, &kidt[37]);
init_idt_desc((u32)k_irq6, 0x08, INTGATE, &kidt[38]);
init_idt_desc((u32)k_irq7, 0x08, INTGATE, &kidt[39]);
init_idt_desc((u32)k_irq8, 0x08, INTGATE, &kidt[40]);
kidtr.limite = IDTSIZE*8;
kidtr.base = IDTBASE;
printk(KERN_INFO "init_idt called\n");
kidtr.base = kidt;
//memcpy((void*)kidtr.base, kidt, kidtr.limite);
asm volatile ("lidt %0;"
:
: "m"(kidtr));
printk(KERN_INFO "lidt executed called\n");
}
#define LBR 0x2
static unsigned long long x86_get_msr(int msr)
{
unsigned long msrl = -1, msrh = -1;
/* NOTE: rdmsr is always return EDX:EAX pair value */
asm volatile (
"rdmsr;"
: "=a"(msrl), "=d"(msrh)
: "c"(msr));
return ((unsigned long long)msrh << 32) | msrl;
}
static int helloworld_init(void) {
unsigned long long ullRet = -1;
init_idt();
ullRet = x86_get_msr(LBR);
printk(KERN_INFO "msr: 0x%08x, ret: 0x%016llx", LBR, ullRet);
printk(KERN_INFO "hello world!\n");
return 0;
}
static void helloworld_exit(void) {
printk(KERN_INFO "see you.\n");
return;
}
module_init(helloworld_init);
module_exit(helloworld_exit);
这篇关于如何处理Linux内核中的常规保护错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!