mirror of
https://github.com/dynup/kpatch
synced 2025-02-19 11:16:54 +00:00
Merge pull request #1322 from joe-lawrence/v6.2-support
Upstream kernel v6.2 support
This commit is contained in:
commit
73cdcb15ab
@ -38,7 +38,7 @@
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
|
||||
/* x86/include/asm/syscall_wrapper.h versions */
|
||||
/* arch/x86/include/asm/syscall_wrapper.h versions */
|
||||
|
||||
# if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)
|
||||
|
||||
@ -81,7 +81,7 @@
|
||||
|
||||
#elif defined(CONFIG_S390)
|
||||
|
||||
/* s390/include/asm/syscall_wrapper.h versions */
|
||||
/* arch/s390/include/asm/syscall_wrapper.h versions */
|
||||
|
||||
#define __KPATCH_S390_SYS_STUBx(x, name, ...) \
|
||||
long __s390_sys##name(struct pt_regs *regs); \
|
||||
@ -114,6 +114,33 @@
|
||||
__diag_pop(); \
|
||||
static inline long __kpatch_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
|
||||
|
||||
#elif defined(CONFIG_PPC64)
|
||||
|
||||
/* arch/powerpc/include/asm/syscall_wrapper.h versions */
|
||||
|
||||
# if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
|
||||
|
||||
# define __KPATCH_SYSCALL_DEFINEx(x, name, ...) \
|
||||
long sys##name(const struct pt_regs *regs); \
|
||||
ALLOW_ERROR_INJECTION(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__));\
|
||||
__attribute__((optimize("-fno-optimize-sibling-calls"))) \
|
||||
long sys##name(const struct pt_regs *regs) \
|
||||
{ \
|
||||
return __se_sys##name(SC_POWERPC_REGS_TO_ARGS(x,__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__))
|
||||
|
||||
# endif /* LINUX_VERSION_CODE */
|
||||
|
||||
#endif /* CONFIG_X86_64 */
|
||||
|
||||
|
||||
|
@ -236,14 +236,21 @@ static struct rela *toc_rela(const struct rela *rela)
|
||||
static void kpatch_bundle_symbols(struct kpatch_elf *kelf)
|
||||
{
|
||||
struct symbol *sym;
|
||||
unsigned int expected_offset;
|
||||
|
||||
list_for_each_entry(sym, &kelf->symbols, list) {
|
||||
if (is_bundleable(sym)) {
|
||||
if (sym->sym.st_value != 0 &&
|
||||
!is_gcc6_localentry_bundled_sym(kelf, sym)) {
|
||||
ERROR("symbol %s at offset %lu within section %s, expected 0",
|
||||
if (sym->pfx)
|
||||
expected_offset = 16;
|
||||
else if (is_gcc6_localentry_bundled_sym(kelf, sym))
|
||||
expected_offset = 8;
|
||||
else
|
||||
expected_offset = 0;
|
||||
|
||||
if (sym->sym.st_value != expected_offset) {
|
||||
ERROR("symbol %s at offset %lu within section %s, expected %u",
|
||||
sym->name, sym->sym.st_value,
|
||||
sym->sec->name);
|
||||
sym->sec->name, expected_offset);
|
||||
}
|
||||
|
||||
sym->sec->sym = sym;
|
||||
@ -1926,6 +1933,8 @@ static int kpatch_include_changed_functions(struct kpatch_elf *kelf)
|
||||
sym->type == STT_FUNC) {
|
||||
changed_nr++;
|
||||
kpatch_include_symbol(sym);
|
||||
if (sym->pfx)
|
||||
kpatch_include_symbol(sym->pfx);
|
||||
}
|
||||
|
||||
if (sym->type == STT_FILE)
|
||||
@ -1940,7 +1949,8 @@ static void kpatch_print_changes(struct kpatch_elf *kelf)
|
||||
struct symbol *sym;
|
||||
|
||||
list_for_each_entry(sym, &kelf->symbols, list) {
|
||||
if (!sym->include || !sym->sec || sym->type != STT_FUNC || sym->parent)
|
||||
if (!sym->include || !sym->sec || sym->type != STT_FUNC ||
|
||||
sym->parent || sym->is_pfx)
|
||||
continue;
|
||||
if (sym->status == NEW)
|
||||
log_normal("new function: %s\n", sym->name);
|
||||
@ -2137,6 +2147,11 @@ static int static_call_sites_group_size(struct kpatch_elf *kelf, int offset)
|
||||
return size;
|
||||
}
|
||||
|
||||
static int call_sites_group_size(struct kpatch_elf *kelf, int offset)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
static int retpoline_sites_group_size(struct kpatch_elf *kelf, int offset)
|
||||
{
|
||||
return 4;
|
||||
@ -2444,6 +2459,11 @@ static struct special_section special_sections[] = {
|
||||
.group_size = static_call_sites_group_size,
|
||||
.group_filter = static_call_sites_group_filter,
|
||||
},
|
||||
{
|
||||
.name = ".call_sites",
|
||||
.arch = X86_64,
|
||||
.group_size = call_sites_group_size,
|
||||
},
|
||||
{
|
||||
.name = ".retpoline_sites",
|
||||
.arch = X86_64,
|
||||
@ -2838,6 +2858,12 @@ static void kpatch_mark_ignored_sections(struct kpatch_elf *kelf)
|
||||
!strncmp(sec->name, ".llvm_addrsig", 13) ||
|
||||
!strncmp(sec->name, ".llvm.", 6))
|
||||
sec->ignore = 1;
|
||||
|
||||
if (kelf->arch == X86_64) {
|
||||
if (!strcmp(sec->name, ".rela__patchable_function_entries") ||
|
||||
!strcmp(sec->name, "__patchable_function_entries"))
|
||||
sec->ignore = 1;
|
||||
}
|
||||
}
|
||||
|
||||
sec = find_section_by_name(&kelf->sections, ".kpatch.ignore.sections");
|
||||
@ -3925,7 +3951,8 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf)
|
||||
struct rela *rela;
|
||||
unsigned char *insn;
|
||||
list_for_each_entry(sym, &kelf->symbols, list) {
|
||||
if (sym->type != STT_FUNC || !sym->sec || !sym->sec->rela)
|
||||
if (sym->type != STT_FUNC || sym->is_pfx ||
|
||||
!sym->sec || !sym->sec->rela)
|
||||
continue;
|
||||
|
||||
switch(kelf->arch) {
|
||||
|
@ -107,7 +107,9 @@
|
||||
#include "varasm.h"
|
||||
#include "stor-layout.h"
|
||||
#include "internal-fn.h"
|
||||
#include "gimple.h"
|
||||
#include "gimple-expr.h"
|
||||
#include "gimple-iterator.h"
|
||||
#include "gimple-fold.h"
|
||||
#include "context.h"
|
||||
#include "tree-ssa-alias.h"
|
||||
@ -129,7 +131,6 @@
|
||||
#include "tree-ssa-operands.h"
|
||||
#include "tree-phinodes.h"
|
||||
#include "tree-cfg.h"
|
||||
#include "gimple-iterator.h"
|
||||
#include "gimple-ssa.h"
|
||||
#include "ssa-iterators.h"
|
||||
#endif
|
||||
|
@ -337,11 +337,12 @@ find_special_section_data() {
|
||||
check[b]=true # bug_entry
|
||||
check[e]=true # exception_table_entry
|
||||
|
||||
# Arch-specific features, without kernel CONFIG_ toggle
|
||||
# Arch-specific features
|
||||
case "$ARCH" in
|
||||
"x86_64")
|
||||
check[a]=true # alt_instr
|
||||
kernel_version_gte 5.10.0 && check[s]=true # static_call_site
|
||||
[[ -n "$CONFIG_PARAVIRT" ]] && check[p]=true # paravirt_patch_site
|
||||
;;
|
||||
"ppc64le")
|
||||
check[f]=true # fixup_entry
|
||||
@ -355,7 +356,6 @@ find_special_section_data() {
|
||||
[[ -n "$CONFIG_PRINTK_INDEX" ]] && check[i]=true # pi_entry
|
||||
[[ -n "$CONFIG_JUMP_LABEL" ]] && check[j]=true # jump_entry
|
||||
[[ -n "$CONFIG_UNWINDER_ORC" ]] && check[o]=true # orc_entry
|
||||
[[ -n "$CONFIG_PARAVIRT" ]] && check[p]=true # paravirt_patch_site
|
||||
|
||||
local c AWK_OPTIONS
|
||||
for c in "${!check[@]}"; do
|
||||
|
@ -44,6 +44,7 @@ if [[ "$TOOLCHAINCMD" =~ ^(.*-)?gcc$ || "$TOOLCHAINCMD" =~ ^(.*-)?clang$ ]] ; th
|
||||
arch/s390/kernel/vdso64/*|\
|
||||
drivers/firmware/efi/libstub/*|\
|
||||
init/version.o|\
|
||||
init/version-timestamp.o|\
|
||||
kernel/system_certificates.o|\
|
||||
lib/*|\
|
||||
tools/*|\
|
||||
|
@ -397,6 +397,97 @@ static void kpatch_create_section_list(struct kpatch_elf *kelf)
|
||||
ERROR("expected NULL");
|
||||
}
|
||||
|
||||
/*
|
||||
* Some x86 kernels have NOP function padding [1] for which objtool [2]
|
||||
* adds ELF function symbols with prefix "__pfx_" to indicate the start
|
||||
* of a function, inclusive of NOP-padding. Find the prefix symbols and
|
||||
* link them to their corresponding function symbols at an expected
|
||||
* offset.
|
||||
*
|
||||
* A few examples:
|
||||
*
|
||||
* Value Size Type Bind Vis Ndx Name
|
||||
* (fork.o, simple case)
|
||||
* 0000000000000000 0 SECTION LOCAL DEFAULT 31 .text.get_task_mm
|
||||
* 0000000000000000 16 FUNC GLOBAL DEFAULT 31 __pfx_get_task_mm
|
||||
* 0000000000000010 91 FUNC GLOBAL DEFAULT 31 get_task_mm
|
||||
*
|
||||
* (fork.o, multiple function aliases)
|
||||
* 0000000000000000 0 SECTION LOCAL DEFAULT 190 .text.__do_sys_fork
|
||||
* 0000000000000000 16 FUNC GLOBAL DEFAULT 190 __pfx___x64_sys_fork
|
||||
* 0000000000000010 49 FUNC LOCAL DEFAULT 190 __do_sys_fork
|
||||
* 0000000000000010 49 FUNC GLOBAL DEFAULT 190 __ia32_sys_fork
|
||||
* 0000000000000010 49 FUNC GLOBAL DEFAULT 190 __x64_sys_fork
|
||||
*
|
||||
* (fork.o multiple functions in one section)
|
||||
* 0000000000000000 0 SECTION LOCAL DEFAULT 59 .init.text
|
||||
* 0000000000000000 16 FUNC LOCAL DEFAULT 59 __pfx_coredump_filter_setup
|
||||
* 0000000000000010 40 FUNC LOCAL DEFAULT 59 coredump_filter_setup
|
||||
* 0000000000000038 16 FUNC WEAK DEFAULT 59 __pfx_arch_task_cache_init
|
||||
* 0000000000000048 10 FUNC WEAK DEFAULT 59 arch_task_cache_init
|
||||
* 0000000000000052 16 FUNC GLOBAL DEFAULT 59 __pfx_fork_init
|
||||
* 0000000000000062 357 FUNC GLOBAL DEFAULT 59 fork_init
|
||||
* 00000000000001c7 16 FUNC GLOBAL DEFAULT 59 __pfx_fork_idle
|
||||
* 00000000000001d7 214 FUNC GLOBAL DEFAULT 59 fork_idle
|
||||
* 00000000000002ad 16 FUNC GLOBAL DEFAULT 59 __pfx_mm_cache_init
|
||||
* 00000000000002bd 72 FUNC GLOBAL DEFAULT 59 mm_cache_init
|
||||
* 0000000000000305 16 FUNC GLOBAL DEFAULT 59 __pfx_proc_caches_init
|
||||
* 0000000000000315 192 FUNC GLOBAL DEFAULT 59 proc_caches_init
|
||||
*
|
||||
* (fork.o, function without nop padding / __pfx_ symbol)
|
||||
* 0000000000000000 0 SECTION LOCAL DEFAULT 99 .text.unlikely.__mmdrop
|
||||
* 0000000000000000 48 FUNC LOCAL DEFAULT 99 __mmdrop.cold
|
||||
*
|
||||
* (kpatch-build generated tmp.ko, multple functions in one section, no __pfx_ symbols)
|
||||
* 0000000000000000 0 SECTION LOCAL DEFAULT 10 .text.unlikely.callback_info.isra.0
|
||||
* 0000000000000010 65 FUNC LOCAL DEFAULT 10 callback_info.isra.0
|
||||
* 0000000000000061 54 FUNC LOCAL DEFAULT 10 callback_info.isra.0
|
||||
* 00000000000000a7 54 FUNC LOCAL DEFAULT 10 callback_info.isra.0
|
||||
*
|
||||
* CONFIG_CFI_CLANG uses something very similar, except the symbol is created
|
||||
* by the compiler and its prefix is "__cfi_".
|
||||
*
|
||||
* [1] bea75b33895f ("x86/Kconfig: Introduce function padding")
|
||||
* [2] 9f2899fe36a6 ("objtool: Add option to generate prefix symbols")
|
||||
*/
|
||||
static void kpatch_link_prefixed_functions(struct kpatch_elf *kelf)
|
||||
{
|
||||
struct symbol *func, *pfx;
|
||||
bool found;
|
||||
|
||||
if (kelf->arch != X86_64)
|
||||
return;
|
||||
|
||||
list_for_each_entry(pfx, &kelf->symbols, list) {
|
||||
if (!pfx->name || pfx->type != STT_FUNC)
|
||||
continue;
|
||||
|
||||
if (strncmp(pfx->name, "__pfx_", 6) &&
|
||||
strncmp(pfx->name, "__cfi_", 6))
|
||||
continue;
|
||||
|
||||
found = false;
|
||||
|
||||
list_for_each_entry(func, &kelf->symbols, list) {
|
||||
if (func->type == STT_FUNC && func->sec == pfx->sec &&
|
||||
func->sym.st_value == pfx->sym.st_value + 16) {
|
||||
|
||||
/*
|
||||
* If a func has aliases, it's possible for
|
||||
* multiple functions to have the same 'pfx'.
|
||||
*/
|
||||
|
||||
pfx->is_pfx = true;
|
||||
func->pfx = pfx;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
ERROR("missing func for %s", pfx->name);
|
||||
}
|
||||
}
|
||||
|
||||
static void kpatch_create_symbol_list(struct kpatch_elf *kelf)
|
||||
{
|
||||
struct section *symtab;
|
||||
@ -459,6 +550,7 @@ static void kpatch_create_symbol_list(struct kpatch_elf *kelf)
|
||||
log_debug("\n");
|
||||
}
|
||||
|
||||
kpatch_link_prefixed_functions(kelf);
|
||||
}
|
||||
|
||||
struct kpatch_elf *kpatch_elf_open(const char *name)
|
||||
@ -960,6 +1052,7 @@ void kpatch_write_output_elf(struct kpatch_elf *kelf, Elf *elf, char *outfile,
|
||||
ehout.e_machine = eh.e_machine;
|
||||
ehout.e_type = eh.e_type;
|
||||
ehout.e_version = EV_CURRENT;
|
||||
ehout.e_flags = eh.e_flags;
|
||||
|
||||
shstrtab = find_section_by_name(&kelf->sections, ".shstrtab");
|
||||
if (!shstrtab)
|
||||
|
@ -77,6 +77,7 @@ struct symbol {
|
||||
struct list_head list;
|
||||
struct symbol *twin;
|
||||
struct symbol *parent;
|
||||
struct symbol *pfx;
|
||||
struct list_head children;
|
||||
struct list_head subfunction_node;
|
||||
struct section *sec;
|
||||
@ -91,6 +92,7 @@ struct symbol {
|
||||
enum symbol_strip strip; /* used in the output elf */
|
||||
};
|
||||
int has_func_profiling;
|
||||
bool is_pfx;
|
||||
};
|
||||
|
||||
struct rela {
|
||||
|
3
test/integration/linux-6.2.0/data-new-LOADED.test
Executable file
3
test/integration/linux-6.2.0/data-new-LOADED.test
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
grep "kpatch: 5" /proc/meminfo
|
20
test/integration/linux-6.2.0/data-new.patch
Normal file
20
test/integration/linux-6.2.0/data-new.patch
Normal file
@ -0,0 +1,20 @@
|
||||
diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c
|
||||
--- src.orig/fs/proc/meminfo.c 2023-01-12 11:20:07.184710563 -0500
|
||||
+++ src/fs/proc/meminfo.c 2023-01-12 11:20:08.166716386 -0500
|
||||
@@ -29,6 +29,8 @@ static void show_val_kb(struct seq_file
|
||||
seq_write(m, " kB\n", 4);
|
||||
}
|
||||
|
||||
+static int foo = 5;
|
||||
+
|
||||
static int meminfo_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct sysinfo i;
|
||||
@@ -154,6 +156,7 @@ static int meminfo_proc_show(struct seq_
|
||||
show_val_kb(m, "CmaFree: ",
|
||||
global_zone_page_state(NR_FREE_CMA_PAGES));
|
||||
#endif
|
||||
+ seq_printf(m, "kpatch: %d\n", foo);
|
||||
|
||||
hugetlb_report_meminfo(m);
|
||||
|
22
test/integration/linux-6.2.0/gcc-static-local-var-6.patch
Normal file
22
test/integration/linux-6.2.0/gcc-static-local-var-6.patch
Normal file
@ -0,0 +1,22 @@
|
||||
diff -Nupr src.orig/net/ipv6/netfilter.c src/net/ipv6/netfilter.c
|
||||
--- src.orig/net/ipv6/netfilter.c 2023-01-12 11:20:07.630713207 -0500
|
||||
+++ src/net/ipv6/netfilter.c 2023-01-12 11:20:29.874845095 -0500
|
||||
@@ -96,6 +96,8 @@ static int nf_ip6_reroute(struct sk_buff
|
||||
return 0;
|
||||
}
|
||||
|
||||
+#include "kpatch-macros.h"
|
||||
+
|
||||
int __nf_ip6_route(struct net *net, struct dst_entry **dst,
|
||||
struct flowi *fl, bool strict)
|
||||
{
|
||||
@@ -109,6 +111,9 @@ int __nf_ip6_route(struct net *net, stru
|
||||
struct dst_entry *result;
|
||||
int err;
|
||||
|
||||
+ if (!jiffies)
|
||||
+ printk("kpatch nf_ip6_route foo\n");
|
||||
+
|
||||
result = ip6_route_output(net, sk, &fl->u.ip6);
|
||||
err = result->error;
|
||||
if (err)
|
155
test/integration/linux-6.2.0/macro-callbacks.patch
Normal file
155
test/integration/linux-6.2.0/macro-callbacks.patch
Normal file
@ -0,0 +1,155 @@
|
||||
diff -Nupr src.orig/drivers/input/joydev.c src/drivers/input/joydev.c
|
||||
--- src.orig/drivers/input/joydev.c 2023-01-12 11:20:06.597707083 -0500
|
||||
+++ src/drivers/input/joydev.c 2023-01-12 11:20:38.032893465 -0500
|
||||
@@ -1096,3 +1096,47 @@ static void __exit joydev_exit(void)
|
||||
|
||||
module_init(joydev_init);
|
||||
module_exit(joydev_exit);
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include "kpatch-macros.h"
|
||||
+
|
||||
+static const char *const module_state[] = {
|
||||
+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state",
|
||||
+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init",
|
||||
+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away",
|
||||
+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up",
|
||||
+};
|
||||
+
|
||||
+static void callback_info(const char *callback, patch_object *obj)
|
||||
+{
|
||||
+ if (obj->mod)
|
||||
+ pr_info("%s: %s -> %s\n", callback, obj->mod->name,
|
||||
+ module_state[obj->mod->state]);
|
||||
+ else
|
||||
+ pr_info("%s: vmlinux\n", callback);
|
||||
+}
|
||||
+
|
||||
+static int pre_patch_callback(patch_object *obj)
|
||||
+{
|
||||
+ callback_info(__func__, obj);
|
||||
+ return 0; /* return -ENODEV; */
|
||||
+}
|
||||
+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback);
|
||||
+
|
||||
+static void post_patch_callback(patch_object *obj)
|
||||
+{
|
||||
+ callback_info(__func__, obj);
|
||||
+}
|
||||
+KPATCH_POST_PATCH_CALLBACK(post_patch_callback);
|
||||
+
|
||||
+static void pre_unpatch_callback(patch_object *obj)
|
||||
+{
|
||||
+ callback_info(__func__, obj);
|
||||
+}
|
||||
+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback);
|
||||
+
|
||||
+static void post_unpatch_callback(patch_object *obj)
|
||||
+{
|
||||
+ callback_info(__func__, obj);
|
||||
+}
|
||||
+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback);
|
||||
diff -Nupr src.orig/drivers/input/misc/pcspkr.c src/drivers/input/misc/pcspkr.c
|
||||
--- src.orig/drivers/input/misc/pcspkr.c 2023-01-12 11:20:06.578706970 -0500
|
||||
+++ src/drivers/input/misc/pcspkr.c 2023-01-12 11:20:38.032893465 -0500
|
||||
@@ -134,3 +134,46 @@ static struct platform_driver pcspkr_pla
|
||||
};
|
||||
module_platform_driver(pcspkr_platform_driver);
|
||||
|
||||
+#include <linux/module.h>
|
||||
+#include "kpatch-macros.h"
|
||||
+
|
||||
+static const char *const module_state[] = {
|
||||
+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state",
|
||||
+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init",
|
||||
+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away",
|
||||
+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up",
|
||||
+};
|
||||
+
|
||||
+static void callback_info(const char *callback, patch_object *obj)
|
||||
+{
|
||||
+ if (obj->mod)
|
||||
+ pr_info("%s: %s -> %s\n", callback, obj->mod->name,
|
||||
+ module_state[obj->mod->state]);
|
||||
+ else
|
||||
+ pr_info("%s: vmlinux\n", callback);
|
||||
+}
|
||||
+
|
||||
+static int pre_patch_callback(patch_object *obj)
|
||||
+{
|
||||
+ callback_info(__func__, obj);
|
||||
+ return 0;
|
||||
+}
|
||||
+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback);
|
||||
+
|
||||
+static void post_patch_callback(patch_object *obj)
|
||||
+{
|
||||
+ callback_info(__func__, obj);
|
||||
+}
|
||||
+KPATCH_POST_PATCH_CALLBACK(post_patch_callback);
|
||||
+
|
||||
+static void pre_unpatch_callback(patch_object *obj)
|
||||
+{
|
||||
+ callback_info(__func__, obj);
|
||||
+}
|
||||
+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback);
|
||||
+
|
||||
+static void post_unpatch_callback(patch_object *obj)
|
||||
+{
|
||||
+ callback_info(__func__, obj);
|
||||
+}
|
||||
+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback);
|
||||
diff -Nupr src.orig/fs/aio.c src/fs/aio.c
|
||||
--- src.orig/fs/aio.c 2023-01-12 11:20:07.273711091 -0500
|
||||
+++ src/fs/aio.c 2023-01-12 11:20:38.033893471 -0500
|
||||
@@ -50,6 +50,50 @@
|
||||
|
||||
#define KIOCB_KEY 0
|
||||
|
||||
+#include <linux/module.h>
|
||||
+#include "kpatch-macros.h"
|
||||
+
|
||||
+static const char *const module_state[] = {
|
||||
+ [MODULE_STATE_LIVE] = "[MODULE_STATE_LIVE] Normal state",
|
||||
+ [MODULE_STATE_COMING] = "[MODULE_STATE_COMING] Full formed, running module_init",
|
||||
+ [MODULE_STATE_GOING] = "[MODULE_STATE_GOING] Going away",
|
||||
+ [MODULE_STATE_UNFORMED] = "[MODULE_STATE_UNFORMED] Still setting it up",
|
||||
+};
|
||||
+
|
||||
+static void callback_info(const char *callback, patch_object *obj)
|
||||
+{
|
||||
+ if (obj->mod)
|
||||
+ pr_info("%s: %s -> %s\n", callback, obj->mod->name,
|
||||
+ module_state[obj->mod->state]);
|
||||
+ else
|
||||
+ pr_info("%s: vmlinux\n", callback);
|
||||
+}
|
||||
+
|
||||
+static int pre_patch_callback(patch_object *obj)
|
||||
+{
|
||||
+ callback_info(__func__, obj);
|
||||
+ return 0;
|
||||
+}
|
||||
+KPATCH_PRE_PATCH_CALLBACK(pre_patch_callback);
|
||||
+
|
||||
+static void post_patch_callback(patch_object *obj)
|
||||
+{
|
||||
+ callback_info(__func__, obj);
|
||||
+}
|
||||
+KPATCH_POST_PATCH_CALLBACK(post_patch_callback);
|
||||
+
|
||||
+static void pre_unpatch_callback(patch_object *obj)
|
||||
+{
|
||||
+ callback_info(__func__, obj);
|
||||
+}
|
||||
+KPATCH_PRE_UNPATCH_CALLBACK(pre_unpatch_callback);
|
||||
+
|
||||
+static void post_unpatch_callback(patch_object *obj)
|
||||
+{
|
||||
+ callback_info(__func__, obj);
|
||||
+}
|
||||
+KPATCH_POST_UNPATCH_CALLBACK(post_unpatch_callback);
|
||||
+
|
||||
#define AIO_RING_MAGIC 0xa10a10a1
|
||||
#define AIO_RING_COMPAT_FEATURES 1
|
||||
#define AIO_RING_INCOMPAT_FEATURES 0
|
9
test/integration/linux-6.2.0/module-LOADED.test
Executable file
9
test/integration/linux-6.2.0/module-LOADED.test
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
|
||||
sudo modprobe xfs
|
||||
sleep 5
|
||||
echo "file fs/xfs/xfs_stats.c +p" > /sys/kernel/debug/dynamic_debug/control
|
||||
grep -q kpatch /sys/fs/xfs/stats/stats
|
||||
dmesg | grep -q "kpatch: pr_debug"
|
77
test/integration/linux-6.2.0/module.patch
Normal file
77
test/integration/linux-6.2.0/module.patch
Normal file
@ -0,0 +1,77 @@
|
||||
kpatch module integration test
|
||||
|
||||
This tests several things related to the patching of modules:
|
||||
|
||||
- 'kpatch_string' tests the referencing of a symbol which is outside the
|
||||
.o, but inside the patch module.
|
||||
|
||||
- alternatives patching (.altinstructions)
|
||||
|
||||
- paravirt patching (.parainstructions)
|
||||
|
||||
- jump labels (5.8+ kernels only) -- including dynamic printk
|
||||
|
||||
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
|
||||
|
||||
diff --git a/fs/xfs/xfs_stats.c b/fs/xfs/xfs_stats.c
|
||||
index 90a77cd3ebad..f65df90ae8e1 100644
|
||||
--- a/fs/xfs/xfs_stats.c
|
||||
+++ b/fs/xfs/xfs_stats.c
|
||||
@@ -16,6 +16,8 @@ static int counter_val(struct xfsstats __percpu *stats, int idx)
|
||||
return val;
|
||||
}
|
||||
|
||||
+extern char *kpatch_string(void);
|
||||
+
|
||||
int xfs_stats_format(struct xfsstats __percpu *stats, char *buf)
|
||||
{
|
||||
int i, j;
|
||||
@@ -85,6 +87,34 @@ int xfs_stats_format(struct xfsstats __percpu *stats, char *buf)
|
||||
0);
|
||||
#endif
|
||||
|
||||
+ /* Reference a symbol outside the .o yet inside the patch module: */
|
||||
+ len += scnprintf(buf + len, PATH_MAX-len, "%s\n", kpatch_string());
|
||||
+
|
||||
+#ifdef CONFIG_X86_64
|
||||
+ /* Test alternatives patching: */
|
||||
+ alternative("ud2", "nop", X86_FEATURE_ALWAYS);
|
||||
+ alternative("nop", "ud2", X86_FEATURE_IA64);
|
||||
+
|
||||
+ /* Test paravirt patching: */
|
||||
+ slow_down_io(); /* paravirt call */
|
||||
+#endif
|
||||
+
|
||||
+ /* Test pr_debug: */
|
||||
+ pr_debug("kpatch: pr_debug() test\n");
|
||||
+
|
||||
+{
|
||||
+ /* Test static branches: */
|
||||
+ static DEFINE_STATIC_KEY_TRUE(kpatch_key);
|
||||
+
|
||||
+ if (static_branch_unlikely(&memcg_kmem_enabled_key))
|
||||
+ printk("kpatch: memcg_kmem_enabled_key\n");
|
||||
+
|
||||
+ BUG_ON(!static_branch_likely(&kpatch_key));
|
||||
+ static_branch_disable(&kpatch_key);
|
||||
+ BUG_ON(static_branch_likely(&kpatch_key));
|
||||
+ static_branch_enable(&kpatch_key);
|
||||
+}
|
||||
+
|
||||
return len;
|
||||
}
|
||||
|
||||
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
|
||||
index c64277659753..05b753c2ec84 100644
|
||||
--- a/net/netlink/af_netlink.c
|
||||
+++ b/net/netlink/af_netlink.c
|
||||
@@ -2980,4 +2980,9 @@ static int __init netlink_proto_init(void)
|
||||
panic("netlink_init: Cannot allocate nl_table\n");
|
||||
}
|
||||
|
||||
+char *kpatch_string(void)
|
||||
+{
|
||||
+ return "kpatch";
|
||||
+}
|
||||
+
|
||||
core_initcall(netlink_proto_init);
|
7
test/integration/linux-6.2.0/multiple.test
Executable file
7
test/integration/linux-6.2.0/multiple.test
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPTDIR="$(readlink -f $(dirname $(type -p $0)))"
|
||||
|
||||
declare -a blacklist=(meminfo-string-LOADED.test)
|
||||
|
||||
source ${SCRIPTDIR}/../common/multiple.template
|
25
test/integration/linux-6.2.0/new-function.patch
Normal file
25
test/integration/linux-6.2.0/new-function.patch
Normal file
@ -0,0 +1,25 @@
|
||||
diff -Nupr src.orig/drivers/tty/n_tty.c src/drivers/tty/n_tty.c
|
||||
--- src.orig/drivers/tty/n_tty.c 2023-01-12 11:20:06.978709342 -0500
|
||||
+++ src/drivers/tty/n_tty.c 2023-01-12 11:20:54.149989024 -0500
|
||||
@@ -2315,7 +2315,7 @@ more_to_be_read:
|
||||
* (note that the process_output*() functions take this lock themselves)
|
||||
*/
|
||||
|
||||
-static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
|
||||
+static ssize_t noinline kpatch_n_tty_write(struct tty_struct *tty, struct file *file,
|
||||
const unsigned char *buf, size_t nr)
|
||||
{
|
||||
const unsigned char *b = buf;
|
||||
@@ -2402,6 +2402,12 @@ break_out:
|
||||
return (b - buf) ? b - buf : retval;
|
||||
}
|
||||
|
||||
+static ssize_t __attribute__((optimize("-fno-optimize-sibling-calls"))) n_tty_write(struct tty_struct *tty, struct file *file,
|
||||
+ const unsigned char *buf, size_t nr)
|
||||
+{
|
||||
+ return kpatch_n_tty_write(tty, file, buf, nr);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* n_tty_poll - poll method for N_TTY
|
||||
* @tty: terminal device
|
34
test/integration/linux-6.2.0/new-globals.patch
Normal file
34
test/integration/linux-6.2.0/new-globals.patch
Normal file
@ -0,0 +1,34 @@
|
||||
diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c
|
||||
--- src.orig/fs/proc/cmdline.c 2023-01-12 11:20:07.184710563 -0500
|
||||
+++ src/fs/proc/cmdline.c 2023-01-12 11:21:02.411038005 -0500
|
||||
@@ -21,3 +21,10 @@ static int __init proc_cmdline_init(void
|
||||
return 0;
|
||||
}
|
||||
fs_initcall(proc_cmdline_init);
|
||||
+
|
||||
+#include <linux/printk.h>
|
||||
+void kpatch_print_message(void)
|
||||
+{
|
||||
+ if (!jiffies)
|
||||
+ printk("hello there!\n");
|
||||
+}
|
||||
diff -Nupr src.orig/fs/proc/meminfo.c src/fs/proc/meminfo.c
|
||||
--- src.orig/fs/proc/meminfo.c 2023-01-12 11:20:07.184710563 -0500
|
||||
+++ src/fs/proc/meminfo.c 2023-01-12 11:21:02.411038005 -0500
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <asm/page.h>
|
||||
#include "internal.h"
|
||||
|
||||
+void kpatch_print_message(void);
|
||||
+
|
||||
void __attribute__((weak)) arch_report_meminfo(struct seq_file *m)
|
||||
{
|
||||
}
|
||||
@@ -55,6 +57,7 @@ static int meminfo_proc_show(struct seq_
|
||||
sreclaimable = global_node_page_state_pages(NR_SLAB_RECLAIMABLE_B);
|
||||
sunreclaim = global_node_page_state_pages(NR_SLAB_UNRECLAIMABLE_B);
|
||||
|
||||
+ kpatch_print_message();
|
||||
show_val_kb(m, "MemTotal: ", i.totalram);
|
||||
show_val_kb(m, "MemFree: ", i.freeram);
|
||||
show_val_kb(m, "MemAvailable: ", available);
|
3
test/integration/linux-6.2.0/shadow-newpid-LOADED.test
Executable file
3
test/integration/linux-6.2.0/shadow-newpid-LOADED.test
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
grep -q newpid: /proc/$$/status
|
75
test/integration/linux-6.2.0/shadow-newpid.patch
Normal file
75
test/integration/linux-6.2.0/shadow-newpid.patch
Normal file
@ -0,0 +1,75 @@
|
||||
diff -Nupr src.orig/fs/proc/array.c src/fs/proc/array.c
|
||||
--- src.orig/fs/proc/array.c 2023-01-12 11:20:07.182710551 -0500
|
||||
+++ src/fs/proc/array.c 2023-01-12 11:21:10.821087869 -0500
|
||||
@@ -397,12 +397,19 @@ static inline void task_seccomp(struct s
|
||||
seq_putc(m, '\n');
|
||||
}
|
||||
|
||||
+#include <linux/livepatch.h>
|
||||
static inline void task_context_switch_counts(struct seq_file *m,
|
||||
struct task_struct *p)
|
||||
{
|
||||
+ int *newpid;
|
||||
+
|
||||
seq_put_decimal_ull(m, "voluntary_ctxt_switches:\t", p->nvcsw);
|
||||
seq_put_decimal_ull(m, "\nnonvoluntary_ctxt_switches:\t", p->nivcsw);
|
||||
seq_putc(m, '\n');
|
||||
+
|
||||
+ newpid = klp_shadow_get(p, 0);
|
||||
+ if (newpid)
|
||||
+ seq_printf(m, "newpid:\t%d\n", *newpid);
|
||||
}
|
||||
|
||||
static void task_cpus_allowed(struct seq_file *m, struct task_struct *task)
|
||||
diff -Nupr src.orig/kernel/exit.c src/kernel/exit.c
|
||||
--- src.orig/kernel/exit.c 2023-01-12 11:20:05.408700033 -0500
|
||||
+++ src/kernel/exit.c 2023-01-12 11:21:10.822087875 -0500
|
||||
@@ -802,6 +802,7 @@ static void synchronize_group_exit(struc
|
||||
spin_unlock_irq(&sighand->siglock);
|
||||
}
|
||||
|
||||
+#include <linux/livepatch.h>
|
||||
void __noreturn do_exit(long code)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
@@ -867,6 +868,8 @@ void __noreturn do_exit(long code)
|
||||
exit_task_work(tsk);
|
||||
exit_thread(tsk);
|
||||
|
||||
+ klp_shadow_free(tsk, 0, NULL);
|
||||
+
|
||||
/*
|
||||
* Flush inherited counters to the parent - before the parent
|
||||
* gets woken up by child-exit notifications.
|
||||
diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c
|
||||
--- src.orig/kernel/fork.c 2023-01-12 11:20:05.408700033 -0500
|
||||
+++ src/kernel/fork.c 2023-01-12 11:21:10.824087886 -0500
|
||||
@@ -2637,6 +2637,7 @@ struct task_struct *create_io_thread(int
|
||||
*
|
||||
* args->exit_signal is expected to be checked for sanity by the caller.
|
||||
*/
|
||||
+#include <linux/livepatch.h>
|
||||
pid_t kernel_clone(struct kernel_clone_args *args)
|
||||
{
|
||||
u64 clone_flags = args->flags;
|
||||
@@ -2645,6 +2646,8 @@ pid_t kernel_clone(struct kernel_clone_a
|
||||
struct task_struct *p;
|
||||
int trace = 0;
|
||||
pid_t nr;
|
||||
+ int *newpid;
|
||||
+ static int ctr = 0;
|
||||
|
||||
/*
|
||||
* For legacy clone() calls, CLONE_PIDFD uses the parent_tid argument
|
||||
@@ -2684,6 +2687,11 @@ pid_t kernel_clone(struct kernel_clone_a
|
||||
if (IS_ERR(p))
|
||||
return PTR_ERR(p);
|
||||
|
||||
+ newpid = klp_shadow_get_or_alloc(p, 0, sizeof(*newpid), GFP_KERNEL,
|
||||
+ NULL, NULL);
|
||||
+ if (newpid)
|
||||
+ *newpid = ctr++;
|
||||
+
|
||||
/*
|
||||
* Do this prior waking up the new thread - the thread pointer
|
||||
* might get invalid after that point, if the thread exits quickly.
|
22
test/integration/linux-6.2.0/special-static.patch
Normal file
22
test/integration/linux-6.2.0/special-static.patch
Normal file
@ -0,0 +1,22 @@
|
||||
diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c
|
||||
--- src.orig/kernel/fork.c 2023-01-12 11:20:05.408700033 -0500
|
||||
+++ src/kernel/fork.c 2023-01-12 11:21:19.186137466 -0500
|
||||
@@ -1700,10 +1700,18 @@ static void posix_cpu_timers_init_group(
|
||||
posix_cputimers_group_init(pct, cpu_limit);
|
||||
}
|
||||
|
||||
+void kpatch_foo(void)
|
||||
+{
|
||||
+ if (!jiffies)
|
||||
+ printk("kpatch copy signal\n");
|
||||
+}
|
||||
+
|
||||
static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
|
||||
{
|
||||
struct signal_struct *sig;
|
||||
|
||||
+ kpatch_foo();
|
||||
+
|
||||
if (clone_flags & CLONE_THREAD)
|
||||
return 0;
|
||||
|
46
test/integration/linux-6.2.0/symvers-disagreement-FAIL.patch
Normal file
46
test/integration/linux-6.2.0/symvers-disagreement-FAIL.patch
Normal file
@ -0,0 +1,46 @@
|
||||
From 2d6b7bce089e52563bd9c67df62f48e90b48047d Mon Sep 17 00:00:00 2001
|
||||
From: Julien Thierry <jthierry@redhat.com>
|
||||
Date: Wed, 6 May 2020 14:30:57 +0100
|
||||
Subject: [PATCH] Symbol version change
|
||||
|
||||
This change causes:
|
||||
1) Some exported symbols in drivers/base/core.c to see their CRCs
|
||||
change.
|
||||
2) Changes usb_get_dev() referencing a get_device() whose CRC has
|
||||
changed, causing the symbol and the new CRC to be included in the
|
||||
__version section of the final module.
|
||||
|
||||
This makes the final module unloadable for the target kernel.
|
||||
|
||||
See "Exported symbol versioning" of the patch author guide for more
|
||||
detail.
|
||||
|
||||
---
|
||||
drivers/base/core.c | 2 ++
|
||||
drivers/usb/core/usb.c | 2 ++
|
||||
2 files changed, 4 insertions(+)
|
||||
|
||||
diff -Nupr src.orig/drivers/base/core.c src/drivers/base/core.c
|
||||
--- src.orig/drivers/base/core.c 2023-01-12 11:20:06.403705933 -0500
|
||||
+++ src/drivers/base/core.c 2023-01-12 11:21:27.466186559 -0500
|
||||
@@ -36,6 +36,8 @@
|
||||
#include "physical_location.h"
|
||||
#include "power/power.h"
|
||||
|
||||
+#include <linux/blktrace_api.h>
|
||||
+
|
||||
#ifdef CONFIG_SYSFS_DEPRECATED
|
||||
#ifdef CONFIG_SYSFS_DEPRECATED_V2
|
||||
long sysfs_deprecated = 1;
|
||||
diff -Nupr src.orig/drivers/usb/core/usb.c src/drivers/usb/core/usb.c
|
||||
--- src.orig/drivers/usb/core/usb.c 2023-01-12 11:20:06.490706448 -0500
|
||||
+++ src/drivers/usb/core/usb.c 2023-01-12 11:21:27.468186571 -0500
|
||||
@@ -697,6 +697,8 @@ EXPORT_SYMBOL_GPL(usb_alloc_dev);
|
||||
*/
|
||||
struct usb_device *usb_get_dev(struct usb_device *dev)
|
||||
{
|
||||
+ barrier();
|
||||
+
|
||||
if (dev)
|
||||
get_device(&dev->dev);
|
||||
return dev;
|
3
test/integration/linux-6.2.0/syscall-LOADED.test
Executable file
3
test/integration/linux-6.2.0/syscall-LOADED.test
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
uname -s | grep -q kpatch
|
20
test/integration/linux-6.2.0/syscall.patch
Normal file
20
test/integration/linux-6.2.0/syscall.patch
Normal file
@ -0,0 +1,20 @@
|
||||
diff -Nupr src.orig/kernel/sys.c src/kernel/sys.c
|
||||
--- src.orig/kernel/sys.c 2023-01-12 11:20:05.406700021 -0500
|
||||
+++ src/kernel/sys.c 2023-01-12 11:21:35.782235867 -0500
|
||||
@@ -1285,13 +1285,15 @@ static int override_release(char __user
|
||||
return ret;
|
||||
}
|
||||
|
||||
-SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
|
||||
+#include "kpatch-syscall.h"
|
||||
+KPATCH_SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
|
||||
{
|
||||
struct new_utsname tmp;
|
||||
|
||||
down_read(&uts_sem);
|
||||
memcpy(&tmp, utsname(), sizeof(tmp));
|
||||
up_read(&uts_sem);
|
||||
+ strcat(tmp.sysname, ".kpatch");
|
||||
if (copy_to_user(name, &tmp, sizeof(tmp)))
|
||||
return -EFAULT;
|
||||
|
9
test/integration/linux-6.2.0/warn-detect-FAIL.patch
Normal file
9
test/integration/linux-6.2.0/warn-detect-FAIL.patch
Normal file
@ -0,0 +1,9 @@
|
||||
diff -Nupr src.orig/arch/x86/kvm/x86.c src/arch/x86/kvm/x86.c
|
||||
--- src.orig/arch/x86/kvm/x86.c 2023-01-12 11:20:04.716695930 -0500
|
||||
+++ src/arch/x86/kvm/x86.c 2023-01-12 11:21:44.162285556 -0500
|
||||
@@ -1,4 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
+
|
||||
/*
|
||||
* Kernel-based Virtual Machine driver for Linux
|
||||
*
|
Loading…
Reference in New Issue
Block a user