c - 调用 get_user_pages_fast 后内核崩溃
问题描述
我从 get_user_pages_fast 函数中得到内核恐慌。
我必须使用 get_user_pages_fast 而不是 pin_user_pages,因为我需要支持最低内核 2.6。
主要目标是从内核内存中获取页面。
我在这里错过了什么?
内核恐慌:
[15307.994946] BUG: kernel NULL pointer dereference, address: 0000000000000000
[15307.996126] #PF: supervisor write access in kernel mode
[15307.996970] #PF: error_code(0x0002) - not-present page
[15307.997800] PGD 80000001158dc067 P4D 80000001158dc067 PUD 1214b5067 PMD 0
[15307.998891] Oops: 0002 [#1] SMP PTI
[15307.999479] CPU: 10 PID: 10586 Comm: flint_ext Tainted: G O 5.12.0-rc1_for_upstream_min_debug_2021_03_01_12_16 #1
[15308.001271] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.13.0-0-gf21b5a4aeb02-prebuilt.qemu.org 04/01/2014
[15308.003007] RIP: 0010:internal_get_user_pages_fast+0x66c/0xad0
[15308.003939] Code: 01 02 00 00 48 8b 53 08 48 8d 42 ff 83 e2 01 48 0f 44 c3 f0 80 08 02 48 63 45 cc 49 83 c4 08 48 81 c1 00 10 00 00 48 8b 75 90 <48> 89 1c c6 83 45 cc 01 48 39 4d c0 0f 85 3a ff ff ff 48 8b 45 98
[15308.006762] RSP: 0018:ffff8881994e3940 EFLAGS: 00010006
[15308.007676] RAX: 0000000000000000 RBX: ffffea0006339140 RCX: 0000000002480000
[15308.008880] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffffea0006339140
[15308.010090] RBP: ffff8881994e3a10 R08: 0000000000000000 R09: 0000000000000001
[15308.011302] R10: 0000000000000001 R11: ffff88810b19c5e0 R12: ffff888117cba400
[15308.012588] R13: 000000ffffffffff R14: ffffea0000000000 R15: 800000018ce45067
[15308.013902] FS: 00007f4cd063e740(0000) GS:ffff88856b900000(0000) knlGS:0000000000000000
[15308.015387] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[15308.016445] CR2: 0000000000000000 CR3: 000000014b58c005 CR4: 0000000000370ea0
[15308.017766] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[15308.019067] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[15308.020327] Call Trace:
[15308.020857] ioctl.isra.0.cold+0x3d/0x9a [mst_pciconf]
[15308.021821] ? __lock_acquire+0x56c/0x2530
[15308.022622] ? find_held_lock+0x2b/0x80
[15308.023381] ? filemap_map_pages+0x163/0x690
[15308.024199] ? __lock_acquire+0x56c/0x2530
[15308.024987] ? find_held_lock+0x2b/0x80
[15308.025736] ? do_sigaction+0x11e/0x270
[15308.026481] ? lockdep_hardirqs_on_prepare+0xd4/0x180
[15308.027428] ? _raw_spin_unlock_irq+0x24/0x30
[15308.028263] new_ioctl+0x24/0x30 [mst_pciconf]
[15308.029107] __x64_sys_ioctl+0x3d8/0x790
[15308.029864] ? __x64_sys_rt_sigaction+0x7a/0x100
[15308.030735] ? lockdep_hardirqs_on_prepare+0xd4/0x180
[15308.031683] do_syscall_64+0x2d/0x40
[15308.032390] entry_SYSCALL_64_after_hwframe+0x44/0xae
用户空间代码:
int allocate_kernel_memory_page(char* pin_pages, struct mtcr_page_info* page_info,
int page_amount)
{
int return_value = 0;
int page_size = getpagesize();
char addrstr[80];
if(!mf || !page_info)
{
return_value = -1;
}
// Allocate the page address array.
page_info->page_address_array =
calloc(page_amount, sizeof(struct mtcr_page_address));
// Set the requested page size.
page_info->page_size = page_amount * page_size;
// Allocate user buffer.
pin_pages = memalign(page_size, page_info->page_size);
// Save the start buffer pointer as an integer.
sprintf(addrstr, "%p", pin_pages);
page_info->page_pointer_start = strtoul(addrstr, NULL, 0);
// Pin the memory in the kernel space.
return_value = ioctl(mf->fd, PCICONF_PAGE_ALLOCATION, page_info);
}
内核空间(来自 switch 案例的案例):
case PAGE_ALLOCATION:
{
struct page_info_st page_info;
int write_permission = 1;
int page_counter;
int ret;
// Copy the page info structure from the user space.
if (copy_from_user(&page_info, udata, sizeof(struct page_info_st))) {
ret = -EFAULT;
goto fin;
}
ret = get_user_pages_fast(page_info.page_pointer_start, page_info.page_size,
write_permission, dev->pages);
}
解决方案
推荐阅读
- javascript - 子类构造函数完成时的回调
- jenkins - 以编程方式创建 jobdsl 参数时出错
- python - 用连字符提取数字的正则表达式
- sql - 如何计算两个日期时间字段之间的确切时间?
- c++ - 如何修复程序的体系结构,以便可以在其他类中使用 Base 类的变量?
- python - 当我在 Windows 上安装 Python 并且它没有配置路径时
- excel - 将范围从 Excel 粘贴到 Ppt 作为图像
- python - 在 Python 中的 for 循环中断言
- javascript - 动态交换 IMG-SRC 与另一个图像?
- apache-flink - 如何按名称删除所有键的状态