8

I'm writing a Linux kernel module, and I'd like to allocate an executable page. Plain kmalloc() returns a pointer within a non-executable page, and I get a kernel panic when executing code there. It has to work on Ubuntu Karmic x86, 2.6.31-20-generic-pae.

red0ct
  • 4,840
  • 3
  • 17
  • 44
pts
  • 80,836
  • 20
  • 110
  • 183

3 Answers3

11
#include <linux/vmalloc.h>
#include <asm/pgtype_types.h>
...
char *p = __vmalloc(byte_size, GFP_KERNEL, PAGE_KERNEL_EXEC);
...
if (p != NULL) vfree(p);
pts
  • 80,836
  • 20
  • 110
  • 183
  • `__vmalloc` doesn't take any argument of type `pgprot_t`, that means `PAGE_KERNEL_EXEC` cannot be used for `__vmalloc`. BTW: you can just use `vmalloc` since it defaults `gfp_mask` to `GFP_KERNEL`... and `linux/vmalloc.h` is enough. No need to import `pgtype_types.h` which isn't even imported anymore for use. – vmemmap Jul 21 '22 at 16:47
  • @Roi: The code in the answer worked for me at the time I wrote it. – pts Jul 22 '22 at 00:21
  • Ofc, the comment is mostly for future users who'll see this answer (: – vmemmap Jul 22 '22 at 07:31
1
/**
 * vmalloc_exec - allocate virtually contiguous, executable memory
 * @size:     allocation size
 *
 * Kernel-internal function to allocate enough pages to cover @size
 * the page level allocator and map them into contiguous and
 * executable kernel virtual space.
 *
 * For tight control over page level allocator and protection flags
 * use __vmalloc() instead.
 *
 * Return: pointer to the allocated memory or %NULL on error
 */
void *vmalloc_exec(unsigned long size)
{
    return __vmalloc_node(size, 1, GFP_KERNEL, PAGE_KERNEL_EXEC,
                  NUMA_NO_NODE, __builtin_return_address(0));
}
youfu
  • 1,547
  • 3
  • 15
  • 21
0

Linux 5.4 and above no longer make interfaces available so that arbitrary kernel modules won't modify page attributes to turn the executable bit on/off. However, there might be a specific configuration that will allow to do so, but I'm not aware of such.

If someone uses a kernel version that is lower than 5.4, you can use set_memory_x(unsigned long addr, int numpages); and friends to change the attributes of a page, or if you need to pass a struct page, you could use set_pages_x.

Keep in mind that it is considered dangerous and you have to know what you are doing.

vmemmap
  • 510
  • 4
  • 20