Re: [PATCH v3 0/9] klp-convert livepatch build tooling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Apr 10, 2019 at 11:50:49AM -0400, Joe Lawrence wrote:
>
> [ ... snip ... ]
>
> TODO
> ----
>
> There are a few outstanding items that I came across while reviewing v2,
> but as changes started accumulating, it made sense to defer those to a
> later version.  I'll reply to this thread individual topics to start
> discussion sub-threads for those.

Multiple object files
=====================

For v3, we tweaked the build scripts so that we could successfully build
a klp-converted livepatch module from multiple object files.

One interesting use-case is supporting two livepatch symbols of the same
name, but different object/position values.

An example target kernel module might be layed out like this:

  test_klp_convert_mod.ko         << target module is comprised of
                                     two object files, each defining
    test_klp_convert_mod_a.o         their own local get_homonym_string()
      get_homonym_string()           function and homonym_string[]
      homonym_string[]               character arrays.

    test_klp_convert_mod_b.o
      get_homonym_string()
      homonym_string[]


A look at interesting parts of the the module's symbol table:

  % eu-readelf --symbols lib/livepatch/test_klp_convert_mod.ko | \
        grep -e 'homonym' -e test_klp_convert_mod_

     29: 0000000000000000      0 FILE    LOCAL  DEFAULT      ABS test_klp_convert_mod_a.c
     32: 0000000000000010      8 FUNC    LOCAL  DEFAULT        3 get_homonym_string
     33: 0000000000000000     17 OBJECT  LOCAL  DEFAULT        5 homonym_string
     37: 0000000000000000      0 FILE    LOCAL  DEFAULT      ABS test_klp_convert_mod_b.c
     38: 0000000000000020      8 FUNC    LOCAL  DEFAULT        3 get_homonym_string
     39: 0000000000000000     17 OBJECT  LOCAL  DEFAULT       11 homonym_string

suggests that any livepatch module that wishes to resolve to
test_klp_convert_mod_a.c :: get_homonym_string() should include an
annotation like:

  file_a.c:

      KLP_MODULE_RELOC(test_klp_convert_mod) relocs_a[] = {
            KLP_SYMPOS(get_homonym_string, 1),
      };

and to resolve test_klp_convert_mod_b.c :: get_homonym_string():

  file_b.c:

      KLP_MODULE_RELOC(test_klp_convert_mod) relocs_b[] = {
            KLP_SYMPOS(get_homonym_string, 2),
      };


Unfortunately klp-convert v3 will fail to build such livepatch module,
regardless of sympos values:

  klp-convert: Conflicting KLP_SYMPOS definition: vmlinux.state_show,2 vs. vmlinux.state_show,1.
  klp-convert: Unable to load user-provided sympos
  make[1]: *** [scripts/Makefile.modpost:148: lib/livepatch/test_klp_convert_multi_objs.ko] Error 255


This abort message can be traced to sympos_sanity_check() as it verifies
that there no duplicate symbol names found in its list of user specified
symbols (ie, those needing to be converted).


Common sympos
-------------

New test case and related fixup can be found here:

  https://github.com/joe-lawrence/linux/commits/klp-convert-v4-multiple-objs

To better debug this issue, I added another selftest that demonstrates
this configuration in isolation.  "show_state" is a popular kernel
function name (my VM reported 5 instances in kallsyms) so I chose that
symbol name.

Initially I specified the *same* symbol position (1) in both .c file
KLP_SYMPOS annotations.  At the very least, we can trivially patch
klp-convert v3 to support annotations for the the same symbol <object,
name, position> value across object files.

Result: a small tweak to sympos_sanity_check() to relax its symbol
uniqueness verification:  allow for duplicate <object, name, position>
instances.  Now it will only complain when a supplied symbol references
the same <object, name> but a different <position>.

diff --git a/scripts/livepatch/klp-convert.c b/scripts/livepatch/klp-convert.c
index 82c27d219372..713835dfc9ec 100644
--- a/scripts/livepatch/klp-convert.c
+++ b/scripts/livepatch/klp-convert.c
@@ -194,7 +194,10 @@ static void clear_sympos_annontations(struct elf *klp_elf)
 	}
 }

-/* Checks if two or more elements in usr_symbols have the same name */
+/*
+ * Checks if two or more elements in usr_symbols have the same
+ * object and name, but different symbol position
+ */
 static bool sympos_sanity_check(void)
 {
 	bool sane = true;
@@ -203,7 +206,9 @@ static bool sympos_sanity_check(void)
 	list_for_each_entry(sp, &usr_symbols, list) {
 		aux = list_next_entry(sp, list);
 		list_for_each_entry_from(aux, &usr_symbols, list) {
-			if (strcmp(sp->symbol_name, aux->symbol_name) == 0) {
+			if (sp->pos != aux->pos &&
+			    strcmp(sp->object_name, aux->object_name) == 0 &&
+			    strcmp(sp->symbol_name, aux->symbol_name) == 0)
 				WARN("Conflicting KLP_SYMPOS definition: %s.%s,%d vs. %s.%s,%d.",
 				sp->object_name, sp->symbol_name, sp->pos,
 				aux->object_name, aux->symbol_name, aux->pos);


Unique sympos
-------------

But even with the above workaround, specifying unique symbol positions
will (and should) result in a klp-convert complaint.

When modifying the test module with unique symbol position annotation
values (1 and 2 respectively):

  test_klp_convert_multi_objs_a.c:

    extern void *state_show;
    ...
    KLP_MODULE_RELOC(vmlinux) vmlinux_relocs_b[] = {
            KLP_SYMPOS(state_show, 1)
    };

  test_klp_convert_multi_objs_b.c:

    extern void *state_show;
    ...
    KLP_MODULE_RELOC(vmlinux) vmlinux_relocs_b[] = {
            KLP_SYMPOS(state_show, 2)
    };


Each object file's symbol table contains a "state_show" instance:

  % eu-readelf --symbols lib/livepatch/test_klp_convert_multi_objs_a.o | grep '\<state_show\>'
     30: 0000000000000000      0 NOTYPE  GLOBAL DEFAULT    UNDEF state_show

  % eu-readelf --symbols lib/livepatch/test_klp_convert_multi_objs_b.o | grep '\<state_show\>'
     20: 0000000000000000      0 NOTYPE  GLOBAL DEFAULT    UNDEF state_show

and the intermediate test_klp_convert_multi_objs.klp.o file contains a
combined .klp.module_relocs.vmlinux relocation section with two
KLP_SYMPOS structures, each with a unique <sympos> value:

  % objcopy -O binary --only-section=.klp.module_relocs.vmlinux \
      lib/livepatch/test_klp_convert_multi_objs.klp.o >(hexdump)

  0000000 0000 0000 0000 0000 0001 0000 0000 0000
  0000010 0000 0000 0002 0000

but the symbol tables were merged, sorted and non-unique symbols
removed, leaving a *single* unresolved "state_show" instance:

  % eu-readelf --symbols lib/livepatch/test_klp_convert_multi_objs.klp.o | grep '\<state_show\>'
     53: 0000000000000000      0 NOTYPE  GLOBAL DEFAULT    UNDEF state_show

which means that even though we have separate relocations for each
"state_show" instance:

  Relocation section [ 6] '.rela.text.unlikely' for section [ 5] '.text.unlikely' at offset 0x44510 contains 11 entries:
    Offset              Type            Value               Addend Name
    0x0000000000000003  X86_64_32S      000000000000000000      +0 state_show
    ...
    0x0000000000000034  X86_64_32S      000000000000000000      +0 state_show
    ...

they share the same rela->sym and there is no way to distinguish which
one correlates to which KLP_SYMPOS structure.


Future Work
-----------

I don't see an easy way to support multiple homonym <object, name>
symbols with unique <position> values in the current livepatch module
Elf format.  The only solutions that come to mind right now include
renaming homonym symbols somehow to retain the relocation->symbol
relationship when separate object files are combined.  Perhaps an
intermediate linker step could make annotated symbols unique in some way
to achieve this.  /thinking out loud

In the meantime, the unique symbol <position> case is already detected
and with a little tweaking we could support multiple common symbol
<position> values.

-- Joe



[Index of Archives]     [Linux&nblp;USB Development]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite Secrets]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux