diff --git a/kmod/patch/kpatch-macros.h b/kmod/patch/kpatch-macros.h index caaadbc..8e09702 100644 --- a/kmod/patch/kpatch-macros.h +++ b/kmod/patch/kpatch-macros.h @@ -4,6 +4,7 @@ #include #include #include +#include "kpatch-syscall.h" /* upstream 33def8498fdd "treewide: Convert macro and uses of __section(foo) to __section("foo")" */ #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) diff --git a/kmod/patch/kpatch-syscall.h b/kmod/patch/kpatch-syscall.h new file mode 100644 index 0000000..07a1cec --- /dev/null +++ b/kmod/patch/kpatch-syscall.h @@ -0,0 +1,155 @@ +#ifndef __KPATCH_SYSCALL_H_ +#define __KPATCH_SYSCALL_H_ + +#include "kpatch-macros.h" + +/* + * These kpatch-specific syscall definition macros can be used for patching a + * syscall. + * + * Attempting to patch a syscall typically results in an error, due to a + * missing fentry hook in the inner __do_sys##name() function. The fentry hook + * is missing because of the 'inline' annotation, which invokes 'notrace'. + * + * These macros are copied almost verbatim from the kernel, the main difference + * being a 'kpatch' prefix added to the __do_sys##name() function name. This + * causes kpatch-build to treat it as a new function (due to + * its new name), and its caller __se_sys##name() function is inlined by its own + * caller __x64_sys##name() function, which has an fentry hook. + + * To patch a syscall, just replace the use of the SYSCALL_DEFINE1 (or similar) + * macro with the "KPATCH_" prefixed version. + */ + +#define KPATCH_IGNORE_SYSCALL_SECTIONS \ + KPATCH_IGNORE_SECTION("__syscalls_metadata"); \ + KPATCH_IGNORE_SECTION("_ftrace_events") + +#define KPATCH_SYSCALL_DEFINE1(name, ...) KPATCH_SYSCALL_DEFINEx(1, _##name, __VA_ARGS__) +#define KPATCH_SYSCALL_DEFINE2(name, ...) KPATCH_SYSCALL_DEFINEx(2, _##name, __VA_ARGS__) +#define KPATCH_SYSCALL_DEFINE3(name, ...) KPATCH_SYSCALL_DEFINEx(3, _##name, __VA_ARGS__) +#define KPATCH_SYSCALL_DEFINE4(name, ...) KPATCH_SYSCALL_DEFINEx(4, _##name, __VA_ARGS__) +#define KPATCH_SYSCALL_DEFINE5(name, ...) KPATCH_SYSCALL_DEFINEx(5, _##name, __VA_ARGS__) +#define KPATCH_SYSCALL_DEFINE6(name, ...) KPATCH_SYSCALL_DEFINEx(6, _##name, __VA_ARGS__) + +#define KPATCH_SYSCALL_DEFINEx(x, sname, ...) \ + KPATCH_IGNORE_SYSCALL_SECTIONS; \ + __KPATCH_SYSCALL_DEFINEx(x, sname, __VA_ARGS__) + +#ifdef CONFIG_X86_64 + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) + +#define __KPATCH_SYSCALL_DEFINEx(x, name, ...) \ + static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ + static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ + __X64_SYS_STUBx(x, name, __VA_ARGS__) \ + __IA32_SYS_STUBx(x, name, __VA_ARGS__) \ + static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ + { \ + long ret = __kpatch_do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\ + __MAP(x,__SC_TEST,__VA_ARGS__); \ + __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ + return ret; \ + } \ + static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) + +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0) + +#define __KPATCH_SYSCALL_DEFINEx(x, name, ...) \ + asmlinkage long __x64_sys##name(const struct pt_regs *regs); \ + ALLOW_ERROR_INJECTION(__x64_sys##name, ERRNO); \ + static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ + static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ + asmlinkage long __x64_sys##name(const struct pt_regs *regs) \ + { \ + return __se_sys##name(SC_X86_64_REGS_TO_ARGS(x,__VA_ARGS__));\ + } \ + __IA32_SYS_STUBx(x, name, __VA_ARGS__) \ + static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ + { \ + long ret = __kpatch_do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\ + __MAP(x,__SC_TEST,__VA_ARGS__); \ + __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ + return ret; \ + } \ + static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) + +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0) */ + +#define __KPATCH_SYSCALL_DEFINEx(x, name, ...) \ + asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \ + static inline long __kpatch_SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ + asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ + { \ + long ret = __kpatch_SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__));\ + __MAP(x,__SC_TEST,__VA_ARGS__); \ + __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ + return ret; \ + } \ + SYSCALL_ALIAS(sys##name, SyS##name); \ + static inline long __kpatch_SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)) + +#endif /* LINUX_VERSION_CODE */ + + +#elif defined(CONFIG_PPC64) + +#define __KPATCH_SYSCALL_DEFINEx(x, name, ...) \ + __diag_push(); \ + __diag_ignore(GCC, 8, "-Wattribute-alias", \ + "Type aliasing is used to sanitize syscall arguments");\ + asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \ + __attribute__((alias(__stringify(__se_sys##name)))); \ + ALLOW_ERROR_INJECTION(sys##name, ERRNO); \ + static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ + asmlinkage long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ + asmlinkage long __attribute__((optimize("-fno-optimize-sibling-calls")))\ + __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ + { \ + long ret = __kpatch_do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\ + __MAP(x,__SC_TEST,__VA_ARGS__); \ + __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ + return ret; \ + } \ + __diag_pop(); \ + static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) + + +#elif defined(CONFIG_S390) + +#define __KPATCH_S390_SYS_STUBx(x, name, ...) \ + long __s390_sys##name(struct pt_regs *regs); \ + ALLOW_ERROR_INJECTION(__s390_sys##name, ERRNO); \ + long __s390_sys##name(struct pt_regs *regs) \ + { \ + long ret = __kpatch_do_sys##name(SYSCALL_PT_ARGS(x, regs, \ + __SC_COMPAT_CAST, __MAP(x, __SC_TYPE, __VA_ARGS__))); \ + __MAP(x,__SC_TEST,__VA_ARGS__); \ + return ret; \ + } + +#define __KPATCH_SYSCALL_DEFINEx(x, name, ...) \ + __diag_push(); \ + __diag_ignore(GCC, 8, "-Wattribute-alias", \ + "Type aliasing is used to sanitize syscall arguments"); \ + long __s390x_sys##name(struct pt_regs *regs) \ + __attribute__((alias(__stringify(__se_sys##name)))); \ + ALLOW_ERROR_INJECTION(__s390x_sys##name, ERRNO); \ + static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \ + long __se_sys##name(struct pt_regs *regs); \ + __KPATCH_S390_SYS_STUBx(x, name, __VA_ARGS__) \ + long __se_sys##name(struct pt_regs *regs) \ + { \ + long ret = __kpatch_do_sys##name(SYSCALL_PT_ARGS(x, regs, \ + __SC_CAST, __MAP(x, __SC_TYPE, __VA_ARGS__))); \ + __MAP(x,__SC_TEST,__VA_ARGS__); \ + return ret; \ + } \ + __diag_pop(); \ + static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) + + +#endif /* CONFIG_X86_64 */ + +#endif /* __KPATCH_SYSCALL_H_ */