I am working on a Linux kernel module, and I want to call function get_futex_key
. How can I do this? The eventual goal is to use kernel functions to return a list of threads that hold a given futex.
I followed this tutorial to create a "hello world" module. It uses the printk
function. I understand that it is possible to use printk
because it is one of the symbols visible to the kernel.
# cat /proc/kallsyms | grep printk
...
ffffffff9ebb9c32 T printk
...
Function get_futex_key
is also visible in /proc/kallsyms
. It is defined in futex.c
, not futex.h
. See this source for example.
# cat /proc/kallsyms | grep "get_futex_key"
ffffffff9e3223c0 t get_futex_key_refs.isra.11
ffffffff9e322a30 t get_futex_key
Assume that 0x20566a0
is a uaddr
obtained with the use of strace
.
# strace -p 117589
strace: Process 117589 attached
futex(0x20566a0, FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, 0, NULL, 0xffffffff^Cstrace: Process 117589 detached
I have tried the following code as fut.c
.
#include <linux/module.h> // included for all kernel modules
#include <linux/kernel.h> // included for KERN_INFO
#include <linux/init.h> // included for __init and __exit macros
#include <linux/futex.h>
#include <kernel/futex.c>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("FutexTestAuthor");
MODULE_DESCRIPTION("Futex Examiner");
static int __init hello_init(void)
{
union futex_key key1 = FUTEX_KEY_INIT;
printk(KERN_INFO "Get futex key\n");
//futex_key key1 = FUTEX_KEY_INIT;
get_futex_key(0x20566a0, 0, &key1, VERIFY_READ);
printk(KERN_INFO "key1 = %p\n", &key1);
return 0; // Non-zero return means that the module couldn't be loaded.
}
static void __exit hello_cleanup(void)
{
printk(KERN_INFO "Cleaning up futex module.\n");
}
module_init(hello_init);
module_exit(hello_cleanup);
The Makefile
obj-m += fut.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Output of make
# make
make -C /lib/modules/4.15.0-204-generic/build M=/home/myusername/git/LinuxExamples/kernel/fut modules
make[1]: Entering directory '/usr/src/linux-headers-4.15.0-204-generic'
CC [M] /home/myusername/git/LinuxExamples/kernel/fut/fut.o
/home/myusername/git/LinuxExamples/kernel/fut/fut.c:5:10: fatal error: kernel/futex.c: No such file or directory
#include <kernel/futex.c>
^~~~~~~~~~~~~~~~
compilation terminated.
scripts/Makefile.build:340: recipe for target '/home/myusername/git/LinuxExamples/kernel/fut/fut.o' failed
make[2]: *** [/home/myusername/git/LinuxExamples/kernel/fut/fut.o] Error 1
Makefile:1596: recipe for target '_module_/home/myusername/git/LinuxExamples/kernel/fut' failed
make[1]: *** [_module_/home/myusername/git/LinuxExamples/kernel/fut] Error 2
make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-204-generic'
Makefile:4: recipe for target 'all' failed
make: *** [all] Error 2
The get_futex_key()
function is not exported by the kernel. You can notice this in two ways:
EXPORT_SYMBOL(name)
after their definition. This one doesn't./proc/kallsyms
, exported functions have an uppercase T
symbol, while others have a lowercase t
. This one has the latter.You cannot create a module that uses get_futex_key()
directly as it will fail linking since the kernel does not export it. You also cannot and should never include .c
files in your module, only .h
(header) files. In fact, most of the times, .c
files won't even be available for you to include in the first place, but only .h
files will.
With the above said, you can either look at the source code of get_futex_key()
to understand how it works and re-implement part of its functionality in your module, or take a look at this other question for some hacks that will allow you to get ahold of unexported symbols from modules: Proper way of getting the address of non-exported kernel symbols in a Linux kernel module