From: Miroslav Benes <mbenes@xxxxxxx> Currently, livepatch infrastructure in the kernel relies on MODULE_INFO(livepatch, "Y") statement in a livepatch module. Then the kernel module loader knows a module is indeed livepatch module and can behave accordingly. klp-convert, on the other hand relies on LIVEPATCH_* statement in the module's Makefile for exactly the same reason. Remove dependency on modinfo and generate MODULE_INFO flag automatically in modpost when LIVEPATCH_* is defined in the module's Makefile. Generate a list of all built livepatch modules based on the .livepatch file and store it in (MODVERDIR)/livepatchmods. Give this list as an argument for modpost which will use it to identify livepatch modules. As MODULE_INFO is no longer needed, remove it. Signed-off-by: Miroslav Benes <mbenes@xxxxxxx> Signed-off-by: Joao Moreira <jmoreira@xxxxxxx> Signed-off-by: Joe Lawrence <joe.lawrence@xxxxxxxxxx> --- lib/livepatch/Makefile | 5 ++ lib/livepatch/test_klp_atomic_replace.c | 1 - lib/livepatch/test_klp_callbacks_demo.c | 1 - lib/livepatch/test_klp_callbacks_demo2.c | 1 - lib/livepatch/test_klp_livepatch.c | 1 - samples/livepatch/Makefile | 4 ++ samples/livepatch/livepatch-sample.c | 1 - scripts/Makefile.modpost | 8 ++- scripts/mod/modpost.c | 84 ++++++++++++++++++++++-- 9 files changed, 94 insertions(+), 12 deletions(-) diff --git a/lib/livepatch/Makefile b/lib/livepatch/Makefile index 26900ddaef82..513d200b7942 100644 --- a/lib/livepatch/Makefile +++ b/lib/livepatch/Makefile @@ -2,6 +2,11 @@ # # Makefile for livepatch test code. +LIVEPATCH_test_klp_atomic_replace := y +LIVEPATCH_test_klp_callbacks_demo := y +LIVEPATCH_test_klp_callbacks_demo2 := y +LIVEPATCH_test_klp_livepatch := y + obj-$(CONFIG_TEST_LIVEPATCH) += test_klp_atomic_replace.o \ test_klp_callbacks_demo.o \ test_klp_callbacks_demo2.o \ diff --git a/lib/livepatch/test_klp_atomic_replace.c b/lib/livepatch/test_klp_atomic_replace.c index 5af7093ca00c..3bf08a1b7b12 100644 --- a/lib/livepatch/test_klp_atomic_replace.c +++ b/lib/livepatch/test_klp_atomic_replace.c @@ -52,6 +52,5 @@ static void test_klp_atomic_replace_exit(void) module_init(test_klp_atomic_replace_init); module_exit(test_klp_atomic_replace_exit); MODULE_LICENSE("GPL"); -MODULE_INFO(livepatch, "Y"); MODULE_AUTHOR("Joe Lawrence <joe.lawrence@xxxxxxxxxx>"); MODULE_DESCRIPTION("Livepatch test: atomic replace"); diff --git a/lib/livepatch/test_klp_callbacks_demo.c b/lib/livepatch/test_klp_callbacks_demo.c index 3fd8fe1cd1cc..76e2f51a6771 100644 --- a/lib/livepatch/test_klp_callbacks_demo.c +++ b/lib/livepatch/test_klp_callbacks_demo.c @@ -116,6 +116,5 @@ static void test_klp_callbacks_demo_exit(void) module_init(test_klp_callbacks_demo_init); module_exit(test_klp_callbacks_demo_exit); MODULE_LICENSE("GPL"); -MODULE_INFO(livepatch, "Y"); MODULE_AUTHOR("Joe Lawrence <joe.lawrence@xxxxxxxxxx>"); MODULE_DESCRIPTION("Livepatch test: livepatch demo"); diff --git a/lib/livepatch/test_klp_callbacks_demo2.c b/lib/livepatch/test_klp_callbacks_demo2.c index 5417573e80af..76db98fc3071 100644 --- a/lib/livepatch/test_klp_callbacks_demo2.c +++ b/lib/livepatch/test_klp_callbacks_demo2.c @@ -88,6 +88,5 @@ static void test_klp_callbacks_demo2_exit(void) module_init(test_klp_callbacks_demo2_init); module_exit(test_klp_callbacks_demo2_exit); MODULE_LICENSE("GPL"); -MODULE_INFO(livepatch, "Y"); MODULE_AUTHOR("Joe Lawrence <joe.lawrence@xxxxxxxxxx>"); MODULE_DESCRIPTION("Livepatch test: livepatch demo2"); diff --git a/lib/livepatch/test_klp_livepatch.c b/lib/livepatch/test_klp_livepatch.c index aff08199de71..d94d0ae232db 100644 --- a/lib/livepatch/test_klp_livepatch.c +++ b/lib/livepatch/test_klp_livepatch.c @@ -46,6 +46,5 @@ static void test_klp_livepatch_exit(void) module_init(test_klp_livepatch_init); module_exit(test_klp_livepatch_exit); MODULE_LICENSE("GPL"); -MODULE_INFO(livepatch, "Y"); MODULE_AUTHOR("Seth Jennings <sjenning@xxxxxxxxxx>"); MODULE_DESCRIPTION("Livepatch test: livepatch module"); diff --git a/samples/livepatch/Makefile b/samples/livepatch/Makefile index 8b9b42a258ad..5fb3280bbdc4 100644 --- a/samples/livepatch/Makefile +++ b/samples/livepatch/Makefile @@ -1,4 +1,8 @@ LIVEPATCH_livepatch-sample := y +LIVEPATCH_livepatch-shadow-fix1 := y +LIVEPATCH_livepatch-shadow-fix2 := y +LIVEPATCH_livepatch-callbacks-demo := y + obj-$(CONFIG_SAMPLE_LIVEPATCH) += livepatch-sample.o obj-$(CONFIG_SAMPLE_LIVEPATCH) += livepatch-shadow-mod.o obj-$(CONFIG_SAMPLE_LIVEPATCH) += livepatch-shadow-fix1.o diff --git a/samples/livepatch/livepatch-sample.c b/samples/livepatch/livepatch-sample.c index 01c9cf003ca2..8900a175046b 100644 --- a/samples/livepatch/livepatch-sample.c +++ b/samples/livepatch/livepatch-sample.c @@ -79,4 +79,3 @@ static void livepatch_exit(void) module_init(livepatch_init); module_exit(livepatch_exit); MODULE_LICENSE("GPL"); -MODULE_INFO(livepatch, "Y"); diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 1e8bb7442689..9fe4c5760aca 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -65,6 +65,11 @@ MODLISTCMD := find $(MODVERDIR) -name '*.mod' | xargs -r grep -h '\.ko$$' | sort __modules := $(shell $(MODLISTCMD)) modules := $(patsubst %.o,%.ko, $(wildcard $(__modules:.ko=.o))) +# find all .livepatch files listed in $(MODVERDIR)/ +ifdef CONFIG_LIVEPATCH +$(shell find $(MODVERDIR) -name '*.livepatch' | xargs -r -I{} basename {} .livepatch > $(MODVERDIR)/livepatchmods) +endif + # Stop after building .o files if NOFINAL is set. Makes compile tests quicker _modpost: $(if $(KBUILD_MODPOST_NOFINAL), $(modules:.ko:.o),$(modules)) @@ -78,7 +83,8 @@ modpost = scripts/mod/modpost \ $(if $(KBUILD_EXTRA_SYMBOLS), $(patsubst %, -e %,$(KBUILD_EXTRA_SYMBOLS))) \ $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \ $(if $(CONFIG_SECTION_MISMATCH_WARN_ONLY),,-E) \ - $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) + $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) \ + $(if $(CONFIG_LIVEPATCH),-l $(MODVERDIR)/livepatchmods) MODPOST_OPT=$(subst -i,-n,$(filter -i,$(MAKEFLAGS))) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 374b22c76ec5..b3ab17d9d834 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1974,10 +1974,6 @@ static void read_symbols(const char *modname) license = get_next_modinfo(&info, "license", license); } - /* 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); @@ -2416,6 +2412,76 @@ static void write_dump(const char *fname) free(buf.p); } +struct livepatch_mod_list { + struct livepatch_mod_list *next; + char *livepatch_mod; +}; + +static struct livepatch_mod_list *load_livepatch_mods(const char *fname) +{ + struct livepatch_mod_list *list_iter, *list_start = NULL; + unsigned long size, pos = 0; + void *file = grab_file(fname, &size); + char *line; + + if (!file) + return NULL; + + while ((line = get_next_line(&pos, file, size))) { + list_iter = NOFAIL(malloc(sizeof(*list_iter))); + list_iter->next = list_start; + list_iter->livepatch_mod = NOFAIL(strdup(line)); + list_start = list_iter; + } + release_file(file, size); + + return list_start; +} + +static void free_livepatch_mods(struct livepatch_mod_list *list_start) +{ + struct livepatch_mod_list *list_iter; + + while (list_start) { + list_iter = list_start->next; + free(list_start->livepatch_mod); + free(list_start); + list_start = list_iter; + } +} + +static int is_livepatch_mod(const char *modname, + struct livepatch_mod_list *list) +{ + const char *myname; + + if (!list) + return 0; + + myname = strrchr(modname, '/'); + if (myname) + myname++; + else + myname = modname; + + while (list) { + if (!strcmp(myname, list->livepatch_mod)) + return 1; + list = list->next; + } + return 0; +} + +static void add_livepatch_flag(struct buffer *b, struct module *mod, + struct livepatch_mod_list *list) +{ + if (is_livepatch_mod(mod->name, list)) { + buf_printf(b, "\nMODULE_INFO(livepatch, \"Y\");\n"); + mod->livepatch = 1; + } +} + + struct ext_sym_list { struct ext_sym_list *next; const char *file; @@ -2431,8 +2497,9 @@ int main(int argc, char **argv) int err; struct ext_sym_list *extsym_iter; struct ext_sym_list *extsym_start = NULL; + struct livepatch_mod_list *livepatch_mods = NULL; - while ((opt = getopt(argc, argv, "i:I:e:mnsT:o:awE")) != -1) { + while ((opt = getopt(argc, argv, "i:I:e:l:mnsT:o:awE")) != -1) { switch (opt) { case 'i': kernel_read = optarg; @@ -2449,6 +2516,9 @@ int main(int argc, char **argv) extsym_iter->file = optarg; extsym_start = extsym_iter; break; + case 'l': + livepatch_mods = load_livepatch_mods(optarg); + break; case 'm': modversions = 1; break; @@ -2506,15 +2576,16 @@ int main(int argc, char **argv) buf.pos = 0; err |= check_modname_len(mod); - err |= check_exports(mod); add_header(&buf, mod); add_intree_flag(&buf, !external_module); add_retpoline(&buf); add_staging_flag(&buf, mod->name); + add_livepatch_flag(&buf, mod, livepatch_mods); err |= add_versions(&buf, mod); add_depends(&buf, mod); add_moddevtable(&buf, mod); add_srcversion(&buf, mod); + err |= check_exports(mod); sprintf(fname, "%s.mod.c", mod->name); write_if_changed(&buf, fname); @@ -2524,6 +2595,7 @@ int main(int argc, char **argv) if (sec_mismatch_count && sec_mismatch_fatal) fatal("modpost: Section mismatches detected.\n" "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n"); + free_livepatch_mods(livepatch_mods); free(buf.p); return err; -- 2.20.1