Thread (27 messages) 27 messages, 5 authors, 2022-12-13

Re: [PATCH v6] livepatch: Clear relocation targets on a module removal

From: Song Liu <song@kernel.org>
Date: 2022-11-29 01:57:27
Also in: live-patching, lkml

On Fri, Nov 18, 2022 at 8:24 AM Petr Mladek [off-list ref] wrote:
[...]
quoted
+#ifdef CONFIG_LIVEPATCH
+void clear_relocate_add(Elf64_Shdr *sechdrs,
+                    const char *strtab,
+                    unsigned int symindex,
+                    unsigned int relsec,
+                    struct module *me)
+{
+     unsigned int i;
+     Elf64_Rela *rela = (void *)sechdrs[relsec].sh_addr;
+     Elf64_Sym *sym;
+     unsigned long *location;
+     const char *symname;
+     u32 *instruction;
+
+     pr_debug("Clearing ADD relocate section %u to %u\n", relsec,
+              sechdrs[relsec].sh_info);
+
+     for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
+             location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+                     + rela[i].r_offset;
+             sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
+                     + ELF64_R_SYM(rela[i].r_info);
+             symname = me->core_kallsyms.strtab
+                     + sym->st_name;
+
+             if (ELF64_R_TYPE(rela[i].r_info) != R_PPC_REL24)
+                     continue;
+             /*
+              * reverse the operations in apply_relocate_add() for case
+              * R_PPC_REL24.
+              */
+             if (sym->st_shndx != SHN_UNDEF &&
+                 sym->st_shndx != SHN_LIVEPATCH)
+                     continue;
+
+             instruction = (u32 *)location;
+             if (is_mprofile_ftrace_call(symname))
+                     continue;
+
+             if (!instr_is_relative_link_branch(ppc_inst(*instruction)))
+                     continue;
+
+             instruction += 1;
+             patch_instruction(instruction, ppc_inst(PPC_RAW_NOP()));
+     }
+
+}
This looks like a lot of duplicated code. Isn't it?
TBH, I think the duplicated code is not really bad.

apply_relocate_add() is a much more complicated function, I would
rather not mess it up to make this function a little simpler.

[...]
This duplicates a lot of code. Please, rename apply_relocate_add() the
same way as __apply_clear_relocate_add() and add the "apply" parameter.
Then add the wrappers for this:

int write_relocate_add(Elf64_Shdr *sechdrs,
                       const char *strtab,
                       unsigned int symindex,
                       unsigned int relsec,
                       struct module *me,
                       bool apply)
{
        int ret;
        bool early = me->state == MODULE_STATE_UNFORMED;
        void *(*write)(void *, const void *, size_t) = memcpy;

        if (!early) {
                write = text_poke;
                mutex_lock(&text_mutex);
        }
How about we move the "early" logic into __write_relocate_add()?
        ret = __write_relocate_add(sechdrs, strtab, symindex, relsec, me,
                                         write, apply);

        if (!early) {
                text_poke_sync();
                mutex_unlock(&text_mutex);
        }

        return ret;
}

int apply_relocate_add(Elf64_Shdr *sechdrs,
                       const char *strtab,
                       unsigned int symindex,
                       unsigned int relsec,
                       struct module *me)
{
        return write_relocate_add(sechdrs, strtab, symindex, relsec, me, true);
Then we just call __write_relocate_add() from here...
}

#ifdef CONFIG_LIVEPATCH
void apply_relocate_add(Elf64_Shdr *sechdrs,
                        const char *strtab,
                        unsigned int symindex,
                        unsigned int relsec,
                        struct module *me)
{
        write_relocate_add(sechdrs, strtab, symindex, relsec, me, false);
and here.

}
#endif

quoted
+#endif
+
 #endif

 int module_finalize(const Elf_Ehdr *hdr,
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -316,6 +316,45 @@ int klp_apply_section_relocs(struct module *pmod, Elf_Shdr *sechdrs,
      return apply_relocate_add(sechdrs, strtab, symndx, secndx, pmod);
 }

+static void klp_clear_object_relocations(struct module *pmod,
+                                     struct klp_object *obj)
+{
+     int i, cnt;
+     const char *objname, *secname;
+     char sec_objname[MODULE_NAME_LEN];
+     Elf_Shdr *sec;
+
+     objname = klp_is_module(obj) ? obj->name : "vmlinux";
+
+     /* For each klp relocation section */
+     for (i = 1; i < pmod->klp_info->hdr.e_shnum; i++) {
+             sec = pmod->klp_info->sechdrs + i;
+             secname = pmod->klp_info->secstrings + sec->sh_name;
+             if (!(sec->sh_flags & SHF_RELA_LIVEPATCH))
+                     continue;
+
+             /*
+              * Format: .klp.rela.sec_objname.section_name
+              * See comment in klp_resolve_symbols() for an explanation
+              * of the selected field width value.
+              */
+             secname = pmod->klp_info->secstrings + sec->sh_name;
+             cnt = sscanf(secname, ".klp.rela.%55[^.]", sec_objname);
+             if (cnt != 1) {
+                     pr_err("section %s has an incorrectly formatted name\n",
+                            secname);
+                     continue;
+             }
Actually, I think we don't need the cnt check here. Once it is removed,
there isn't much duplicated logic.
quoted
+
+             if (strcmp(objname, sec_objname))
+                     continue;
+
+             clear_relocate_add(pmod->klp_info->sechdrs,
+                                pmod->core_kallsyms.strtab,
+                                pmod->klp_info->symndx, i, pmod);
+     }
+}
Huh, this duplicates a lot of tricky code.

It is even worse because this squashed code from two functions
klp_apply_section_relocs() and klp_apply_object_relocs()
into a single function. As a result, the code duplication is not
even obvious.

Also the suffix "_reloacations() does not match the suffix of
the related funciton:

        + klp_apply_object_relocs()             (existing)
        + klp_clear_object_relocations()        (new)

This all would complicate maintenance of the code.

Please, implement a common:

int klp_write_section_relocs(struct module *pmod, Elf_Shdr *sechdrs,
                             const char *shstrtab, const char *strtab,
                             unsigned int symndx, unsigned int secndx,
                             const char *objname, bool apply);

and

int klp_write_object_relocs(struct klp_patch *patch,
                            struct klp_object *obj,
                            bool apply);

and add the respective wrappers:

int klp_apply_section_relocs();   /* also needed in module/main.c */
int klp_apply_object_relocs();
void klp_clear_object_relocs();
With the above simplification (removing cnt check), do we still need
all these wrappers? Personally, I think they will make the code more
difficult to follow..

Thanks,
Song
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help