我编写内核模块来调试用户进程的堆栈。我找到了一种方法来使用task_struct结构中的mm字段获取指向堆栈的指针,但是当我尝试从堆栈地址读取值时,我的模块崩溃了。 代码(对于带有pid 860的现有流程):
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/pid.h>
#include <linux/proc_fs.h>
struct task_struct *ed_task;
long int *val;
void *stack_p;
int i = 0;
static int __init init(void)
{
ed_task = pid_task(find_vpid(860), PIDTYPE_PID);
stack_p = (void *) ed_task->mm->start_stack;
printk("stack %d: %p", i, stack_p);
val = stack_p - sizeof(void *);
printk("stack %d value: %ld", i, *val);
printk(">");
return 0;
}
static void __exit modex(void)
{
}
module_init(init);
module_exit(modex);
MODULE_LICENSE("GPL");
错误:
[ 2714.296489] stack 0: 00007fffbd922e30
[ 2714.296495] BUG: unable to handle kernel paging request at 00007fffbd922e28
[ 2714.297844] IP: init+0x65/0x1000 [main3]
[ 2714.299017] PGD 10140d067
[ 2714.299019] P4D 10140d067
[ 2714.300188] PUD 0
[ 2714.303364] Oops: 0000 [#4] PREEMPT SMP
[ 2714.306523] Modules linked in: main3(O+) main1(O+) main(O+) main2(O+) rndis_host cdc_ether usbnet mii fuse rfcomm bnep nls_iso8859_1 nls_cp437 vfat fat intel_rapl x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel kvm hp_wmi irqbypass iTCO_wdt mousedev sparse_keymap iTCO_vendor_support ppdev joydev mei_wdt btusb crct10dif_pclmul crc32_pclmul crc32c_intel ghash_clmulni_intel btrtl pcbc btbcm aesni_intel btintel bluetooth evdev input_leds aes_x86_64 uvcvideo crypto_simd glue_helper cryptd videobuf2_vmalloc intel_cstate intel_rapl_perf videobuf2_memops ecdh_generic pcspkr videobuf2_v4l2 videobuf2_core videodev media psmouse mac_hid hid_generic arc4 nouveau iwldvm mac80211 mxm_wmi iwlwifi ttm cfg80211 drm_kms_helper drm rfkill syscopyarea sysfillrect snd_hda_codec_hdmi sysimgblt snd_hda_codec_idt
[ 2714.312788] snd_hda_codec_generic fb_sys_fops snd_hda_intel i2c_algo_bit snd_hda_codec snd_hda_core snd_hwdep snd_pcm snd_timer snd soundcore parport_pc thermal tpm_infineon hp_accel ac e1000e lis3lv02d parport wmi mei_me mei input_polldev battery video ptp pps_core button lpc_ich shpchp tpm_tis tpm_tis_core tpm sch_fq_codel vboxnetflt(O) vboxnetadp(O) pci_stub vboxpci(O) vboxdrv(O) sg ip_tables x_tables ext4 crc16 jbd2 fscrypto mbcache sr_mod cdrom sd_mod usbhid hid serio_raw atkbd libps2 ahci libahci libata scsi_mod firewire_ohci xhci_pci xhci_hcd sdhci_pci sdhci ehci_pci led_class ehci_hcd firewire_core mmc_core crc_itu_t usbcore usb_common i8042 serio [last unloaded: main]
[ 2714.318036] CPU: 3 PID: 6244 Comm: insmod Tainted: G D O 4.12.4-1-ARCH #1
[ 2714.319130] Hardware name: Hewlett-Packard HP EliteBook 8560w/1631, BIOS 68SVD Ver. F.60 03/12/2015
[ 2714.320246] task: ffff917ea5819c80 task.stack: ffff9f90455c8000
[ 2714.321406] RIP: 0010:init+0x65/0x1000 [main3]
[ 2714.322524] RSP: 0018:ffff9f90455cbc90 EFLAGS: 00010286
[ 2714.323684] RAX: 00007fffbd922e30 RBX: 0000000000000000 RCX: ffffffff8ba55a68
[ 2714.324813] RDX: 00007fffbd922e28 RSI: 0000000000000000 RDI: ffffffffc0f08031
[ 2714.325937] RBP: ffff9f90455cbc90 R08: 000000000000044b R09: ffffffff8bca0940
[ 2714.327040] R10: fffff2d0c2ecac40 R11: 0000000000000000 R12: ffffffffc0498000
[ 2714.328142] R13: ffff917e6ee4c480 R14: ffffffffc0f09050 R15: ffff917f06e24660
[ 2714.329279] FS: 00007f8999054b80(0000) GS:ffff917f3dcc0000(0000) knlGS:0000000000000000
[ 2714.330389] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 2714.331516] CR2: 00007fffbd922e28 CR3: 000000010150f000 CR4: 00000000000406e0
[ 2714.332652] Call Trace:
[ 2714.333810] do_one_initcall+0x50/0x190
[ 2714.334945] ? do_init_module+0x27/0x1e6
[ 2714.336065] do_init_module+0x5f/0x1e6
[ 2714.337197] load_module+0x2610/0x2ab0
[ 2714.338349] ? vfs_read+0x115/0x130
[ 2714.339469] SYSC_finit_module+0xf6/0x110
[ 2714.340574] ? SYSC_finit_module+0xf6/0x110
[ 2714.341675] SyS_finit_module+0xe/0x10
[ 2714.342782] entry_SYSCALL_64_fastpath+0x1a/0xa5
[ 2714.343899] RIP: 0033:0x7f8998765bb9
[ 2714.344988] RSP: 002b:00007ffc068a0528 EFLAGS: 00000206 ORIG_RAX: 0000000000000139
[ 2714.346111] RAX: ffffffffffffffda RBX: 00007f8998a26aa0 RCX: 00007f8998765bb9
[ 2714.347203] RDX: 0000000000000000 RSI: 000000000041aada RDI: 0000000000000003
[ 2714.348279] RBP: 00007f8998a26af8 R08: 0000000000000000 R09: 00007f8998a28e40
[ 2714.349368] R10: 0000000000000003 R11: 0000000000000206 R12: 0000000000001020
[ 2714.350441] R13: 0000000000001018 R14: 00007f8998a26af8 R15: 0000000000000001
[ 2714.351524] Code: 48 89 15 07 13 a7 00 e8 8d 11 cf ca 48 8b 05 fb 12 a7 00 8b 35 ed 12 a7 00 48 c7 c7 31 80 f0 c0 48 8d 50 f8 48 89 15 eb 12 a7 00 <48> 8b 50 f8 e8 65 11 cf ca 48 c7 c7 45 80 f0 c0 e8 59 11 cf ca
[ 2714.353786] RIP: init+0x65/0x1000 [main3] RSP: ffff9f90455cbc90
[ 2714.354914] CR2: 00007fffbd922e28
[ 2714.356130] ---[ end trace a150fd8aba7bd1e3 ]---
为什么它不起作用?堆栈是否有任何特殊的内存保护或我做错了什么?
答案 0 :(得分:0)
您无法从内核空间直接访问用户空间内存。为此,您需要使用内核提供的API函数copy_from_user()。
修改代码以使用此API应该有效:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/pid.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h> // Header file corresponding to copy_from_user()
struct task_struct *ed_task;
long int *valp; // Pointer to destination kernel memory
long int val; // Destination kernel memory
void *stack_p;
int i = 0;
static int __init init(void)
{
ed_task = pid_task(find_vpid(2298), PIDTYPE_PID);
stack_p = (void *) ed_task->mm->start_stack;
printk("stack %d: %p\n", i, stack_p);
valp = stack_p - sizeof(void *);
copy_from_user(&val, valp, sizeof(val));
printk("stack %d value: %ld", i, val);
printk(">");
return 0;
}
static void __exit modex(void)
{
}
module_init(init);
module_exit(modex);
MODULE_LICENSE("GPL");