-
Notifications
You must be signed in to change notification settings - Fork 128
kallsyms_lookup_name is not exported anymore in kernels > 5.7 #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hi! The lack of The function I'm using (e.g. here in a new branch) looks like this: unsigned long kaddr_lookup_name(const char *fname_raw)
{
int i;
unsigned long kaddr;
char *fname_lookup, *fname;
fname_lookup = kzalloc(NAME_MAX, GFP_KERNEL);
if (!fname_lookup)
return 0;
fname = kzalloc(strlen(fname_raw)+4, GFP_KERNEL);
if (!fname)
return 0;
/*
* We have to add "+0x0" to the end of our function name
* because that's the format that sprint_symbol() returns
* to us. If we don't do this, then our search can stop
* prematurely and give us the wrong function address!
*/
strcpy(fname, fname_raw);
strcat(fname, "+0x0");
/*
* Get the kernel base address:
* sprint_symbol() is less than 0x100000 from the start of the kernel, so
* we can just AND-out the last 3 bytes from it's address to the the base
* address.
* There might be a better symbol-name to use?
*/
kaddr = (unsigned long) &sprint_symbol;
kaddr &= 0xffffffffff000000;
/*
* All the syscalls (and all interesting kernel functions I've seen so far)
* are within the first 0x100000 bytes of the base address. However, the kernel
* functions are all aligned so that the final nibble is 0x0, so we only
* have to check every 16th address.
*/
for ( i = 0x0 ; i < 0x100000 ; i++ )
{
/*
* Lookup the name ascribed to the current kernel address
*/
sprint_symbol(fname_lookup, kaddr);
/*
* Compare the looked-up name to the one we want
*/
if ( strncmp(fname_lookup, fname, strlen(fname)) == 0 )
{
/*
* Clean up and return the found address
*/
kfree(fname_lookup);
return kaddr;
}
/*
* Jump 16 addresses to next possible address
*/
kaddr += 0x10;
}
/*
* We didn't find the name, so clean up and return 0
*/
kfree(fname_lookup);
return 0;
} I've also pushed my working branch to GitHub here (in my testing so far, all the modules that use I'd be interested to hear what you think! |
Hi!
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kprobes.h>
static struct kprobe kp = {
.symbol_name = "kallsyms_lookup_name"
};
int __init init_test(void) {
register_kprobe(&kp);
// x --> unsigned hexadecimal integer
pr_alert("Found at 0x%px \n", kp.addr);
return 0;
}
void __exit cleanup_test(void) {
unregister_kprobe(&kp);
}
MODULE_LICENSE("GPL");
module_init(init_test);
module_exit(cleanup_test); Output in the kernel logs: Output in
I haven't tried to hook it up to the lib but the addresses are equal.
Thank you for replying to me and let me know what you think, looking forward on finding a stable solution! |
Now this is a lovely solution! I threw it into this branch (just for the root backdoor for now) and it works really nicely! Early on, I check the kernel version, and setup the struct: #if LINUX_VERSION_CODE >= KERNEL_VERSION(5,7,0)
#define KPROBE_LOOKUP 1
#include <linux/kprobes.h>
static struct kprobe kp = {
.symbol_name = "kallsyms_lookup_name"
};
#endif and then later on, resolve the #ifdef KPROBE_LOOKUP
typedef unsigned long (*kallsyms_lookup_name_t)(const char *name);
kallsyms_lookup_name_t kallsyms_lookup_name;
register_kprobe(&kp);
kallsyms_lookup_name = (kallsyms_lookup_name_t) kp.addr;
unregister_kprobe(&kp);
#endif I'm gonna test the other techniques to make sure that they all work properly, but this definitely looks like the one to go with. |
Awesome! |
These changes have been merged into master (and I credited you with the idea in a comment!). |
Excellent! |
The best solution I found on the internet, thanks. ;-p |
This kprobe method depends on Relevant docs: https://docs.kernel.org/trace/kprobes.html#configuring-kprobes |
Just for my understanding: why is the usage of both kallsyms_lookup_name AND kprobes needed? I may got something twisted because in my head both try to reach the same goal right? finding the address of the hooked syscall? thx for the replies |
So you have either methods on the same file that conditionally compile depending on the version of the kernel, you're not actually using both. I agree, tho that it is confusing and hard to read. |
Issue
In newer kernel versions (> 5.7.0) the function
kallsyms_lookup_name
, used in your ftrace_helper.h library, is not exported anymore by default. This means that compiling the code provided by you (also found here) on newer kernels will fail throwing:ERROR: modpost: "kallsyms_lookup_name" undefined!
More references:
https://lkml.org/lkml/2020/2/25/576
https://lwn.net/Articles/813350/
Solution
I've done some research online and found this workaround, which compiles and works on Manjaro with kernel 5.9.16; so I have decided to link this awesome solution to your library.
patch.c - here's the solution wrote by @zizzu0 and modified by me
usable by including patch.h
And finally, the patched function in the lib ftracer_hekper.h
Conclusion
The described methods works also on older kernels, like in the 5.4.0-58 used in the Vagrant instance provided by your blog. It works by extracting the dynamic address from the kernel.
I haven't opened a pull request because I couldn't find the ftracer_helper lib here (I have only found it as a gist) and especially because I am a begginner in kernel land, my code could have been written and integrated better. It was a cool exercise for a beginner like me, hope you will find it useful!
Sorry for my English, I ain't a native speaker :)
The text was updated successfully, but these errors were encountered: