[PATCH v3] kernel/module_64.c: Add REL24 relocation support of livepatch symbols
Kamalesh Babulal
kamalesh at linux.vnet.ibm.com
Thu Nov 2 16:49:59 AEDT 2017
On Tuesday 31 October 2017 07:49 PM, Naveen N . Rao wrote:
> Hi Kamalesh,
> Sorry for the late review. Overall, the patch looks good to me. So:
> Acked-by: Naveen N. Rao <naveen.n.rao at linux.vnet.ibm.com>
>
> However, I have a few minor comments which can be addressed in a
> subsequent patch.
>
Thanks for the review.
[...]
>> diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c
>> index 0b0f896..005aaea 100644
>> --- a/arch/powerpc/kernel/module_64.c
>> +++ b/arch/powerpc/kernel/module_64.c
[...]
>> @@ -239,10 +257,19 @@ static void relaswap(void *_x, void *_y, int size)
>>
>> /* Get size of potential trampolines required. */
>> static unsigned long get_stubs_size(const Elf64_Ehdr *hdr,
>> - const Elf64_Shdr *sechdrs)
>> + const Elf64_Shdr *sechdrs,
>> + struct module *me)
>> {
>> /* One extra reloc so it's always 0-funcaddr terminated */
>> unsigned long relocs = 1;
>
> You might want to get rid of 'relocs' above and simply use the below
> two.
>
>> + /*
>> + * size of livepatch stub is 28 instructions, whereas the
>> + * non-livepatch stub requires 7 instructions. Account for
>> + * different stub sizes and track the livepatch relocation
>> + * count in me->arch.klp_relocs.
>> + */
>> + unsigned long sec_relocs = 0;
>> + unsigned long klp_relocs = 0;
>
> You should also initialize this to 1 (similar to relocs above) for use
> in the iterators below. Or, update the iterators to use
> me->arch.klp_relocs (1)
relocs is Sum(sec_relocs), whereas per section relocation count is
assigned to sec_relocs. If the section is livepatch section, then it
added to klp_relocs or else to relocs. sec_relocs acts like a temp
variable to hold the current section relocation count.
>
>> unsigned i;
>>
>> /* Every relocated section... */
>> @@ -262,9 +289,14 @@ static unsigned long get_stubs_size(const Elf64_Ehdr *hdr,
>> sechdrs[i].sh_size / sizeof(Elf64_Rela),
>> sizeof(Elf64_Rela), relacmp, relaswap);
>>
>> - relocs += count_relocs((void *)sechdrs[i].sh_addr,
>> + sec_relocs = count_relocs((void *)sechdrs[i].sh_addr,
>> sechdrs[i].sh_size
>> / sizeof(Elf64_Rela));
>
> How about also capturing 'sec_relocs' in 'struct mod_arch_specific'? (2)
> That will help simplify a lot of the calculations here and elsewhere.
> Note that there are many other places where the number of stubs is
> derived looking at 'sh_size', which is incorrect since we now have klp
> stubs as well (create_ftrace_stub() for instance).
>
>> + relocs += sec_relocs;
>> +#ifdef CONFIG_LIVEPATCH
>> + if (sechdrs[i].sh_flags & SHF_RELA_LIVEPATCH)
>> + klp_relocs += sec_relocs;
>> +#endif
>
> If a module has SHF_RELA_LIVEPATCH, but the kernel is compiled without
> CONFIG_LIVEPATCH, should we refuse to load the kernel module?
Yes, the module load will fail.
>
> You might want to consider removing the above #ifdef and processing some
> of these flags regardless of CONFIG_LIVEPATCH.
ifdef guard, can be replaced with check for SHF_RELA_LIVEPATCH in
section flag.
>
>> }
>> }
>>
>> @@ -273,6 +305,15 @@ static unsigned long get_stubs_size(const Elf64_Ehdr *hdr,
>> relocs++;
>> #endif
>>
>> + relocs -= klp_relocs;
>> +#ifdef CONFIG_LIVEPATCH
>> + me->arch.klp_relocs = klp_relocs;
>> +
>> + pr_debug("Looks like a total of %lu stubs, (%lu) livepatch stubs, max\n",
> ^^^^^
> (%lu livepatch stubs)
>
> Just wondering why the brackets are the way they are...
Makes it better to use the brackets like you suggested.
>
>> + relocs, klp_relocs);
>> + return (relocs * sizeof(struct ppc64_stub_entry) +
>> + klp_relocs * sizeof(struct ppc64le_klp_stub_entry));
>> +#endif
>> pr_debug("Looks like a total of %lu stubs, max\n", relocs);
>> return relocs * sizeof(struct ppc64_stub_entry);
>> }
[...]
>>
>> +#ifdef CONFIG_LIVEPATCH
>> +static unsigned long klp_stub_for_addr(const Elf64_Shdr *sechdrs,
>> + unsigned long addr,
>> + struct module *me)
>> +{
>> + struct ppc64le_klp_stub_entry *klp_stubs;
>> + unsigned int num_klp_stubs = me->arch.klp_relocs;
>> + unsigned int i, num_stubs;
>> +
>> + num_stubs = (sechdrs[me->arch.stubs_section].sh_size -
>> + (num_klp_stubs * sizeof(*klp_stubs))) /
>> + sizeof(struct ppc64_stub_entry);
>
> (2) This can be simplified if we have me->arch.sec_relocs.
Having it will make the calculation look simple:
num_stubs = (me->arch.sec_relocs * size(struct ppc64_stub_entry).
>
>> +
>> + /*
>> + * Create livepatch stubs after the regular stubs.
>> + */
>> + klp_stubs = (void *)sechdrs[me->arch.stubs_section].sh_addr +
>> + (num_stubs * sizeof(struct ppc64_stub_entry));
>> + for (i = 0; stub_func_addr(klp_stubs[i].funcdata); i++) {
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> (1) This needs us to allocate one additional stub.
>
>
Good catch, yes there should an extra stub.
--
cheers,
Kamalesh.
More information about the Linuxppc-dev
mailing list