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

Song Liu song at kernel.org
Tue Nov 29 12:57:06 AEDT 2022


On Fri, Nov 18, 2022 at 8:24 AM Petr Mladek <pmladek at suse.com> wrote:
>
[...]

> >
> > +#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
>
>
> > +#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.

> > +
> > +             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


More information about the Linuxppc-dev mailing list