Re: [PATCH v7 03/10] kbuild/modpost: create symbols.klp and integrate klp-convert

From: Marcos Paulo de Souza
Date: Tue Mar 14 2023 - 14:49:41 EST


On Mon, Mar 06, 2023 at 09:08:17AM -0500, Joe Lawrence wrote:
> For automatic resolution of livepatch relocations, a file called
> symbols.klp is used. This file maps symbols within every compiled kernel
> object allowing the identification of symbols whose name is unique, thus
> relocation can be automatically inferred, or providing information that
> helps developers when code annotation is required for solving the
> matter.
>
> Add support for creating symbols.klp in the main Makefile. First, ensure
> that built-in is compiled when CONFIG_LIVEPATCH is enabled (as required
> to achieve a complete symbols.klp file). Define the command to build
> symbols.klp (filechk_klp_map) and hook it in the modules rule. Save the
> list of livepatch modules in $(MODULES_LIVEPATCH).
>
> As it is undesirable to have symbols from livepatch objects inside
> symbols.klp, filechk_klp_map filters out modules.livepatch from
> modules.order: `sort $(MODORDER) $(MODULES_LIVEPATCH) | uniq -u`.
>
> The "clean" Makefile target may remove the modules.livepatch file,
> however, symbols.klp may be needed for building external modules, so
> defer its cleanup to the "mrproper" target.
>
> Finally, update the modpost program so that it does not warn about
> unresolved symbols resolved by klp-convert.
>

I don't have strong skills on Kbuild, but the changes makes sense.

Acked-by: Marcos Paulo de Souza <mpdesouza@xxxxxxxx>

> 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 | 2 ++
> Documentation/dontdiff | 1 +
> Makefile | 16 +++++++++++-----
> scripts/Makefile.modfinal | 33 +++++++++++++++++++++++++++++++++
> scripts/Makefile.modpost | 5 +++++
> scripts/mod/modpost.c | 28 ++++++++++++++++++++++++++--
> scripts/mod/modpost.h | 1 +
> 7 files changed, 79 insertions(+), 7 deletions(-)
>
> diff --git a/.gitignore b/.gitignore
> index 20dce5c3b9e0..fc9b2f13b049 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -53,6 +53,7 @@
> *.xz
> *.zst
> Module.symvers
> +modules.livepatch
> modules.order
>
> #
> @@ -66,6 +67,7 @@ modules.order
> /vmlinux.symvers
> /vmlinux-gdb.py
> /vmlinuz
> +/symbols.klp
> /System.map
> /Module.markers
> /modules.builtin
> diff --git a/Documentation/dontdiff b/Documentation/dontdiff
> index 352ff53a2306..23c2a89fb791 100644
> --- a/Documentation/dontdiff
> +++ b/Documentation/dontdiff
> @@ -76,6 +76,7 @@ Module.markers
> Module.symvers
> PENDING
> SCCS
> +symbols.klp
> System.map*
> TAGS
> aconf
> diff --git a/Makefile b/Makefile
> index 3f6628780eb2..dd5d6c258906 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -730,8 +730,13 @@ KBUILD_MODULES :=
> KBUILD_BUILTIN := 1
>
> # If we have only "make modules", don't compile built-in objects.
> +# When we're building livepatch modules, we need to consider the
> +# built-in objects during the descend as well, as built-in objects may
> +# hold symbols which are referenced from livepatches and are required by
> +# klp-convert post-processing tool for resolving these cases.
> +
> ifeq ($(MAKECMDGOALS),modules)
> - KBUILD_BUILTIN :=
> + KBUILD_BUILTIN := $(if $(CONFIG_LIVEPATCH),1)
> endif
>
> # If we have "make <whatever> modules", compile modules
> @@ -1183,6 +1188,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),)
>
> @@ -1543,8 +1549,8 @@ endif
> #
>
> # *.ko are usually independent of vmlinux, but CONFIG_DEBUG_INFOBTF_MODULES
> -# is an exception.
> -ifdef CONFIG_DEBUG_INFO_BTF_MODULES
> +# and CONFIG_LIVEPATCH are exceptions.
> +ifneq ($(or $(CONFIG_DEBUG_INFO_BTF_MODULES),$(CONFIG_LIVEPATCH)),)
> KBUILD_BUILTIN := 1
> modules: vmlinux
> endif
> @@ -1602,14 +1608,14 @@ endif # CONFIG_MODULES
> CLEAN_FILES += include/ksym vmlinux.symvers modules-only.symvers \
> modules.builtin modules.builtin.modinfo modules.nsdeps \
> compile_commands.json .thinlto-cache rust/test rust/doc \
> - .vmlinux.objs .vmlinux.export.c
> + modules.livepatch .vmlinux.objs .vmlinux.export.c
>
> # Directories & files removed with 'make mrproper'
> MRPROPER_FILES += include/config include/generated \
> arch/$(SRCARCH)/include/generated .objdiff \
> debian snap tar-install \
> .config .config.old .version \
> - Module.symvers \
> + Module.symvers symbols.klp \
> certs/signing_key.pem \
> certs/x509.genkey \
> vmlinux-gdb.py \
> diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal
> index a30d5b08eee9..a8901e4e98c5 100644
> --- a/scripts/Makefile.modfinal
> +++ b/scripts/Makefile.modfinal
> @@ -14,6 +14,7 @@ include $(srctree)/scripts/Makefile.lib
>
> # find all modules listed in modules.order
> modules := $(call read-file, $(MODORDER))
> +modules-klp := $(call read-file, $(MODULES_LIVEPATCH))
>
> __modfinal: $(modules:%.o=%.ko)
> @:
> @@ -65,6 +66,38 @@ endif
>
> targets += $(modules:%.o=%.ko) $(modules:%.o=%.mod.o)
>
> +# Livepatch
> +# ---------------------------------------------------------------------------
> +
> +%.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:%.o=%.ko): %.ko: %.tmp.ko FORCE
> + $(call if_changed,klp_convert)
> +
> +targets += $(modules-klp:.ko=.tmp.ko)
> +
> +ifeq ($(KBUILD_EXTMOD),)
> +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/\.o$$//' | \
> + 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 43343e13c542..02f1354d4cff 100644
> --- a/scripts/Makefile.modpost
> +++ b/scripts/Makefile.modpost
> @@ -47,6 +47,7 @@ modpost-args = \
> $(if $(KBUILD_MODPOST_WARN),-w) \
> $(if $(KBUILD_NSDEPS),-d $(MODULES_NSDEPS)) \
> $(if $(CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS)$(KBUILD_NSDEPS),-N) \
> + $(if $(CONFIG_LIVEPATCH),-l $(MODULES_LIVEPATCH)) \
> -o $@
>
> modpost-deps := $(MODPOST)
> @@ -138,6 +139,10 @@ $(output-symdump): $(modpost-deps) FORCE
> $(call if_changed,modpost)
>
> __modpost: $(output-symdump)
> +ifndef CONFIG_LIVEPATCH
> + $(Q)rm -f $(MODULES_LIVEPATCH)
> + $(Q)touch $(MODULES_LIVEPATCH)
> +endif
> PHONY += FORCE
> FORCE:
>
> diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
> index efff8078e395..0a8f0ce75761 100644
> --- a/scripts/mod/modpost.c
> +++ b/scripts/mod/modpost.c
> @@ -1831,6 +1831,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->is_livepatch = true;
> +
> for (sym = info.symtab_start; sym < info.symtab_stop; sym++) {
> symname = remove_dot(info.strtab + sym->st_name);
>
> @@ -1919,7 +1923,7 @@ static void check_exports(struct module *mod)
> const char *basename;
> exp = find_symbol(s->name);
> if (!exp) {
> - if (!s->weak && nr_unresolved++ < MAX_UNRESOLVED_REPORTS)
> + if (!s->weak && !mod->is_livepatch && nr_unresolved++ < MAX_UNRESOLVED_REPORTS)
> modpost_log(warn_unresolved ? LOG_WARN : LOG_ERROR,
> "\"%s\" [%s.ko] undefined!\n",
> s->name, mod->name);
> @@ -2320,6 +2324,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;
> +
> + list_for_each_entry(mod, &modules, list) {
> + if (mod->is_livepatch)
> + buf_printf(&buf, "%s.o\n", mod->name);
> + }
> +
> + write_if_changed(&buf, fname);
> + free(buf.p);
> +}
> +
> struct dump_list {
> struct list_head list;
> const char *file;
> @@ -2330,11 +2348,12 @@ int main(int argc, char **argv)
> struct module *mod;
> char *missing_namespace_deps = NULL;
> char *dump_write = NULL, *files_source = NULL;
> + char *livepatch_modules = NULL;
> int opt;
> LIST_HEAD(dump_lists);
> struct dump_list *dl, *dl2;
>
> - 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 = true;
> @@ -2344,6 +2363,9 @@ int main(int argc, char **argv)
> dl->file = optarg;
> list_add_tail(&dl->list, &dump_lists);
> break;
> + case 'l':
> + livepatch_modules = optarg;
> + break;
> case 'm':
> modversions = true;
> break;
> @@ -2403,6 +2425,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 1178f40a73f3..9be9bf6fb7da 100644
> --- a/scripts/mod/modpost.h
> +++ b/scripts/mod/modpost.h
> @@ -119,6 +119,7 @@ struct module {
> bool is_gpl_compatible;
> bool from_dump; /* true if module was loaded from *.symvers */
> bool is_vmlinux;
> + bool is_livepatch;
> bool seen;
> bool has_init;
> bool has_cleanup;
> --
> 2.39.2
>