From 3cafcf72c39f6bdca61c6620522adc6d6b316180 Mon Sep 17 00:00:00 2001 From: Qiao Ma Date: Sun, 20 Mar 2022 15:50:00 +0800 Subject: [PATCH 1/4] border: fix bug that enum keyword missing in gcc.FunctionDecl When rebuilding function declaration from gcc tree, the keyword 'enum' is missed due to gcc bugs. For example: > static bool is_release_function(enum bpf_func_id func_id) It will be rebuilt as: > static bool is_release_function(bpf_func_id func_id) The keyword enum is missing, which will trigger compile error. So we need to add some extra code to fix it. Signed-off-by: Qiao Ma --- sched_boundary/sched_boundary.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sched_boundary/sched_boundary.py b/sched_boundary/sched_boundary.py index 0cd5c6b..6933ee0 100644 --- a/sched_boundary/sched_boundary.py +++ b/sched_boundary/sched_boundary.py @@ -60,6 +60,17 @@ class GccBugs(object): else: return str + @staticmethod + def function_signature(decl): + fn_signature = str(decl.str_decl) + fn_signature = GccBugs.enum_type_name(decl.result, fn_signature) + + for arg in decl.arguments: + if isinstance(arg.type, gcc.EnumeralType): + arg_type_name = str(arg.type.name) + fn_signature = fn_signature.replace(arg_type_name, 'enum ' + arg_type_name) + return fn_signature + # extern type array[] -> extern type array[] @staticmethod def array_size(decl, str): @@ -202,7 +213,7 @@ class SchedBoundaryExtract(SchedBoundary): lines[fn_row_start][fn_col_start:].replace(decl.name, new_name) lines[fn_row_end] = lines[fn_row_end] + '\n' + \ "/* DON'T MODIFY SIGNATURE OF FUNCTION {}, IT'S CALLBACK FUNCTION */\n".format(new_name) + \ - GccBugs.enum_type_name(decl.result, decl.str_decl) + '\n' + GccBugs.function_signature(decl) + '\n' for decl, export, fn_row_start, fn_col_start, fn_row_end, fn_col_end in self.interface_list: fn_export_jump.write(export) -- Gitee From 481a3273e9272ef00ee75cff2561dd532abc2a7d Mon Sep 17 00:00:00 2001 From: Qiao Ma Date: Wed, 23 Mar 2022 11:44:27 +0800 Subject: [PATCH 2/4] border: fixed Gcc bugs about typedef struct and va_list arguments There are two bugs when rebuilding function decleration from gcc tree: 1. if argument's type is a typedef alias of a struct type, the 'struct' keyword would missing when rebuilding. 2. if the argument type is va_list, the rebuilding result is 'struct *', which is incorrect. The major cause is that the va_list is a gcc builtin type, and its gcc tree orgnization is different from regular types. Signed-off-by: Qiao Ma --- sched_boundary/sched_boundary.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/sched_boundary/sched_boundary.py b/sched_boundary/sched_boundary.py index 6933ee0..e312884 100644 --- a/sched_boundary/sched_boundary.py +++ b/sched_boundary/sched_boundary.py @@ -52,6 +52,14 @@ class GccBugs(object): def array_pointer(decl, str): return GccBugs.array_pointer_re.sub(r'\1 (*\3)[\2]', str) + @staticmethod + def typedef(decl, str): + if isinstance(decl.type.name, gcc.TypeDecl): + name = decl.type.name.name + return str.replace('struct ' + name, name) + else: + return str + @staticmethod def enum_type_name(decl, str): if isinstance(decl.type, gcc.EnumeralType): @@ -60,15 +68,27 @@ class GccBugs(object): else: return str + @staticmethod + def is_val_list(arg): + return isinstance(arg.type, gcc.PointerType) and \ + isinstance(arg.type.dereference, gcc.RecordType) and \ + isinstance(arg.type.dereference.name, gcc.Declaration) and \ + arg.type.dereference.name.is_builtin and \ + arg.type.dereference.name.name == '__va_list_tag' + @staticmethod def function_signature(decl): fn_signature = str(decl.str_decl) fn_signature = GccBugs.enum_type_name(decl.result, fn_signature) - for arg in decl.arguments: + # special dealing with enum types. enum type will missing enum keyword in func.str_decl if isinstance(arg.type, gcc.EnumeralType): arg_type_name = str(arg.type.name) fn_signature = fn_signature.replace(arg_type_name, 'enum ' + arg_type_name) + # special dealing with builtin types, for example: va_list + elif GccBugs.is_val_list(arg): + fn_signature = fn_signature.replace("struct *", "va_list") + return fn_signature # extern type array[] -> extern type array[] @@ -79,7 +99,7 @@ class GccBugs(object): @staticmethod def fix(decl, str): for bugfix in [GccBugs.array_pointer, GccBugs.enum_type_name, - GccBugs.array_size]: + GccBugs.array_size, GccBugs.typedef]: str = bugfix(decl, str) return str -- Gitee From 48a2d89080b03374705156a3fdd8eb8bf9dfe387 Mon Sep 17 00:00:00 2001 From: Qiao Ma Date: Fri, 25 Mar 2022 20:24:47 +0800 Subject: [PATCH 3/4] src: use stack_trace_save_tsk() to check stack if CONFIG_ARCH_STACKWALK is enabled If CONFIG_ARCH_STACKWALK is enabled in v5.10, function save_stack_trace_tsk() is deprecated, the struct definition of stack_trace is deprecated, too. And we can use stack_trace_save_tsk() to replace it, which is similar to save_stack_trace_tsk(). Signed-off-by: Qiao Ma --- src/stack_check.h | 54 ++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/src/stack_check.h b/src/stack_check.h index 20282be..3823fe4 100644 --- a/src/stack_check.h +++ b/src/stack_check.h @@ -3,6 +3,7 @@ #include #include +#include #include "helper.h" #define MAX_STACK_ENTRIES 100 @@ -43,36 +44,27 @@ static void stack_check_init(void) addr_sort(mod_func_addr, mod_func_size, NR_INTERFACE_FN); } -static int stack_check_fn_insmod(struct stack_trace *trace) +static int stack_check_fn(unsigned long *entries, unsigned int nr_entries, bool install) { - unsigned long address; - int i, idx; - - for (i = 0; i < trace->nr_entries; i++) { - address = trace->entries[i]; - idx = bsearch(vm_func_addr, 0, NR_INTERFACE_FN - 1, address); - if (idx == -1) - continue; - - if (address < vm_func_addr[idx] + vm_func_size[idx]) - return -EAGAIN; + int i, ret; + unsigned long *func_addr; + unsigned long *func_size; + + if (install) { + func_addr = vm_func_addr; + func_size = vm_func_size; + } else { + func_addr = mod_func_addr; + func_size = mod_func_size; } - return 0; -} - -static int stack_check_fn_rmmod(struct stack_trace *trace) -{ - unsigned long address; - int i, idx; + for (i = 0; i < nr_entries; i++) { + int idx; - for (i = 0; i < trace->nr_entries; i++) { - address = trace->entries[i]; - idx = bsearch(mod_func_addr, 0, NR_INTERFACE_FN - 1, address); + idx = bsearch(func_addr, 0, NR_INTERFACE_FN - 1, address); if (idx == -1) - continue; - - if (address < mod_func_addr[idx] + mod_func_size[idx]) + return 0; + if (address < func_addr[idx] + func_size[idx]) return -EAGAIN; } @@ -83,6 +75,9 @@ static int stack_check_fn_rmmod(struct stack_trace *trace) static int stack_check_task(struct task_struct *task, bool install) { unsigned long entries[MAX_STACK_ENTRIES]; + unsigned int nr_entries = 0; + +#ifndef CONFIG_ARCH_STACKWALK struct stack_trace trace; trace.skip = 0; @@ -91,11 +86,12 @@ static int stack_check_task(struct task_struct *task, bool install) trace.entries = entries; save_stack_trace_tsk(task, &trace); + nr_entries = trace.nr_entries; +#else /* CONFIG_ARCH_STACKWALK */ + nr_entries = stack_trace_save_tsk(task, &entries, MAX_STACK_ENTRIES, 0); +#endif /* CONFIG_ARCH_STACKWALK */ - if (install) - return stack_check_fn_insmod(&trace); - else - return stack_check_fn_rmmod(&trace); + return stack_check_fn(entries, nr_entries, install); } static int stack_check(bool install) -- Gitee From d82d237e9eb47cdfbe352913e2adcaec7c8403ef Mon Sep 17 00:00:00 2001 From: Qiao Ma Date: Wed, 6 Apr 2022 17:31:27 +0800 Subject: [PATCH 4/4] src: do not call func write_cr0() when patching instructions Cr0.WP bit is disabled to skip processor's page attribute checking when patching instructions, and it works well in kernel v4.19. However, in kernel v5.10, when calling write_cr0(), kernel will check cr0.WP bit. If this bit is cleared, kernel will automatically set this bit and then update cr0 again. So we cannot actually clear cr0.WP bit, and it will make kernel crash when patching instructions. To avoid such problem, this commit directly use inline asm to update cr0, rather than call func write_cr0(). Signed-off-by: Qiao Ma --- src/head_jump.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/head_jump.h b/src/head_jump.h index 7fd8ba4..4c44466 100644 --- a/src/head_jump.h +++ b/src/head_jump.h @@ -84,14 +84,19 @@ static unsigned long mod_func_size[NR_INTERFACE_FN]; #define JUMP_REMOVE_FUNC(func) \ memcpy((unsigned char *)orig_##func, store_orig_##func, HEAD_LEN) +static inline void do_write_cr0(unsigned long val) +{ + asm volatile("mov %0,%%cr0": "+r" (val) : : "memory"); +} + /* Must be used in stop machine context */ #define JUMP_OPERATION(ops) do { \ unsigned long cr0; \ \ cr0 = read_cr0(); \ - write_cr0(cr0 & 0xfffeffff); \ + do_write_cr0(cr0 & 0xfffeffff); \ jump_##ops(); \ - write_cr0(cr0); \ + do_write_cr0(cr0); \ } while(0) #else /* For ARM64 */ -- Gitee