-
Notifications
You must be signed in to change notification settings - Fork 570
WIP: Introduce Ftrace in the syscall section #180
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
Draft
nickchen120235
wants to merge
11
commits into
sysprog21:master
Choose a base branch
from
nickchen120235:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+324
−0
Draft
Changes from 1 commit
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
f7cc340
Create Ftrace syscall hooking example
nickchen120235 9b7be18
Update ftrace example
nickchen120235 6626ce8
Complete ftrace part
nickchen120235 7486076
inhibit some sections of code that breaks when rendering
nickchen120235 b44bf10
requested changes
nickchen120235 2df343f
all `ftrace` should use verb
nickchen120235 7f5cf1f
change callback func description
nickchen120235 5a71f73
shorten the code
nickchen120235 3b0cc7d
split lines
nickchen120235 8cf0d6d
provide usage example
nickchen120235 beb9272
fix example
nickchen120235 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
/** | ||
* syscall-ftrace.c | ||
* | ||
* System call "stealing" with Ftrace | ||
*/ | ||
|
||
#include <linux/kernel.h> | ||
#include <linux/init.h> | ||
#include <linux/module.h> | ||
#include <linux/moduleparam.h> | ||
#include <linux/version.h> | ||
#include <linux/unistd.h> | ||
#include <linux/kprobes.h> | ||
#include <linux/sched.h> | ||
#include <linux/uaccess.h> | ||
#include <linux/slab.h> | ||
/** This is what we're using here. */ | ||
#include <linux/ftrace.h> | ||
|
||
MODULE_LICENSE("GPL"); | ||
|
||
#define MAX_FILENAME_SIZE 200 | ||
|
||
/* UID we want to spy on - will be filled from the command line. */ | ||
static int uid; | ||
nickchen120235 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
module_param(uid, int, 0644); | ||
|
||
/** | ||
* This is a helper structure that housekeeps all information | ||
* needed for hooking. Usage with `PREPARE_HOOK` is recommended. | ||
* | ||
* Example: | ||
* static ftrace_hook_t sys_clone_hook = PREPARE_HOOK(__NR_openat, my_sys_clone, &orig_sys_clone) | ||
*/ | ||
typedef struct ftrace_hook { | ||
unsigned long nr; // syscall name | ||
void* new; // hook function | ||
void* orig; // original function | ||
|
||
unsigned long address; // address to the original function | ||
struct ftrace_ops ops; // ftrace structure | ||
} ftrace_hook_t; | ||
|
||
#define PREPARE_HOOK(_nr, _hook, _orig) { \ | ||
.nr = (_nr), \ | ||
.new = (_hook), \ | ||
.orig = (_orig) \ | ||
} | ||
|
||
unsigned long **sys_call_table; | ||
nickchen120235 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/** | ||
* For the sake of simplicity, only the kprobe method is included. | ||
* If you want to know more about different methods to get | ||
* kallsyms_lookup_name, see syscall.c. | ||
*/ | ||
static int resolve_address(ftrace_hook_t *hook) | ||
{ | ||
static struct kprobe kp = { | ||
.symbol_name = "kallsyms_lookup_name" | ||
}; | ||
unsigned long (*kallsyms_lookup_name)(const char *name); | ||
linD026 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
register_kprobe(&kp); | ||
kallsyms_lookup_name = (unsigned long (*)(const char *))kp.addr; | ||
unregister_kprobe(&kp); | ||
|
||
if (kallsyms_lookup_name) pr_info("[syscall-ftrace] kallsyms_lookup_name is found at 0x%lx\n", (unsigned long)kallsyms_lookup_name); | ||
else { | ||
pr_err("[syscall-ftrace] kallsyms_lookup_name is not found!\n"); | ||
return -1; | ||
} | ||
|
||
sys_call_table = (unsigned long **)kallsyms_lookup_name("sys_call_table"); | ||
if (sys_call_table) pr_info("[syscall-ftrace] sys_call_table is found at 0x%lx\n", (unsigned long)sys_call_table); | ||
else { | ||
pr_err("[syscall-ftrace] sys_call_table is not found!\n"); | ||
return -1; | ||
} | ||
|
||
hook->address = (unsigned long)sys_call_table[hook->nr]; | ||
*((unsigned long*) hook->orig) = hook->address; | ||
return 0; | ||
} | ||
|
||
/** | ||
* This is where the magic happens. | ||
* | ||
*/ | ||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0) | ||
static void notrace ftrace_thunk(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ops, struct ftrace_regs *fregs) | ||
{ | ||
ftrace_hook_t *hook = container_of(ops, ftrace_hook_t, ops); | ||
if (!within_module(parent_ip, THIS_MODULE)) fregs->regs.ip = (unsigned long) hook->new; | ||
} | ||
|
||
#else | ||
static void notrace ftrace_thunk(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ops, struct pt_regs *regs) | ||
{ | ||
ftrace_hook_t *hook = container_of(ops, ftrace_hook_t, ops); | ||
if (!within_module(parent_ip, THIS_MODULE)) regs->ip = (unsigned long) hook->new; | ||
} | ||
|
||
#endif /** Version >= v5.11 */ | ||
|
||
int install_hook(ftrace_hook_t *hook) | ||
nickchen120235 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
int err; | ||
err = resolve_address(hook); | ||
if (err) return err; | ||
|
||
hook->ops.func = ftrace_thunk; | ||
hook->ops.flags = FTRACE_OPS_FL_SAVE_REGS | FTRACE_OPS_FL_IPMODIFY; | ||
err = ftrace_set_filter_ip(&hook->ops, hook->address, 0, 0); | ||
if (err) { | ||
pr_err("[syscall-ftrace] ftrace_set_filter_ip() failed: %d\n", err); | ||
return err; | ||
} | ||
|
||
err = register_ftrace_function(&hook->ops); | ||
if (err) { | ||
pr_err("[syscall-ftrace] register_ftrace_function() failed: %d\n", err); | ||
return err; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
void remove_hook(ftrace_hook_t *hook) | ||
nickchen120235 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
int err; | ||
err = unregister_ftrace_function(&hook->ops); | ||
if (err) pr_err("[syscall-ftrace] unregister_ftrace_function() failed: %d\n", err); | ||
|
||
err = ftrace_set_filter_ip(&hook->ops, hook->address, 1, 0); | ||
if (err) pr_err("[syscall-ftrace] ftrace_set_filter_ip() failed: %d\n", err); | ||
} | ||
|
||
/** For some reason the kernel segfaults when the arguments are expanded. */ | ||
static asmlinkage long (*original_call)(struct pt_regs *regs); | ||
static asmlinkage long our_sys_openat(struct pt_regs *regs) | ||
{ | ||
char *kfilename; | ||
kfilename = kmalloc(GFP_KERNEL, MAX_FILENAME_SIZE*sizeof(char)); | ||
if (!kfilename) return original_call(regs); | ||
|
||
if (copy_from_user(kfilename, (char __user *)regs->si, MAX_FILENAME_SIZE) < 0) { | ||
kfree(kfilename); | ||
return original_call(regs); | ||
} | ||
|
||
pr_info("[syscall-ftrace] File opened by UID %d: %s\n", uid, kfilename); | ||
kfree(kfilename); | ||
|
||
return original_call(regs); | ||
} | ||
|
||
static ftrace_hook_t sys_openat_hook = PREPARE_HOOK(__NR_openat, our_sys_openat, &original_call); | ||
|
||
static int __init syscall_ftrace_start(void) | ||
{ | ||
int err; | ||
err = install_hook(&sys_openat_hook); | ||
if (err) return err; | ||
pr_info("[syscall-ftrace] hooked, spying on uid %d\n", uid); | ||
return 0; | ||
} | ||
|
||
static void __exit syscall_ftrace_end(void) | ||
{ | ||
remove_hook(&sys_openat_hook); | ||
pr_info("[syscall-ftrace] removed\n"); | ||
} | ||
|
||
module_init(syscall_ftrace_start); | ||
module_exit(syscall_ftrace_end); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.