From: Miroslav Benes <mbe...@suse.cz>

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 <mbe...@suse.cz>
Signed-off-by: Joao Moreira <jmore...@suse.de>
Signed-off-by: Joe Lawrence <joe.lawre...@redhat.com>
---
 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.lawre...@redhat.com>");
 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.lawre...@redhat.com>");
 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.lawre...@redhat.com>");
 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 <sjenn...@redhat.com>");
 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

Reply via email to