如何在Linux中分配可执行内存

3
自从Linux 5.8内核发布以来,*__vmalloc()的签名已经发生了变化:
void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)

针对这个问题

void *__vmalloc(unsigned long size, gfp_t gfp_mask)

这意味着您无法通过此函数分配可执行内存。因此,在进行更新后,您的代码将如下所示:
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,8,0)
return __vmalloc(len, GFP_KERNEL, PAGE_KERNEL_EXEC);
#else
return __vmalloc(len, GFP_KERNEL);
#endif

然而这意味着,在内核中没有使用noexec参数的情况下,无法为大于等于5.8的内核分配可执行内存。

那么这里的替代方案是什么,或者换句话说,在内核5.8之后我如何仍然分配可执行内存?

1个回答

2

查看vmalloc.c,我们可以看到:

  • __vmalloc 调用 __vmalloc_node,后者调用 __vmalloc_node_range(见下文)。
  • __vmalloc_node_range 保留了 prot 参数。

因此,我们可以从 __vmalloc_node_range 重新创建 __vmalloc(..., PAGE_KERNEL_EXEC);

#if LINUX_VERSION_CODE < KERNEL_VERSION(5,8,0)
return __vmalloc(len, GFP_KERNEL, PAGE_KERNEL_EXEC);
#else
return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END, gfp_mask,
             PAGE_KERNEL_EXEC, 0, node, caller);
#endif

vmalloc.c中提取的代码:

void *__vmalloc_node(unsigned long size, unsigned long align,
                gfp_t gfp_mask, int node, const void *caller)
{
    return __vmalloc_node_range(size, align, VMALLOC_START, VMALLOC_END,
                gfp_mask, PAGE_KERNEL, 0, node, caller);
}
void *__vmalloc(unsigned long size, gfp_t gfp_mask)
{
    return __vmalloc_node(size, 1, gfp_mask, NUMA_NO_NODE,
                __builtin_return_address(0));
}

1
如果您查看 vmalloc.c,您会发现缺少 EXPORT_SYMBOL(__vmalloc_node_range)。如果我正确理解 EXPORT_SYMBOL,这意味着您无法在内核模块中使用此函数。 - Xander
当我尝试编译它时,我会得到一个错误ERROR: modpost: "__vmalloc_node_range" [<ko_file_location>] undefined!,尽管这个函数在vmalloc.h中被列出来了。 - Xander
@Xander Arf,你说得对...如果是这样的话,你可能想尝试使用int set_memory_x(unsigned long addr, int numpages);不过我不确定它是否被导出。 - Mathieu
我可以按页分配vmalloc,但这对我的应用程序来说并不是最理想的。此外,set_memory_x()函数适用于物理内存而非虚拟内存吗? - Xander

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接