3

Since the release of the Linux 5.8 kernel the signature of *__vmalloc() has changed from:

void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)

To this

void *__vmalloc(unsigned long size, gfp_t gfp_mask)

Which means you cannot allocate executable memory via this function. So this is what your code will look like after that update:

#if LINUX_VERSION_CODE < KERNEL_VERSION(5,8,0)
return __vmalloc(len, GFP_KERNEL, PAGE_KERNEL_EXEC);
#else
return __vmalloc(len, GFP_KERNEL);
#endif

But this means, that without using the noexec parameter for the kernel, it is not possible to vmalloc executable memory for Kernels >= 5.8.

What is the alternative here, or in other words, how can I still allocate executable memory after kernel 5.8?

Xander
  • 418
  • 2
  • 12

1 Answers1

2

Looking at vmalloc.c, we can see that

  • __vmalloc calls __vmalloc_node which calls __vmalloc_node_range (see below)
  • __vmalloc_node_range has kept the prot parameter.

So, we can imagine recreate __vmalloc(..., PAGE_KERNEL_EXEC); from __vmalloc_node_range:

#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

The extracted code from 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));
}
Mathieu
  • 8,840
  • 7
  • 32
  • 45
  • 1
    If you look at [vmalloc.c](https://github.com/torvalds/linux/blob/master/mm/vmalloc.c#L3128) you will see that `EXPORT_SYMBOL(__vmalloc_node_range)` is missing. This means you cannot use this function in a kernel module if I understand `EXPORT_SYMBOL` correctly. – Xander Dec 09 '22 at 10:29
  • When I try to compile this I get the error `ERROR: modpost: "__vmalloc_node_range" [] undefined!`, even though this function is listed in `vmalloc.h`. – Xander Dec 09 '22 at 10:31
  • @Xander Arf, you're right.... In that case, you may want to try to use `int set_memory_x(unsigned long addr, int numpages);` But I wonder if it's exported too – Mathieu Dec 09 '22 at 10:36
  • I can allocate vmalloc by page, but that is less then ideal for my application. Also is this `set_memory_x()` function for physical memory and not virtual? – Xander Dec 09 '22 at 10:48