尝试从mm_struct-> start_code复制时,memcpy失败

时间:2014-03-08 18:45:11

标签: c linux memory-management linux-kernel kernel

我遇到了一些非常奇怪的行为,任务指向的代码段> mm,我希望有人可以帮助我。我正在做的是拉出代码段并将其放入缓冲区,然后从中生成HMAC。偶尔我会得到一个Ooops!说不能与调用堆栈终止在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()完全停止任务并在复制后重新启动它,但似乎没有什么能阻止问题。

更新:我仍在努力解决这个问题,尽管我还会投入更多数据。这是Oops转储。

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()每次都失败;有时不会阅读整个请求,有时会返回部分请求。每次它在部分失败时都会在页面边界上失效 - 再次使得它看起来像是在复制中被带走的内存。

鉴于我正在挂钩do_fork(),当我试图捕获它时,该进程是否可以从内核空间转换到用户空间?正如我之前提到的,我已经尝试停止当前任务并重新启动帖子副本,但它没有任何效果。

还有趣的是要注意;我已经有相同的(memcpy())代码在不同的负载下连续工作六周而没有在运行Ubuntu 12.04(3.8.13-bone28)的单个处理器ARM BeagleBoard Black上出现故障。这个问题似乎只发生在我运行Ubuntu 12.04的x86机箱上,然后才发生重负载就像启动Chromium一样。

很抱歉在这里啰嗦,我很难过。

有什么想法吗?

提前再次感谢,

皮特

1 个答案:

答案 0 :(得分:1)

您无法直接从用户空间可靠地复制内存,如您所发现的那样。

使用copy_from_user()代替memcpy()。并且不要禁用抢占,没有意义。