From 29b67264bd171be9e8d89abcb0074e12cde66c24 Mon Sep 17 00:00:00 2001 From: "zhangyongde.zyd" Date: Tue, 26 Dec 2023 14:43:22 +0800 Subject: [PATCH] create-diff-object: detect unsupported static calls commit f83218ad12a2d9e20d99d379c78974a576aa558c upstream Similar to jump labels, static calls aren't supported when the static call key was originally defined in a module rather than in vmlinux. Detect those cases and either remove them (in the case of tracepoints) or error out. This patch used to detect the static call inside the module object which is not supported. Static calls are only supported in the case where the corresponding atic call key lives in vmlinux. --- kpatch-build/create-diff-object.c | 69 ++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 431d1e7..5cd4379 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -72,7 +72,7 @@ enum loglevel loglevel = NORMAL; bool KLP_ARCH; bool multi_pfe; -int jump_label_errors; +int jump_label_errors, static_call_errors; /******************* * Data structures @@ -2434,6 +2434,68 @@ static bool jump_table_group_filter(struct lookup_table *lookup, return true; } +static bool static_call_sites_group_filter(struct lookup_table *lookup, + struct section *relasec, + unsigned int group_offset, + unsigned int group_size) +{ + struct rela *code = NULL, *key = NULL, *rela; + bool tracepoint = false; + struct lookup_result symbol; + int i = 0; + + /* + * Here we hard-code knowledge about the contents of the jump_entry + * struct. It has three fields: code, target, and key. Each field has + * a relocation associated with it. + */ + list_for_each_entry(rela, &relasec->relas, list) { + if (rela->offset >= group_offset && + rela->offset < group_offset + group_size) { + if (i == 0) + code = rela; + else if (i == 1) + key = rela; + i++; + } + } + + if (i != 2 || !key || !code) + ERROR("BUG: .static_call_sites has an unexpected format"); + + if (!strncmp(key->sym->name, "__SCK__tp_func_", 15)) + tracepoint = true; + + /* + * Static calls are only supported in the case where the corresponding + * static call key lives in vmlinux (see explanation in + * jump_table_group_filter). + */ + + if (lookup_symbol(lookup, key->sym, &symbol) && + strcmp(symbol.objname, "vmlinux")) { + + /* The key lives in a module -- not supported */ + + /* Inert tracepoints are harmless */ + if (tracepoint) + return false; + + /* + * This will be upgraded to an error after all static call + * errors have been reported. + */ + log_normal("Found a static call at %s()+0x%lx, using key %s, which is defined in a module. Use KPATCH_STATIC_CALL() instead.\n", + code->sym->name, code->addend, key->sym->name); + static_call_errors++; + return false; + } + + /* The key lives in vmlinux or the patch module itself */ + return true; +} + + static struct special_section special_sections[] = { { .name = "__bug_table", @@ -2480,6 +2542,7 @@ static struct special_section special_sections[] = { .name = ".static_call_sites", .arch = X86_64, .group_size = static_call_sites_group_size, + .group_filter = static_call_sites_group_filter, }, { .name = ".retpoline_sites", @@ -2677,6 +2740,10 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf, ERROR("Found %d unsupported jump label(s) in the patched code. Use static_key_enabled() instead.", jump_label_errors); + if (static_call_errors) + ERROR("Found %d unsupported static call(s) in the patched code. Use KPATCH_STATIC_CALL() instead.", + static_call_errors); + if (!dest_offset) { /* no changed or global functions referenced */ relasec->status = relasec->base->status = SAME; -- Gitee