[PATCH] ARM: decompressor: fix BSS size calculation for LLVM ld.lld

Fangrui Song maskray at google.com
Fri Feb 5 13:33:52 EST 2021


On 2021-02-05, Ard Biesheuvel wrote:
>On Fri, 5 Feb 2021 at 19:00, Nick Desaulniers <ndesaulniers at google.com> wrote:
>>
>> On Fri, Feb 5, 2021 at 12:52 AM Ard Biesheuvel <ardb at kernel.org> wrote:
>> >
>> > The LLVM ld.lld linker uses a different symbol type for __bss_start,
>> > resulting in the calculation of KBSS_SZ to be thrown off. Up until now,
>> > this has gone unnoticed as it only affects the appended DTB case, but
>> > pending changes for ARM in the way the decompressed kernel is cleaned
>> > from the caches has uncovered this problem.
>> >
>> > On a ld.lld build:
>> >
>> >   $ nm vmlinux |grep bss_
>> >   c1c22034 D __bss_start
>> >   c1c86e98 B __bss_stop
>> >
>> > resulting in
>> >
>>
>> $ readelf -s arch/arm/boot/compressed/vmlinux | grep bss_size
>>
>> >   433: c1c86e98     0 NOTYPE  GLOBAL DEFAULT  ABS _kernel_bss_size
>> >
>> > which is obviously incorrect, and may cause the cache clean to access
>> > unmapped memory, or cause the size calculation to wrap, resulting in no
>> > cache clean to be performed at all.
>> >
>> > Fix this by updating the sed regex to take D type symbols into account.
>> >
>> > Cc: Nick Desaulniers <ndesaulniers at google.com>
>> > Cc: Nathan Chancellor <nathan at kernel.org>
>> > Cc: Guillaume Tucker <guillaume.tucker at collabora.com>
>> > Link: https://lore.kernel.org/linux-arm-kernel/6c65bcef-d4e7-25fa-43cf-2c435bb61bb9@collabora.com/
>> > Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
>>
>>
>> Reviewed-by: Nick Desaulniers <ndesaulniers at google.com>
>> Tested-by: Nick Desaulniers <ndesaulniers at google.com>
>>
>> Thanks for debugging+fixing this, and Guillaume for the report.  It's
>> nice to see a fix so early; thinking back to last year before KernelCI
>> integration, we probably would have only noticed when CrOS went to
>> upgrade their rk3288 platform devices.
>>
>> Some other tags that might be nice to apply:
>>
>> Cc: stable at kernel.org
>> Fixes: 429f7a062e3b ("ARM: decompressor: fix BSS size calculation")
>> Reported-by: Guillaume Tucker <guillaume.tucker at collabora.com>
>> Reported-by: "kernelci.org bot" <bot at kernelci.org>
>>
>
>Thanks. I'll add these tags and drop this patch into the patch system
>
>> Tests run:
>>
>...
>>
>> + Fangrui,
>> Fangrui, __bss_start looks like it's linker script defined by the
>> BSS_SECTION macro from include/asm-generic/vmlinux.lds.h:1160 being
>> used in arch/arm/kernel/vmlinux.lds.S:149.  Should these symbols be
>> placed in .bss? Might save a few bytes in the image, unless there's an
>> initial value that's encoded with them?
>>
>
>Not sure what you are asking here. These symbols just delineate .bss,
>they don't take up any space themselves.
>
>What seems to be happening is that the placement of __bss_start
>outside of the .sbss/.bss section declarations causes it to be
>annotated as residing in .data.

In my build (make -sk -j 50 ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- LLVM=1 O=/tmp/out/arm -j 50 defconfig vmlinux), vmlinux has:

   [34] .data..percpu     PROGBITS        c195f000 151f000 00c20c 00  WA  0   0 64
   [35] .data             PROGBITS        c1a00000 1530000 217914 00  WA  0   0 4096
   [36] __bug_table       PROGBITS        c1c17918 1747918 00a5cc 00  WA  0   0  4
   [37] .sbss             PROGBITS        c1c21ee4 1751ee4 000000 00  WA  0   0  1
   [38] .bss              NOBITS          c1c21f00 1751f00 063f98 00  WA  0   0 64

__bss_start is defined relative to __bug_table.
The issue is that __bss_start is defined outside of the output section description of .bss,
so its st_shndx (section) is not guaranteed.

I noticed that many linker script fragments used by the kernel have similar problems.
The delineating symbols are defined outside of output sections. With ld --orphan-handling=,
we can somewhat guarantee there are no undesired interleaving sections, but it is hard to
ensure their st_shndx values.

>
>> > ---
>> >  arch/arm/boot/compressed/Makefile | 4 ++--
>> >  1 file changed, 2 insertions(+), 2 deletions(-)
>> >
>> > diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
>> > index fb521efcc6c2..54307db7854d 100644
>> > --- a/arch/arm/boot/compressed/Makefile
>> > +++ b/arch/arm/boot/compressed/Makefile
>> > @@ -115,8 +115,8 @@ asflags-y := -DZIMAGE
>> >
>> >  # Supply kernel BSS size to the decompressor via a linker symbol.
>> >  KBSS_SZ = $(shell echo $$(($$($(NM) $(obj)/../../../../vmlinux | \
>> > -               sed -n -e 's/^\([^ ]*\) [AB] __bss_start$$/-0x\1/p' \
>> > -                      -e 's/^\([^ ]*\) [AB] __bss_stop$$/+0x\1/p') )) )
>> > +               sed -n -e 's/^\([^ ]*\) [ABD] __bss_start$$/-0x\1/p' \
>> > +                      -e 's/^\([^ ]*\) [ABD] __bss_stop$$/+0x\1/p') )) )
>>
>> I wasn't sure whether we still needed `A`, but
>> commit 6cea14f55474 ("ARM: replace unnecessary perl with sed and the
>> shell $(( )) operator")
>> references that depending on the version of binutils you might observe
>> that.  There's no more info on which version or under what conditions.
>> Lest we reintroduce this same problem for that version, it's fine to
>> leave it.
>>

In my observation a symbol may be SHN_ABS (nm key 'A') if it is

* defined by --defsym
* a symbol assignment outside of output sections in -no-pie link mode

>Agreed.
>
>> >  LDFLAGS_vmlinux = --defsym _kernel_bss_size=$(KBSS_SZ)
>> >  # Supply ZRELADDR to the decompressor via a linker symbol.
>> >  ifneq ($(CONFIG_AUTO_ZRELADDR),y)
>> > --
>> > 2.30.0
>> >
>>
>>
>> --
>> Thanks,
>> ~Nick Desaulniers



More information about the linux-arm-kernel mailing list