我在 task->mm 指向的代码段中遇到了一些非常奇怪的行为,我希望有人能帮助我。我正在做的是将代码段拉出并将其放入缓冲区,然后从中生成 HMAC。偶尔我会得到一个哎呀!说不能使用终止于 memcpy() 的调用堆栈。似乎正在发生的事情是数据在复制过程的中间消失,它导致页面错误,然后是 Ooops。我广泛搜索了对 mm_struct 中使用的这种看似短暂的内存特性的引用,但一无所获。我不相信我在代码中做了任何有争议的事情;为简洁起见,此处删除了注释等。
struct mm_struct* __mm;
...
__mm = get_task_mm(__task);
if(likely(__mm))
{
__buflen = (__mm->end_code - __mm->start_code);
if(likely(__buflen > 0))
{
__buf = (unsigned char*)__get_buffer(__buflen);
if(likely(__buf))
{
preempt_disable();
memcpy(__buf, (uint8_t*)__mm->start_code, __buflen);
preempt_enable();
mmput(__mm);
if(unlikely(!__do_ntru_hmac(__buf, __buflen, __hmac)))
{
__retcode = 0;
}
__release_buffer(__buf, __buflen);
}
else
{
printk(KERN_ERR "[%s] Buffer allocation failure [%d]\n", __task->comm, __buflen);
__retcode = 0;
}
...
内存分配例程很简单,旨在能够一次分配大块内存。它们看起来像这样:
void* __get_buffer(unsigned long __buflen)
{
if(likely(__buflen <= KMALLOC_MAX_SIZE))
{
return kmalloc(__buflen, GFP_KERNEL);
}
else
{
return (void*)__get_free_pages(GFP_KERNEL, get_order(__buflen));
}
return NULL;
}
void __release_buffer(void* __buffer, unsigned long __buflen)
{
if(likely(__buflen <= KMALLOC_MAX_SIZE))
{
kfree(__buffer);
}
else
{
free_pages((unsigned long)__buffer, get_order(__buflen));
}
return;
}
错误似乎是随机发生的,我无法将它与任务、父级或 struct task_struct 的任何其他组件联系起来。我尝试过使用互斥锁和自旋锁来保护 memcpy 期间的内存,我尝试使用 set_task_state() 完全停止任务并在复制后重新启动它,但似乎没有什么可以阻止问题。
更新:我仍在努力解决这个问题,尽管我会投入更多数据。这是糟糕的转储。
Mar 16 09:39:27 ubuntu kernel: [ 324.229195] BUG: unable to handle kernel paging request at 0804b000
Mar 16 09:39:27 ubuntu kernel: [ 324.229199] IP: [<c1312dfd>] memcpy+0x1d/0x40
Mar 16 09:39:27 ubuntu kernel: [ 324.229221] *pdpt = 000000002cf4c001 *pde = 000000003b72c067
Mar 16 09:39:27 ubuntu kernel: [ 324.229223] Oops: 0000 [#1] SMP
Mar 16 09:39:27 ubuntu kernel: [ 324.229225] Modules linked in: aerolock(OF) vmhgfs(OF) vmw_balloon psmouse snd_ens1371 serio_raw gameport snd_ac97_codec ac97_bus snd_pcm snd_seq_midi btusb snd_rawmidi snd_seq_midi_event snd_seq snd_timer snd_seq_device vmwgfx snd ttm drm bnep rfcomm soundcore mac_hid bluetooth snd_page_alloc vmw_vmci i2c_piix4 parport_pc ppdev shpchp lp parport hid_generic usbhid hid pcnet32 mptspi ahci libahci mptscsih mptbase floppy mii vmw_pvscsi vmxnet3
Mar 16 09:39:27 ubuntu kernel: [ 324.229256] CPU: 0 PID: 2880 Comm: aerolockd Tainted: GF O 3.11.0-17-generic #31~precise1-Ubuntu
Mar 16 09:39:27 ubuntu kernel: [ 324.229258] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/31/2013
Mar 16 09:39:27 ubuntu kernel: [ 324.229259] task: f1816700 ti: ed774000 task.ti: ed774000
Mar 16 09:39:27 ubuntu kernel: [ 324.229262] EIP: 0060:[<c1312dfd>] EFLAGS: 00010202 CPU: 0
Mar 16 09:39:27 ubuntu kernel: [ 324.229264] EIP is at memcpy+0x1d/0x40
Mar 16 09:39:27 ubuntu kernel: [ 324.229266] EAX: ecc80000 EBX: 00011cd0 ECX: 00003b34 EDX: 08048000
Mar 16 09:39:27 ubuntu kernel: [ 324.229268] ESI: 0804b000 EDI: ecc83000 EBP: ed775e74 ESP: ed775e68
Mar 16 09:39:27 ubuntu kernel: [ 324.229269] DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
Mar 16 09:39:27 ubuntu kernel: [ 324.229271] CR0: 80050033 CR2: 0804b000 CR3: 2d9d5000 CR4: 001407f0
Mar 16 09:39:27 ubuntu kernel: [ 324.229345] Stack:
Mar 16 09:39:27 ubuntu kernel: [ 324.229347] 00011cd0 f1816700 f33703b4 ed775eb0 f9ba3a1b 0000063b 00000000 00000000
Mar 16 09:39:27 ubuntu kernel: [ 324.229353] 0000063c c1b80e4c f1816700 ed775ee0 08048000 ecc80000 00000000 f1816700
Mar 16 09:39:27 ubuntu kernel: [ 324.229358] f9baa952 f1816700 ed775f08 f9ba3b6e 00000000 00000000 00000000 c1b9d642
Mar 16 09:39:27 ubuntu kernel: [ 324.229364] Call Trace:
Mar 16 09:39:27 ubuntu kernel: [ 324.229370] [<f9ba3a1b>] __generate_hmac+0x8b/0x190 [aerolock]
Mar 16 09:39:27 ubuntu kernel: [ 324.229373] [<f9ba3b6e>] __validate_hmac+0x4e/0x220 [aerolock]
Mar 16 09:39:27 ubuntu kernel: [ 324.229377] [<f9ba3da0>] ret_do_fork+0x60/0x70 [aerolock]
Mar 16 09:39:27 ubuntu kernel: [ 324.229384] [<c167f12a>] trampoline_handler+0x11a/0x1c0
Mar 16 09:39:27 ubuntu kernel: [ 324.229390] [<c10839a4>] ? wake_up_new_task+0xe4/0x150
Mar 16 09:39:27 ubuntu kernel: [ 324.229394] [<c1054bf5>] ? SyS_clone+0x25/0x30
Mar 16 09:39:27 ubuntu kernel: [ 324.229397] [<c1054bf5>] ? SyS_clone+0x25/0x30
Mar 16 09:39:27 ubuntu kernel: [ 324.229400] [<c167efee>] kretprobe_trampoline+0x16/0x38
Mar 16 09:39:27 ubuntu kernel: [ 324.229404] [<c167efd8>] ? kretprobe_trampoline_holder+0x8/0x8
Mar 16 09:39:27 ubuntu kernel: [ 324.229406] [<c167c937>] syscall_call+0x7/0xb
Mar 16 09:39:27 ubuntu kernel: [ 324.229408] Code: c3 90 8d 74 26 00 e8 33 fe ff ff eb e8 90 55 89 e5 83 ec 0c 89 5d f4 89 75 f8 89 7d fc 3e 8d 74 26 00 89 cb 89 c7 c1 e9 02 89 d6 <f3> a5 89 d9 83 e1 03 74 02 f3 a4 8b 5d f4 8b 75 f8 8b 7d fc 89
Mar 16 09:39:27 ubuntu kernel: [ 324.229439] EIP: [<c1312dfd>] memcpy+0x1d/0x40 SS:ESP 0068:ed775e68
Mar 16 09:39:27 ubuntu kernel: [ 324.229444] CR2: 000000000804b000
Mar 16 09:39:27 ubuntu kernel: [ 324.229447] ---[ end trace 3c014cb0223fa59a ]---
我尝试了很多不同的策略,但都以失败告终。例如 copy_from_user() 每次都失败;有时不阅读整个请求,有时返回部分请求。每次它在部分失败时,它都会在页面边界上失败——再次使内存看起来像是在复制过程中被带走。
考虑到我正在 Hook do_fork(),当我试图捕获它时,进程是否可以从内核空间过渡到用户空间?正如我之前提到的,我试过停止当前任务并重新启动后复制,但没有任何效果。
也很有趣;在运行 Ubuntu 12.04 (3.8.13-bone28) 的单个处理器 ARM BeagleBoard Black 上,我有相同的 (memcpy()) 代码在不同的负载下连续运行六周而没有出现故障。这个问题似乎只发生在我运行 Ubuntu 12.04 的 x86 机器上,然后只有当我对它施加重负载时,比如启动 Chromium。
抱歉在这里啰嗦了这么久,我被难住了。
有什么想法吗?
再次感谢,
皮特
最佳答案
正如您所发现的,您不能直接从用户空间可靠地复制内存。
使用 copy_from_user()
而不是 memcpy()
。并且不要禁用抢占,这没有意义。
关于c - 尝试从 mm_struct->start_code 复制时 memcpy 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22273516/