c - BUG:在系统调用中访问自定义结构时无法处理内核分页请求
问题描述
使用带有内核 4.4.21 的 linux,我需要实现一个系统调用,它的参数中有一个自定义结构的指针。这些是要编辑的文件:
// in linux-4.4.21/arch/x86/entry/syscalls/syscall_64.tbl :
546 x32 procmem sys_procmem
// in linux-4.4.21/include/linux/syscalls.h :
struct proc_segs;
asmlinkage longsys_procmem (int pid, struct proc_segs *info);
我将 sys_procmem.c(实现)放在 linux-4.4.21/kernel/sys_procmem.c 中(sys_procmem.o 添加到该目录的 Makefile 中):
#include <linux/linkage.h>
#include <linux/sched.h>
#include <linux/kernel.h>
struct proc_segs
{
unsigned long stID;
};
asmlinkage long sys_procmem (int pid, struct proc_segs *info)
{
printk("sys_procmem called \n"); // this is fine in dmesg
info->stID = 1234567; // KILLED
return 0;
}
测试:
#include <sys/syscall.h>
#include <unistd.h>
#include <stdio.h>
struct proc_segs
{
unsigned long stID;
};
int main() {
unsigned long info[10];
long sysval = syscall(546, 1, info);
printf("My stID : %lu\n", info[0]);
} // I have no idea why this works (or not on me), but it was included in the excercise's manual
//or:
int main() {
struct proc_segs info;
syscall(546, getpid(), &info);
printf("My stID : %lu\n", info.stID);
}
两人都惨遭杀害。
dmesg:
[ 3298.944925] sys_procmem called
[ 3298.944997] BUG: unable to handle kernel paging request at 00007ffe570aa8e0
[ 3298.945005] IP: [<ffffffff8109d540>] sys_procmem+0x140/0x280
[ 3298.945017] PGD 7a919067 PUD 790a6067 PMD 7a82f067 PTE 800000004c530867
[ 3298.945027] Oops: 0003 [#2] SMP
[ 3298.945047] Modules linked in: bnep rfcomm bluetooth btrfs xor qxl raid6_pq snd_hda_codec_generic ttm snd_hda_intel snd_hda_codec kvm_intel drm_kms_helper snd_hda_core kvm drm snd_hwdep snd_pcm snd_seq_midi snd_seq_midi_event snd_rawmidi snd_seq snd_seq_device irqbypass snd_timer crct10dif_pclmul snd crc32_pclmul aesni_intel aes_x86_64 fb_sys_fops lrw syscopyarea glue_helper soundcore sysfillrect ablk_helper sysimgblt joydev lpc_ich cryptd input_leds serio_raw mac_hid parport_pc ppdev lp parport hid_generic usbhid hid e1000e psmouse ahci libahci virtio_blk
[ 3298.945122] CPU: 5 PID: 2752 Comm: test-procmem Tainted: G D 4.4.21.1810887 #13
[ 3298.945126] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS ?-20191223_100556-anatol 04/01/2014
[ 3298.945130] task: ffff88002c1e96c0 ti: ffff880079f68000 task.ti: ffff880079f68000
[ 3298.945134] RIP: 0010:[<ffffffff8109d540>] [<ffffffff8109d540>] sys_procmem+0x140/0x280
[ 3298.945142] RSP: 0018:ffff880079f6bf38 EFLAGS: 00010282
[ 3298.945145] RAX: 0000000000000024 RBX: ffff88013bb98000 RCX: 0000000000000006
[ 3298.945148] RDX: 0000000000000000 RSI: 0000000000000246 RDI: ffff88013fd4db30
[ 3298.945151] RBP: ffff880079f6bf48 R08: 000000000000000a R09: 0000000000000000
[ 3298.945154] R10: 0000000000000000 R11: 0000000000000304 R12: 00007ffe570aa8e0
[ 3298.945157] R13: 00007ffe570aaa10 R14: 0000000000000000 R15: 0000000000000000
[ 3298.945161] FS: 00007fe88da41740(0000) GS:ffff88013fd40000(0000) knlGS:0000000000000000
[ 3298.945165] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 3298.945168] CR2: 00007ffe570aa8e0 CR3: 000000007acb0000 CR4: 00000000003406e0
[ 3298.945177] Stack:
[ 3298.945180] 0000000000000000 0000000000400490 00007ffe570aa930 ffffffff817e7676
[ 3298.945187] 0000000000000000 0000000000000000 00007ffe570aaa10 0000000000000000
[ 3298.945196] 0000000000000000 00007fe88d82d6c8 0000000000000202 00007fe88d82ee80
[ 3298.945205] Call Trace:
[ 3298.945229] [<ffffffff817e7676>] entry_SYSCALL_64_fastpath+0x16/0x75
[ 3298.945234] Code: 00 48 8b b0 08 01 00 00 31 c0 e8 69 b6 0d 00 48 8b 83 48 07 00 00 48 c7 c7 e4 51 aa 81 48 8b b0 18 01 00 00 31 c0 e8 4d b6 0d 00 <49> c7 04 24 c7 a1 1b 00 48 c7 c7 01 52 aa 81 31 c0 e8 37 b6 0d
[ 3298.945315] RIP [<ffffffff8109d540>] sys_procmem+0x140/0x280
[ 3298.945322] RSP <ffff880079f6bf38>
[ 3298.945325] CR2: 00007ffe570aa8e0
[ 3298.945330] ---[ end trace 0b79468970c7e49f ]---
这是在 64 位 Ubuntu 14.04 虚拟机中完成的。我的朋友在使用 VirtualBox 或 VMWare Player 时没有问题,我的是 KVM/QEMU(虽然导师明确建议我们使用前两者,但使用 KVM 内核编译确实更快)。不同的管理程序是否与此有关?
解决方案
感谢评论。我添加了copy_from_user
和copy_to_user
。
现在它起作用了。
#include <linux/uaccess.h>
// struct definition
asmlinkage long sys_procmem (int pid, struct proc_segs *info)
{
printk("sys_procmem called \n");
struct proc_segs temp_info;
copy_from_user(&temp_info, info, sizeof(struct proc_segs));
info->stID = 1234567;
copy_to_user(info, &temp_info, sizeof(struct proc_segs));
return 0;
}
推荐阅读
- python - 生成 Google 搜索 url 的 Python 程序
- excel - 选择除标题以外的所有使用范围
- java - 传递空值时区分名称相同但参数列表不同的两个方法
- javascript - 仅匹配空格而不匹配选项卡、回车或 Javascript 中的谎言提要的正则表达式
- javascript - 如何修复 JavaScript 中未定义的 TypeError?对象的所有字段都存在
- android - Android wear os 在设备上试用时显示心率为 1
- facebook - 使用 FB Live 但未经审查的应用程序使用 FB Graph API 在 Facebook 页面上发布
- shell - 如何在shellscript中获取包的CMake变量
- python - PyQt4 没有安装
- python - 如何使用 aws 设计多客户端预处理软件管道?