Skip to content

Commit

Permalink
Merge pull request dynup#1322 from joe-lawrence/v6.2-support
Browse files Browse the repository at this point in the history
Upstream kernel v6.2 support
  • Loading branch information
jpoimboe authored Apr 14, 2023
2 parents 0dc10ca + f499fc2 commit 73cdcb1
Show file tree
Hide file tree
Showing 23 changed files with 692 additions and 11 deletions.
31 changes: 29 additions & 2 deletions kmod/patch/kpatch-syscall.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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); \
Expand Down Expand Up @@ -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 */


Expand Down
39 changes: 33 additions & 6 deletions kpatch-build/create-diff-object.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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) {
Expand Down
3 changes: 2 additions & 1 deletion kpatch-build/gcc-plugins/gcc-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions kpatch-build/kpatch-build
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions kpatch-build/kpatch-cc
Original file line number Diff line number Diff line change
Expand Up @@ -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/*|\
Expand Down
93 changes: 93 additions & 0 deletions kpatch-build/kpatch-elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions kpatch-build/kpatch-elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -91,6 +92,7 @@ struct symbol {
enum symbol_strip strip; /* used in the output elf */
};
int has_func_profiling;
bool is_pfx;
};

struct rela {
Expand Down
3 changes: 3 additions & 0 deletions test/integration/linux-6.2.0/data-new-LOADED.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

grep "kpatch: 5" /proc/meminfo
20 changes: 20 additions & 0 deletions test/integration/linux-6.2.0/data-new.patch
Original file line number Diff line number Diff line change
@@ -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 changes: 22 additions & 0 deletions test/integration/linux-6.2.0/gcc-static-local-var-6.patch
Original file line number Diff line number Diff line change
@@ -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)
Loading

0 comments on commit 73cdcb1

Please sign in to comment.