From: Josh Poimboeuf <jpoimboe@xxxxxxxxxx> Create cmd_klp_convert and hook it into scripts/Makefile.modpost. cmd_klp_convert invokes klp-convert with the right arguments for the conversion of unresolved symbols inside a livepatch. Signed-off-by: Josh Poimboeuf <jpoimboe@xxxxxxxxxx> Signed-off-by: Konstantin Khlebnikov <khlebnikov@xxxxxxxxxxxxxx> Signed-off-by: Miroslav Benes <mbenes@xxxxxxx> Signed-off-by: Joao Moreira <jmoreira@xxxxxxx> Signed-off-by: Joe Lawrence <joe.lawrence@xxxxxxxxxx> --- .gitignore | 1 + Makefile | 18 ++---------------- scripts/Makefile.modfinal | 38 +++++++++++++++++++++++++++++++++++++- scripts/Makefile.modpost | 5 +++++ scripts/mod/modpost.c | 28 ++++++++++++++++++++++++++-- scripts/mod/modpost.h | 1 + 6 files changed, 72 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 50638a15a527..eb0179d00260 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ *.xz *.zst Module.symvers +modules.livepatch modules.order # diff --git a/Makefile b/Makefile index 64ec4bc8172c..31d5b6f608d9 100644 --- a/Makefile +++ b/Makefile @@ -1089,6 +1089,7 @@ PHONY += prepare0 export extmod_prefix = $(if $(KBUILD_EXTMOD),$(KBUILD_EXTMOD)/) export MODORDER := $(extmod_prefix)modules.order export MODULES_NSDEPS := $(extmod_prefix)modules.nsdeps +export MODULES_LIVEPATCH := $(extmod-prefix)modules.livepatch ifeq ($(KBUILD_EXTMOD),) core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ @@ -1485,7 +1486,7 @@ endif # CONFIG_MODULES # Directories & files removed with 'make clean' CLEAN_FILES += include/ksym vmlinux.symvers modules-only.symvers \ modules.builtin modules.builtin.modinfo modules.nsdeps \ - compile_commands.json .thinlto-cache + compile_commands.json .thinlto-cache modules.livepatch # Directories & files removed with 'make mrproper' MRPROPER_FILES += include/config include/generated \ @@ -1747,22 +1748,7 @@ PHONY += modules modules_install ifdef CONFIG_MODULES -quiet_cmd_klp_map = KLP symbols.klp - -define cmd_klp_map - $(shell echo "klp-convert-symbol-data.0.1" > $(objtree)/symbols.klp) \ - $(shell echo "*vmlinux" >> $(objtree)/symbols.klp) \ - $(shell nm -f posix $(objtree)/vmlinux | cut -d\ -f1 >> $(objtree)/symbols.klp) \ - $(foreach ko, $(sort $(shell cat modules.order)), \ - $(eval mod = $(patsubst %.ko,%.mod,$(ko))) \ - $(eval obj = $(patsubst %.ko,%.o,$(ko))) \ - $(if $(shell grep -o LIVEPATCH $(mod)),, \ - $(shell echo "*$(shell basename -s .ko $(ko))" >> $(objtree)/symbols.klp) \ - $(shell nm -f posix $(obj) | cut -d\ -f1 >> $(objtree)/symbols.klp))) -endef - modules: modules_check - $(if $(CONFIG_LIVEPATCH), $(call cmd,klp_map)) $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost PHONY += modules_check diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal index 7f39599e9fae..cb31262436ba 100644 --- a/scripts/Makefile.modfinal +++ b/scripts/Makefile.modfinal @@ -14,6 +14,8 @@ include $(srctree)/scripts/Makefile.lib # find all modules listed in modules.order modules := $(sort $(shell cat $(MODORDER))) +modules-klp := $(sort $(shell cat $(MODULES_LIVEPATCH))) +modules-no-klp := $(filter-out $(modules-klp), $(modules)) __modfinal: $(modules) @: @@ -56,7 +58,7 @@ if_changed_except = $(if $(call newer_prereqs_except,$(2))$(cmd-check), \ # Re-generate module BTFs if either module's .ko or vmlinux changed -$(modules): %.ko: %$(mod-prelink-ext).o %.mod.o scripts/module.lds $(if $(KBUILD_BUILTIN),vmlinux) FORCE +$(modules-no-klp): %.ko: %$(mod-prelink-ext).o %.mod.o scripts/module.lds $(if $(KBUILD_BUILTIN),vmlinux) FORCE +$(call if_changed_except,ld_ko_o,vmlinux) ifdef CONFIG_DEBUG_INFO_BTF_MODULES +$(if $(newer-prereqs),$(call cmd,btf_ko)) @@ -64,6 +66,40 @@ endif targets += $(modules) $(modules:.ko=.mod.o) +# Live Patch +# --------------------------------------------------------------------------- + +%.tmp.ko: %.o %.mod.o symbols.klp FORCE + +$(call if_changed,ld_ko_o) + +quiet_cmd_klp_convert = KLP $@ + cmd_klp_convert = scripts/livepatch/klp-convert symbols.klp $< $@ + +$(modules-klp): %.ko: %.tmp.ko FORCE + $(call if_changed,klp_convert) + +targets += $(modules-klp:.ko=.tmp.ko) + +ifeq ($(KBUILD_EXTMOD),) +# Read out modules.{order,livepatch} instead of expanding $(modules-no-klp). +# Otherwise, allmodconfig would fail with "Argument list too long". +filechk_klp_map = \ + echo "klp-convert-symbol-data.0.1"; \ + echo "*vmlinux"; \ + $(NM) -f posix vmlinux | cut -d\ -f1; \ + sort $(MODORDER) $(MODULES_LIVEPATCH) | \ + uniq -u | \ + sed 's/\.ko$$//' | \ + while read o; \ + do \ + echo "*$$(basename $$o)"; \ + $(NM) -f posix $$o.o | cut -d\ -f1; \ + done + +symbols.klp: FORCE + $(call filechk,klp_map) +endif + # Add FORCE to the prequisites of a target to force it to be always rebuilt. # --------------------------------------------------------------------------- diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 48585c4d04ad..c5df629de7b2 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -48,6 +48,7 @@ MODPOST = scripts/mod/modpost \ $(if $(CONFIG_MODVERSIONS),-m) \ $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a) \ $(if $(CONFIG_SECTION_MISMATCH_WARN_ONLY),,-E) \ + $(if $(CONFIG_LIVEPATCH),-l $(MODULES_LIVEPATCH)) \ -o $@ ifdef MODPOST_VMLINUX @@ -136,6 +137,10 @@ $(output-symdump): $(MODORDER) $(input-symdump) $(modules:.ko=$(mod-prelink-ext) targets += $(output-symdump) __modpost: $(output-symdump) +ifndef CONFIG_LIVEPATCH + $(Q)rm -f $(MODULES_LIVEPATCH) + $(Q)touch $(MODULES_LIVEPATCH) +endif ifneq ($(KBUILD_MODPOST_NOFINAL),1) $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modfinal endif diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 6bfa33217914..1034b673c95c 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -2051,6 +2051,10 @@ static void read_symbols(const char *modname) handle_moddevtable(mod, &info, sym, symname); } + /* Livepatch modules have unresolved symbols resolved by klp-convert */ + if (get_modinfo(&info, "livepatch")) + mod->livepatch = 1; + for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { symname = remove_dot(info.strtab + sym->st_name); @@ -2170,7 +2174,7 @@ static void check_exports(struct module *mod) const char *basename; exp = find_symbol(s->name); if (!exp || exp->module == mod) { - if (!s->weak && nr_unresolved++ < MAX_UNRESOLVED_REPORTS) + if (!s->weak && !mod->livepatch && nr_unresolved++ < MAX_UNRESOLVED_REPORTS) modpost_log(warn_unresolved ? LOG_WARN : LOG_ERROR, "\"%s\" [%s.ko] undefined!\n", s->name, mod->name); @@ -2502,6 +2506,20 @@ static void write_namespace_deps_files(const char *fname) free(ns_deps_buf.p); } +static void write_livepatch_modules(const char *fname) +{ + struct buffer buf = { }; + struct module *mod; + + for (mod = modules; mod; mod = mod->next) { + if (mod->livepatch) + buf_printf(&buf, "%s.ko\n", mod->name); + } + + write_if_changed(&buf, fname); + free(buf.p); +} + struct dump_list { struct dump_list *next; const char *file; @@ -2513,12 +2531,13 @@ int main(int argc, char **argv) struct buffer buf = { }; char *missing_namespace_deps = NULL; char *dump_write = NULL, *files_source = NULL; + char *livepatch_modules = NULL; int opt; int n; struct dump_list *dump_read_start = NULL; struct dump_list **dump_read_iter = &dump_read_start; - while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:")) != -1) { + while ((opt = getopt(argc, argv, "ei:l:mnT:o:awENd:")) != -1) { switch (opt) { case 'e': external_module = 1; @@ -2529,6 +2548,9 @@ int main(int argc, char **argv) (*dump_read_iter)->file = optarg; dump_read_iter = &(*dump_read_iter)->next; break; + case 'l': + livepatch_modules = optarg; + break; case 'm': modversions = 1; break; @@ -2605,6 +2627,8 @@ int main(int argc, char **argv) if (dump_write) write_dump(dump_write); + if (livepatch_modules) + write_livepatch_modules(livepatch_modules); if (sec_mismatch_count && !sec_mismatch_warn_only) error("Section mismatches detected.\n" "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n"); diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 0c47ff95c0e2..8c7e7e546158 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -123,6 +123,7 @@ struct module { int seen; int has_init; int has_cleanup; + int livepatch; struct buffer dev_table_buf; char srcversion[25]; // Missing namespace dependencies -- 2.26.3