我正在尝试在 Ubuntu 16.04 上的 linux 内核 4.15.0-74-generic 上挂钩系统调用。加载内核模块时,它会给出以下消息dmesg
:
[96963.055549] BUG: unable to handle kernel paging request at ffffffff81e00520
[96963.055556] IP: entry_point+0x14/0x50 [syshook]
[96963.055557] PGD 1bbe0e067 P4D 1bbe0e067 PUD 1bbe0f063 PMD 0
[96963.055560] Oops: 0000 [#1] SMP PTI
[96963.055562] Modules linked in: syshook(OE+) xt_recent pci_stub vboxpci(OE) vboxnetadp(OE) vboxnetflt(OE) vboxdrv(OE) ip6t_REJECT nf_reject_ipv6 nf_log_ipv6 xt_hl ip6t_rt nf_conntrack_ipv6 nf_defrag_ipv6 ipt_REJECT nf_reject_ipv4 xt_comment nf_log_ipv4 nf_log_common xt_LOG xt_multiport intel_rapl x86_pkg_temp_thermal xt_limit intel_powerclamp coretemp kvm_intel kvm irqbypass xt_tcpudp snd_hda_codec_realtek snd_hda_codec_generic xt_addrtype input_leds snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_pcm crct10dif_pclmul crc32_pclmul snd_seq_midi snd_seq_midi_event ghash_clmulni_intel snd_rawmidi nf_conntrack_ipv4 nf_defrag_ipv4 pcbc xt_conntrack snd_seq aesni_intel snd_seq_device ip6table_filter aes_x86_64 ip6_tables snd_timer nf_conntrack_netbios_ns nf_conntrack_broadcast crypto_simd nf_nat_ftp
[96963.055583] nf_nat glue_helper i2c_i801 snd shpchp nf_conntrack_ftp cryptd intel_cstate intel_rapl_perf wmi_bmof mei_me mei soundcore ie31200_edac nf_conntrack libcrc32c iptable_filter lpc_ich binfmt_misc ip_tables ppdev mac_hid parport_pc x_tables lp parport autofs4 hid_generic usbhid hid i915 i2c_algo_bit drm_kms_helper syscopyarea sysfillrect ahci sysimgblt libahci fb_sys_fops drm r8169 mii wmi video
[96963.055611] CPU: 3 PID: 1621 Comm: insmod Tainted: G W OE 4.15.0-74-generic #83~16.04.1-Ubuntu
[96963.055612] Hardware name: LENOVO 3492H2Q/, BIOS F1KT52AUS 05/24/2013
[96963.055615] RIP: 0010:entry_point+0x14/0x50 [syshook]
[96963.055616] RSP: 0018:ffffa2cdc89c7c68 EFLAGS: 00010246
[96963.055617] RAX: 0000000000000000 RBX: ffffffffc07a8000 RCX: 0000000000000000
[96963.055618] RDX: 0000000000833a67 RSI: 0000000000000000 RDI: ffffffff81e00280
[96963.055619] RBP: ffffa2cdc89c7ce8 R08: ffff90251f3a6080 R09: ffff902516803980
[96963.055620] R10: ffffc668c14f8a00 R11: ffffffff97c5fc20 R12: ffffffffc07a60c0
[96963.055621] R13: 0000000000000000 R14: 0000000000000001 R15: 0000000000000001
[96963.055622] FS: 00007fd9d1159700(0000) GS:ffff90251f380000(0000) knlGS:0000000000000000
[96963.055623] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[96963.055624] CR2: ffffffff81e00520 CR3: 0000000204ff4001 CR4: 00000000001626e0
[96963.055625] Call Trace:
[96963.055631] ? do_one_initcall+0x55/0x1ac
[96963.055633] ? _cond_resched+0x1a/0x50
[96963.055636] ? kmem_cache_alloc_trace+0xa6/0x1d0
[96963.055640] do_init_module+0x5f/0x223
[96963.055642] load_module+0x188c/0x1e90
[96963.055646] ? ima_post_read_file+0x83/0xa0
[96963.055648] SYSC_finit_module+0xe5/0x120
[96963.055650] ? SYSC_finit_module+0xe5/0x120
[96963.055652] SyS_finit_module+0xe/0x10
[96963.055654] do_syscall_64+0x73/0x130
[96963.055656] entry_SYSCALL_64_after_hwframe+0x3d/0xa2
[96963.055658] RIP: 0033:0x7fd9d0c8c4d9
[96963.055658] RSP: 002b:00007ffdddf2e158 EFLAGS: 00000202 ORIG_RAX: 0000000000000139
[96963.055660] RAX: ffffffffffffffda RBX: 00005557c908b250 RCX: 00007fd9d0c8c4d9
[96963.055661] RDX: 0000000000000000 RSI: 00005557c87e526b RDI: 0000000000000003
[96963.055661] RBP: 00005557c87e526b R08: 0000000000000000 R09: 00007fd9d0f51ea0
[96963.055662] R10: 0000000000000003 R11: 0000000000000202 R12: 0000000000000000
[96963.055663] R13: 00005557c908b210 R14: 0000000000000000 R15: 0000000000000000
[96963.055664] Code: c0 c9 c3 e8 df b0 ee d5 0f 1f 44 00 00 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 c7 c7 80 02 e0 81 55 48 89 3d 74 22 00 00 <48> 8b 04 25 20 05 e0 81 48 89 e5 48 89 05 5a 22 00 00 e8 35 ff
[96963.055684] RIP: entry_point+0x14/0x50 [syshook] RSP: ffffa2cdc89c7c68
[96963.055685] CR2: ffffffff81e00520
[96963.055687] ---[ end trace fa6b1eb8d1543662 ]---
我究竟做错了什么?如何调试内核模块?
源代码是:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/unistd.h>
#include <linux/semaphore.h>
#include <linux/dirent.h>
#include <asm/cacheflush.h>
void **sys_call_table;
asmlinkage int (*original_rmdir)(const char __user * pathname);
asmlinkage int sys_rmdir(const char __user * pathname)
{
printk("Do whatever you want\n");
return 0;
}
int set_page_rw(unsigned long addr)
{
unsigned int level;
pte_t *pte = lookup_address(addr, &level);
if (pte->pte &~ _PAGE_RW) pte->pte |= _PAGE_RW;
return 0;
}
int set_page_ro(unsigned long addr)
{
unsigned int level;
pte_t *pte = lookup_address(addr, &level);
pte->pte = pte->pte &~_PAGE_RW;
return 0;
}
static int entry_point(void)
{
sys_call_table = (void*)0xffffffff81e00280;
original_rmdir = sys_call_table[__NR_rmdir];
set_page_rw(sys_call_table);
sys_call_table[__NR_rmdir] = sys_rmdir;
return 0;
}
static void exit_point(void)
{
sys_call_table[__NR_rmdir] = original_rmdir;
set_page_ro(sys_call_table);
return 0;
}
module_init(entry_point);
module_exit(exit_point);
答案1
鉴于您收到的消息:
[96963.055549] BUG: unable to handle kernel paging request at ffffffff81e00520
我会挖掘你的set_page_ro()
和set_page_rw()
功能。
特别是因为该消息为您提供了为系统调用表输入的地址 (ffffffff81e00520)。
为什么你用这样的值来硬编码它?我敢打赌内核会导出一个宏或extern void *
类似的东西以获得正确的值......
编辑:因此,如果使用正在运行的内核的 System.map 检索该地址,可能会很好。但是,如果你看这段代码切换页面 RW/RO 的过程看起来与您所做的不同......
当你这样做时:
if (pte->pte &~ _PAGE_RW) pte->pte |= _PAGE_RW;
github上的示例代码是这样的:
set_pte_atomic(pte, pte_clear_flags(*pte, _PAGE_RW));