Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1306179 > unrolled thread

[PATCH v3 00/21] arm64: implement support for KASLR

Started byArd Biesheuvel <ard.biesheuvel@linaro.org>
First post2016-01-11 14:20 +0100
Last post2016-01-12 08:20 +0100
Articles 19 on this page of 39 — 3 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v3 00/21] arm64: implement support for KASLR Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:20 +0100
    [PATCH v3 14/21] arm64: [re]define SWAPPER_TABLE_[SHIFT|SIZE] for use in asm code Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
      Re: [PATCH v3 14/21] arm64: [re]define SWAPPER_TABLE_[SHIFT|SIZE] for  use in asm code Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
    [PATCH v3 08/21] arm64: add support for module PLTs Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
    [PATCH v3 04/21] arm64: decouple early fixmap init from linear mapping Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
      Re: [PATCH v3 04/21] arm64: decouple early fixmap init from linear  mapping Mark Rutland <mark.rutland@arm.com> - 2016-01-11 17:10 +0100
        Re: [PATCH v3 04/21] arm64: decouple early fixmap init from linear mapping Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 17:20 +0100
          Re: [PATCH v3 04/21] arm64: decouple early fixmap init from linear  mapping Mark Rutland <mark.rutland@arm.com> - 2016-01-11 17:30 +0100
            Re: [PATCH v3 04/21] arm64: decouple early fixmap init from linear  mapping Mark Rutland <mark.rutland@arm.com> - 2016-01-11 18:00 +0100
              Re: [PATCH v3 04/21] arm64: decouple early fixmap init from linear mapping Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 18:10 +0100
                Re: [PATCH v3 04/21] arm64: decouple early fixmap init from linear mapping Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 18:20 +0100
                  Re: [PATCH v3 04/21] arm64: decouple early fixmap init from linear  mapping Mark Rutland <mark.rutland@arm.com> - 2016-01-11 18:30 +0100
    [PATCH v3 14/21] arm64: redefine SWAPPER_TABLE_SHIFT for use in asm code Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
    [PATCH v3 01/21] of/fdt: make memblock minimum physical address arch configurable Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
    [PATCH v3 16/21] scripts/sortextable: add support for ET_DYN binaries Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
    [PATCH v3 17/21] arm64: add support for a relocatable kernel and KASLR Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
    [PATCH v3 11/21] arm64: avoid R_AARCH64_ABS64 relocations for Image header fields Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
      Re: [PATCH v3 11/21] arm64: avoid R_AARCH64_ABS64 relocations for  Image header fields Mark Rutland <mark.rutland@arm.com> - 2016-01-13 19:20 +0100
        Re: [PATCH v3 11/21] arm64: avoid R_AARCH64_ABS64 relocations for  Image header fields Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-13 19:50 +0100
          Re: [PATCH v3 11/21] arm64: avoid R_AARCH64_ABS64 relocations for  Image header fields Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-14 10:00 +0100
            Re: [PATCH v3 11/21] arm64: avoid R_AARCH64_ABS64 relocations for  Image header fields Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-14 10:10 +0100
              Re: [PATCH v3 11/21] arm64: avoid R_AARCH64_ABS64 relocations for  Image header fields Mark Rutland <mark.rutland@arm.com> - 2016-01-14 11:50 +0100
                Re: [PATCH v3 11/21] arm64: avoid R_AARCH64_ABS64 relocations for  Image header fields Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-14 12:30 +0100
    [PATCH v3 06/21] arm64: pgtable: implement static [pte|pmd|pud]_offset variants Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
      Re: [PATCH v3 06/21] arm64: pgtable: implement static  [pte|pmd|pud]_offset variants Mark Rutland <mark.rutland@arm.com> - 2016-01-11 17:30 +0100
        Re: [PATCH v3 06/21] arm64: pgtable: implement static  [pte|pmd|pud]_offset variants Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 18:30 +0100
          Re: [PATCH v3 06/21] arm64: pgtable: implement static  [pte|pmd|pud]_offset variants Mark Rutland <mark.rutland@arm.com> - 2016-01-11 18:40 +0100
    [PATCH v3 13/21] arm64: allow kernel Image to be loaded anywhere in physical memory Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
    [PATCH v3 12/21] arm64: avoid dynamic relocations in early boot code Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
      Re: [PATCH v3 12/21] arm64: avoid dynamic relocations in early boot  code Mark Rutland <mark.rutland@arm.com> - 2016-01-14 18:20 +0100
    [PATCH v3 15/21] arm64: split elf relocs into a separate header. Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
    [PATCH v3 09/21] extable: add support for relative extables to search and sort routines Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
    [PATCH v3 10/21] arm64: switch to relative exception tables Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
    [PATCH v3 19/21] efi: stub: add implementation of efi_random_alloc() Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
    [PATCH v3 18/21] efi: stub: implement efi_get_random_bytes() based on EFI_RNG_PROTOCOL Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
    [PATCH v3 20/21] efi: stub: use high allocation for converted command line Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
    [PATCH v3 21/21] arm64: efi: invoke EFI_RNG_PROTOCOL to supply KASLR randomness Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-11 14:30 +0100
    Re: [PATCH v3 00/21] arm64: implement support for KASLR Kees Cook <keescook@chromium.org> - 2016-01-11 23:10 +0100
      Re: [PATCH v3 00/21] arm64: implement support for KASLR Ard Biesheuvel <ard.biesheuvel@linaro.org> - 2016-01-12 08:20 +0100

Page 2 of 2 — ← Prev page 1 [2]


#1309100 — Re: [PATCH v3 11/21] arm64: avoid R_AARCH64_ABS64 relocations for Image header fields

FromArd Biesheuvel <ard.biesheuvel@linaro.org>
Date2016-01-14 10:10 +0100
SubjectRe: [PATCH v3 11/21] arm64: avoid R_AARCH64_ABS64 relocations for Image header fields
Message-ID<qQM4O-4UH-25@gated-at.bofh.it>
In reply to#1309089
On 14 January 2016 at 09:51, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> On 13 January 2016 at 19:48, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
>> On 13 January 2016 at 19:12, Mark Rutland <mark.rutland@arm.com> wrote:
>>> On Mon, Jan 11, 2016 at 02:19:04PM +0100, Ard Biesheuvel wrote:
>>>> Unfortunately, the current way of using the linker to emit build time
>>>> constants into the Image header will no longer work once we switch to
>>>> the use of PIE executables. The reason is that such constants are emitted
>>>> into the binary using R_AARCH64_ABS64 relocations, which we will resolve
>>>> at runtime, not at build time, and the places targeted by those
>>>> relocations will contain zeroes before that.
>>>>
>>>> So move back to assembly time constants or R_AARCH64_ABS32 relocations
>>>> (which, interestingly enough, do get resolved at build time)
>>>
>>> To me it seems very odd that ABS64 and ABS32 are treated differently,
>>> and it makes me somewhat uncomfortable becuase it feels like a bug.
>>>
>>> Do we know whether the inconsistency between ABS64 and ABS32 was
>>> deliberate?
>>>
>>> I couldn't spot anything declaring a difference in the AArch64 ELF
>>> spec, and I'm not sure where else to look.
>>>
>>
>> My assumption is that PIE only defers resolving R_AARCH64_ABS64
>> relocations since those are the only ones that can be used to refer to
>> memory addresses
>>
>
> OK, digging into the binutils source code, it turns out that indeed,
> ABSnn relocations where nn equals the ELFnn memory size are treated
> differently, but only if they have default visibility. This is simply
> a result of the fact the code path is shared between shared libraries
> and PIE executables, since PIE executable are fully linked. It also
> means that we can simply work around it by emitting the linker symbols
> as hidden.
>

... and the bad news is that, while emitting the symbols as hidden
turns them from R_AARCH64_ABS64 into a R_AARCH64_RELATIVE relocations,
it does not actually force the value to be emitted at build time.

So I am going to stick with the patch, but elaborate in a comment
about why R_AARCH64_ABSnn are treated differently if nn equals the
pointer size. (look at elfNN_aarch64_final_link_relocate() in binutils
if you are keen to look at the code yourself)

-- 
Ard.



>
>>>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>>>> ---
>>>>  arch/arm64/include/asm/assembler.h | 15 ++++++++
>>>>  arch/arm64/kernel/head.S           | 17 +++++++--
>>>>  arch/arm64/kernel/image.h          | 37 ++++++--------------
>>>>  3 files changed, 40 insertions(+), 29 deletions(-)
>>>>
>>>> diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
>>>> index d8bfcc1ce923..e211af783a3d 100644
>>>> --- a/arch/arm64/include/asm/assembler.h
>>>> +++ b/arch/arm64/include/asm/assembler.h
>>>> @@ -222,4 +222,19 @@ lr       .req    x30             // link register
>>>>       .size   __pi_##x, . - x;        \
>>>>       ENDPROC(x)
>>>>
>>>> +     .macro  le16, val
>>>> +     .byte   \val & 0xff
>>>> +     .byte   (\val >> 8) & 0xff
>>>> +     .endm
>>>> +
>>>> +     .macro  le32, val
>>>> +     le16    \val
>>>> +     le16    (\val >> 16)
>>>> +     .endm
>>>> +
>>>> +     .macro  le64, val
>>>> +     le32    \val
>>>> +     le32    (\val >> 32)
>>>> +     .endm
>>>> +
>>>>  #endif       /* __ASM_ASSEMBLER_H */
>>>> diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
>>>> index 350515276541..211f75e673f4 100644
>>>> --- a/arch/arm64/kernel/head.S
>>>> +++ b/arch/arm64/kernel/head.S
>>>> @@ -51,6 +51,17 @@
>>>>  #define KERNEL_START _text
>>>>  #define KERNEL_END   _end
>>>>
>>>> +#ifdef CONFIG_CPU_BIG_ENDIAN
>>>> +#define __HEAD_FLAG_BE       1
>>>> +#else
>>>> +#define __HEAD_FLAG_BE       0
>>>> +#endif
>>>> +
>>>> +#define __HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2)
>>>> +
>>>> +#define __HEAD_FLAGS ((__HEAD_FLAG_BE << 0) |        \
>>>> +                      (__HEAD_FLAG_PAGE_SIZE << 1))
>>>> +
>>>>  /*
>>>>   * Kernel startup entry point.
>>>>   * ---------------------------
>>>> @@ -83,9 +94,9 @@ efi_head:
>>>>       b       stext                           // branch to kernel start, magic
>>>>       .long   0                               // reserved
>>>>  #endif
>>>> -     .quad   _kernel_offset_le               // Image load offset from start of RAM, little-endian
>>>> -     .quad   _kernel_size_le                 // Effective size of kernel image, little-endian
>>>> -     .quad   _kernel_flags_le                // Informative flags, little-endian
>>>> +     le64    TEXT_OFFSET                     // Image load offset from start of RAM, little-endian
>>>> +     .long   _kernel_size_le, 0              // Effective size of kernel image, little-endian
>>>> +     le64    __HEAD_FLAGS                    // Informative flags, little-endian
>>>>       .quad   0                               // reserved
>>>>       .quad   0                               // reserved
>>>>       .quad   0                               // reserved
>>>> diff --git a/arch/arm64/kernel/image.h b/arch/arm64/kernel/image.h
>>>> index bc2abb8b1599..bb6b0e69d0a4 100644
>>>> --- a/arch/arm64/kernel/image.h
>>>> +++ b/arch/arm64/kernel/image.h
>>>> @@ -26,41 +26,26 @@
>>>>   * There aren't any ELF relocations we can use to endian-swap values known only
>>>>   * at link time (e.g. the subtraction of two symbol addresses), so we must get
>>>>   * the linker to endian-swap certain values before emitting them.
>>>> + * Note that this will not work for 64-bit values: these are resolved using
>>>> + * R_AARCH64_ABS64 relocations, which are fixed up at runtime rather than at
>>>> + * build time when building the PIE executable (for KASLR).
>>>>   */
>>>>  #ifdef CONFIG_CPU_BIG_ENDIAN
>>>> -#define DATA_LE64(data)                                      \
>>>> -     ((((data) & 0x00000000000000ff) << 56) |        \
>>>> -      (((data) & 0x000000000000ff00) << 40) |        \
>>>> -      (((data) & 0x0000000000ff0000) << 24) |        \
>>>> -      (((data) & 0x00000000ff000000) << 8)  |        \
>>>> -      (((data) & 0x000000ff00000000) >> 8)  |        \
>>>> -      (((data) & 0x0000ff0000000000) >> 24) |        \
>>>> -      (((data) & 0x00ff000000000000) >> 40) |        \
>>>> -      (((data) & 0xff00000000000000) >> 56))
>>>> +#define DATA_LE32(data)                              \
>>>> +     ((((data) & 0x000000ff) << 24) |        \
>>>> +      (((data) & 0x0000ff00) << 8)  |        \
>>>> +      (((data) & 0x00ff0000) >> 8)  |        \
>>>> +      (((data) & 0xff000000) >> 24))
>>>>  #else
>>>> -#define DATA_LE64(data) ((data) & 0xffffffffffffffff)
>>>> +#define DATA_LE32(data) ((data) & 0xffffffff)
>>>>  #endif
>>>>
>>>> -#ifdef CONFIG_CPU_BIG_ENDIAN
>>>> -#define __HEAD_FLAG_BE       1
>>>> -#else
>>>> -#define __HEAD_FLAG_BE       0
>>>> -#endif
>>>> -
>>>> -#define __HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2)
>>>> -
>>>> -#define __HEAD_FLAGS ((__HEAD_FLAG_BE << 0) |        \
>>>> -                      (__HEAD_FLAG_PAGE_SIZE << 1))
>>>> -
>>>>  /*
>>>>   * These will output as part of the Image header, which should be little-endian
>>>> - * regardless of the endianness of the kernel. While constant values could be
>>>> - * endian swapped in head.S, all are done here for consistency.
>>>> + * regardless of the endianness of the kernel.
>>>>   */
>>>>  #define HEAD_SYMBOLS                                         \
>>>> -     _kernel_size_le         = DATA_LE64(_end - _text);      \
>>>> -     _kernel_offset_le       = DATA_LE64(TEXT_OFFSET);       \
>>>> -     _kernel_flags_le        = DATA_LE64(__HEAD_FLAGS);
>>>> +     _kernel_size_le         = DATA_LE32(_end - _text);
>>>>
>>>>  #ifdef CONFIG_EFI
>>>>
>>>> --
>>>> 2.5.0
>>>>

[toc] | [prev] | [next] | [standalone]


#1309170 — Re: [PATCH v3 11/21] arm64: avoid R_AARCH64_ABS64 relocations for Image header fields

FromMark Rutland <mark.rutland@arm.com>
Date2016-01-14 11:50 +0100
SubjectRe: [PATCH v3 11/21] arm64: avoid R_AARCH64_ABS64 relocations for Image header fields
Message-ID<qQNDz-5Lf-3@gated-at.bofh.it>
In reply to#1309100
On Thu, Jan 14, 2016 at 10:05:42AM +0100, Ard Biesheuvel wrote:
> On 14 January 2016 at 09:51, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> > On 13 January 2016 at 19:48, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
> >> On 13 January 2016 at 19:12, Mark Rutland <mark.rutland@arm.com> wrote:
> >>> On Mon, Jan 11, 2016 at 02:19:04PM +0100, Ard Biesheuvel wrote:
> >>>> Unfortunately, the current way of using the linker to emit build time
> >>>> constants into the Image header will no longer work once we switch to
> >>>> the use of PIE executables. The reason is that such constants are emitted
> >>>> into the binary using R_AARCH64_ABS64 relocations, which we will resolve
> >>>> at runtime, not at build time, and the places targeted by those
> >>>> relocations will contain zeroes before that.
> >>>>
> >>>> So move back to assembly time constants or R_AARCH64_ABS32 relocations
> >>>> (which, interestingly enough, do get resolved at build time)
> >>>
> >>> To me it seems very odd that ABS64 and ABS32 are treated differently,
> >>> and it makes me somewhat uncomfortable becuase it feels like a bug.
> >>>
> >>> Do we know whether the inconsistency between ABS64 and ABS32 was
> >>> deliberate?
> >>>
> >>> I couldn't spot anything declaring a difference in the AArch64 ELF
> >>> spec, and I'm not sure where else to look.
> >>>
> >>
> >> My assumption is that PIE only defers resolving R_AARCH64_ABS64
> >> relocations since those are the only ones that can be used to refer to
> >> memory addresses
> >>
> >
> > OK, digging into the binutils source code, it turns out that indeed,
> > ABSnn relocations where nn equals the ELFnn memory size are treated
> > differently, but only if they have default visibility. This is simply
> > a result of the fact the code path is shared between shared libraries
> > and PIE executables, since PIE executable are fully linked. It also
> > means that we can simply work around it by emitting the linker symbols
> > as hidden.
> >
> 
> ... and the bad news is that, while emitting the symbols as hidden
> turns them from R_AARCH64_ABS64 into a R_AARCH64_RELATIVE relocations,
> it does not actually force the value to be emitted at build time.
> 
> So I am going to stick with the patch, but elaborate in a comment
> about why R_AARCH64_ABSnn are treated differently if nn equals the
> pointer size. (look at elfNN_aarch64_final_link_relocate() in binutils
> if you are keen to look at the code yourself)

Ok. Thanks for digging into that.

One thing though: I would prefer if we could still keep all the LE64
image header values together, to have them dealt with consistently.

Could we hide the ABS32 usage behind some macros to do so, e.g.

in image.h:

#define DEFINE_IMAGE_LE64(sym, data) 				\
	sym##_lo32 = DATA_LE32(data & 0xffffffff);		\
	sym##_hi32 = DATA_LE32(data >> 32);

#define HEAD_SYMBOLS						\
	DEFINE_IMAGE_LE64(_kernel_size_le, _end - _text);	\
	DEFINE_IMAGE_LE64(_kernel_offset_le, TEXT_OFFSET);	\
	DEFINE_IMAGE_LE64(_kernel_flags_le, __HEAD_FLAGS);

and in head.S:

#define IMAGE_LE64(sym)	.long sym##_lo32, sym##_hi32

	...
	IMAGE_LE64(_kernel_size_le)	// Image load offset from start	of RAM, little-endian
	IMAGE_LE64(_kernel_offset_le)	// Effective size of kernel image, little-endian
	IMAGE_LE64(_kernel_flags_le)	// Informative flags, little-endian
	...

Thanks,
Mark.

> 
> -- 
> Ard.
> 
> 
> 
> >
> >>>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> >>>> ---
> >>>>  arch/arm64/include/asm/assembler.h | 15 ++++++++
> >>>>  arch/arm64/kernel/head.S           | 17 +++++++--
> >>>>  arch/arm64/kernel/image.h          | 37 ++++++--------------
> >>>>  3 files changed, 40 insertions(+), 29 deletions(-)
> >>>>
> >>>> diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
> >>>> index d8bfcc1ce923..e211af783a3d 100644
> >>>> --- a/arch/arm64/include/asm/assembler.h
> >>>> +++ b/arch/arm64/include/asm/assembler.h
> >>>> @@ -222,4 +222,19 @@ lr       .req    x30             // link register
> >>>>       .size   __pi_##x, . - x;        \
> >>>>       ENDPROC(x)
> >>>>
> >>>> +     .macro  le16, val
> >>>> +     .byte   \val & 0xff
> >>>> +     .byte   (\val >> 8) & 0xff
> >>>> +     .endm
> >>>> +
> >>>> +     .macro  le32, val
> >>>> +     le16    \val
> >>>> +     le16    (\val >> 16)
> >>>> +     .endm
> >>>> +
> >>>> +     .macro  le64, val
> >>>> +     le32    \val
> >>>> +     le32    (\val >> 32)
> >>>> +     .endm
> >>>> +
> >>>>  #endif       /* __ASM_ASSEMBLER_H */
> >>>> diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
> >>>> index 350515276541..211f75e673f4 100644
> >>>> --- a/arch/arm64/kernel/head.S
> >>>> +++ b/arch/arm64/kernel/head.S
> >>>> @@ -51,6 +51,17 @@
> >>>>  #define KERNEL_START _text
> >>>>  #define KERNEL_END   _end
> >>>>
> >>>> +#ifdef CONFIG_CPU_BIG_ENDIAN
> >>>> +#define __HEAD_FLAG_BE       1
> >>>> +#else
> >>>> +#define __HEAD_FLAG_BE       0
> >>>> +#endif
> >>>> +
> >>>> +#define __HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2)
> >>>> +
> >>>> +#define __HEAD_FLAGS ((__HEAD_FLAG_BE << 0) |        \
> >>>> +                      (__HEAD_FLAG_PAGE_SIZE << 1))
> >>>> +
> >>>>  /*
> >>>>   * Kernel startup entry point.
> >>>>   * ---------------------------
> >>>> @@ -83,9 +94,9 @@ efi_head:
> >>>>       b       stext                           // branch to kernel start, magic
> >>>>       .long   0                               // reserved
> >>>>  #endif
> >>>> -     .quad   _kernel_offset_le               // Image load offset from start of RAM, little-endian
> >>>> -     .quad   _kernel_size_le                 // Effective size of kernel image, little-endian
> >>>> -     .quad   _kernel_flags_le                // Informative flags, little-endian
> >>>> +     le64    TEXT_OFFSET                     // Image load offset from start of RAM, little-endian
> >>>> +     .long   _kernel_size_le, 0              // Effective size of kernel image, little-endian
> >>>> +     le64    __HEAD_FLAGS                    // Informative flags, little-endian
> >>>>       .quad   0                               // reserved
> >>>>       .quad   0                               // reserved
> >>>>       .quad   0                               // reserved
> >>>> diff --git a/arch/arm64/kernel/image.h b/arch/arm64/kernel/image.h
> >>>> index bc2abb8b1599..bb6b0e69d0a4 100644
> >>>> --- a/arch/arm64/kernel/image.h
> >>>> +++ b/arch/arm64/kernel/image.h
> >>>> @@ -26,41 +26,26 @@
> >>>>   * There aren't any ELF relocations we can use to endian-swap values known only
> >>>>   * at link time (e.g. the subtraction of two symbol addresses), so we must get
> >>>>   * the linker to endian-swap certain values before emitting them.
> >>>> + * Note that this will not work for 64-bit values: these are resolved using
> >>>> + * R_AARCH64_ABS64 relocations, which are fixed up at runtime rather than at
> >>>> + * build time when building the PIE executable (for KASLR).
> >>>>   */
> >>>>  #ifdef CONFIG_CPU_BIG_ENDIAN
> >>>> -#define DATA_LE64(data)                                      \
> >>>> -     ((((data) & 0x00000000000000ff) << 56) |        \
> >>>> -      (((data) & 0x000000000000ff00) << 40) |        \
> >>>> -      (((data) & 0x0000000000ff0000) << 24) |        \
> >>>> -      (((data) & 0x00000000ff000000) << 8)  |        \
> >>>> -      (((data) & 0x000000ff00000000) >> 8)  |        \
> >>>> -      (((data) & 0x0000ff0000000000) >> 24) |        \
> >>>> -      (((data) & 0x00ff000000000000) >> 40) |        \
> >>>> -      (((data) & 0xff00000000000000) >> 56))
> >>>> +#define DATA_LE32(data)                              \
> >>>> +     ((((data) & 0x000000ff) << 24) |        \
> >>>> +      (((data) & 0x0000ff00) << 8)  |        \
> >>>> +      (((data) & 0x00ff0000) >> 8)  |        \
> >>>> +      (((data) & 0xff000000) >> 24))
> >>>>  #else
> >>>> -#define DATA_LE64(data) ((data) & 0xffffffffffffffff)
> >>>> +#define DATA_LE32(data) ((data) & 0xffffffff)
> >>>>  #endif
> >>>>
> >>>> -#ifdef CONFIG_CPU_BIG_ENDIAN
> >>>> -#define __HEAD_FLAG_BE       1
> >>>> -#else
> >>>> -#define __HEAD_FLAG_BE       0
> >>>> -#endif
> >>>> -
> >>>> -#define __HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2)
> >>>> -
> >>>> -#define __HEAD_FLAGS ((__HEAD_FLAG_BE << 0) |        \
> >>>> -                      (__HEAD_FLAG_PAGE_SIZE << 1))
> >>>> -
> >>>>  /*
> >>>>   * These will output as part of the Image header, which should be little-endian
> >>>> - * regardless of the endianness of the kernel. While constant values could be
> >>>> - * endian swapped in head.S, all are done here for consistency.
> >>>> + * regardless of the endianness of the kernel.
> >>>>   */
> >>>>  #define HEAD_SYMBOLS                                         \
> >>>> -     _kernel_size_le         = DATA_LE64(_end - _text);      \
> >>>> -     _kernel_offset_le       = DATA_LE64(TEXT_OFFSET);       \
> >>>> -     _kernel_flags_le        = DATA_LE64(__HEAD_FLAGS);
> >>>> +     _kernel_size_le         = DATA_LE32(_end - _text);
> >>>>
> >>>>  #ifdef CONFIG_EFI
> >>>>
> >>>> --
> >>>> 2.5.0
> >>>>
> 

[toc] | [prev] | [next] | [standalone]


#1309193 — Re: [PATCH v3 11/21] arm64: avoid R_AARCH64_ABS64 relocations for Image header fields

FromArd Biesheuvel <ard.biesheuvel@linaro.org>
Date2016-01-14 12:30 +0100
SubjectRe: [PATCH v3 11/21] arm64: avoid R_AARCH64_ABS64 relocations for Image header fields
Message-ID<qQOgi-6eV-17@gated-at.bofh.it>
In reply to#1309170
On 14 January 2016 at 11:46, Mark Rutland <mark.rutland@arm.com> wrote:
> On Thu, Jan 14, 2016 at 10:05:42AM +0100, Ard Biesheuvel wrote:
>> On 14 January 2016 at 09:51, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
>> > On 13 January 2016 at 19:48, Ard Biesheuvel <ard.biesheuvel@linaro.org> wrote:
>> >> On 13 January 2016 at 19:12, Mark Rutland <mark.rutland@arm.com> wrote:
>> >>> On Mon, Jan 11, 2016 at 02:19:04PM +0100, Ard Biesheuvel wrote:
>> >>>> Unfortunately, the current way of using the linker to emit build time
>> >>>> constants into the Image header will no longer work once we switch to
>> >>>> the use of PIE executables. The reason is that such constants are emitted
>> >>>> into the binary using R_AARCH64_ABS64 relocations, which we will resolve
>> >>>> at runtime, not at build time, and the places targeted by those
>> >>>> relocations will contain zeroes before that.
>> >>>>
>> >>>> So move back to assembly time constants or R_AARCH64_ABS32 relocations
>> >>>> (which, interestingly enough, do get resolved at build time)
>> >>>
>> >>> To me it seems very odd that ABS64 and ABS32 are treated differently,
>> >>> and it makes me somewhat uncomfortable becuase it feels like a bug.
>> >>>
>> >>> Do we know whether the inconsistency between ABS64 and ABS32 was
>> >>> deliberate?
>> >>>
>> >>> I couldn't spot anything declaring a difference in the AArch64 ELF
>> >>> spec, and I'm not sure where else to look.
>> >>>
>> >>
>> >> My assumption is that PIE only defers resolving R_AARCH64_ABS64
>> >> relocations since those are the only ones that can be used to refer to
>> >> memory addresses
>> >>
>> >
>> > OK, digging into the binutils source code, it turns out that indeed,
>> > ABSnn relocations where nn equals the ELFnn memory size are treated
>> > differently, but only if they have default visibility. This is simply
>> > a result of the fact the code path is shared between shared libraries
>> > and PIE executables, since PIE executable are fully linked. It also
>> > means that we can simply work around it by emitting the linker symbols
>> > as hidden.
>> >
>>
>> ... and the bad news is that, while emitting the symbols as hidden
>> turns them from R_AARCH64_ABS64 into a R_AARCH64_RELATIVE relocations,
>> it does not actually force the value to be emitted at build time.
>>
>> So I am going to stick with the patch, but elaborate in a comment
>> about why R_AARCH64_ABSnn are treated differently if nn equals the
>> pointer size. (look at elfNN_aarch64_final_link_relocate() in binutils
>> if you are keen to look at the code yourself)
>
> Ok. Thanks for digging into that.
>
> One thing though: I would prefer if we could still keep all the LE64
> image header values together, to have them dealt with consistently.
>
> Could we hide the ABS32 usage behind some macros to do so, e.g.
>
> in image.h:
>
> #define DEFINE_IMAGE_LE64(sym, data)                            \
>         sym##_lo32 = DATA_LE32(data & 0xffffffff);              \
>         sym##_hi32 = DATA_LE32(data >> 32);
>
> #define HEAD_SYMBOLS                                            \
>         DEFINE_IMAGE_LE64(_kernel_size_le, _end - _text);       \
>         DEFINE_IMAGE_LE64(_kernel_offset_le, TEXT_OFFSET);      \
>         DEFINE_IMAGE_LE64(_kernel_flags_le, __HEAD_FLAGS);
>

I will steal this

> and in head.S:
>
> #define IMAGE_LE64(sym) .long sym##_lo32, sym##_hi32
>
>         ...
>         IMAGE_LE64(_kernel_size_le)     // Image load offset from start of RAM, little-endian
>         IMAGE_LE64(_kernel_offset_le)   // Effective size of kernel image, little-endian
>         IMAGE_LE64(_kernel_flags_le)    // Informative flags, little-endian
>         ...

... and implement this with an asm macro.

Thanks,
Ard.



>>
>> --
>> Ard.
>>
>>
>>
>> >
>> >>>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> >>>> ---
>> >>>>  arch/arm64/include/asm/assembler.h | 15 ++++++++
>> >>>>  arch/arm64/kernel/head.S           | 17 +++++++--
>> >>>>  arch/arm64/kernel/image.h          | 37 ++++++--------------
>> >>>>  3 files changed, 40 insertions(+), 29 deletions(-)
>> >>>>
>> >>>> diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
>> >>>> index d8bfcc1ce923..e211af783a3d 100644
>> >>>> --- a/arch/arm64/include/asm/assembler.h
>> >>>> +++ b/arch/arm64/include/asm/assembler.h
>> >>>> @@ -222,4 +222,19 @@ lr       .req    x30             // link register
>> >>>>       .size   __pi_##x, . - x;        \
>> >>>>       ENDPROC(x)
>> >>>>
>> >>>> +     .macro  le16, val
>> >>>> +     .byte   \val & 0xff
>> >>>> +     .byte   (\val >> 8) & 0xff
>> >>>> +     .endm
>> >>>> +
>> >>>> +     .macro  le32, val
>> >>>> +     le16    \val
>> >>>> +     le16    (\val >> 16)
>> >>>> +     .endm
>> >>>> +
>> >>>> +     .macro  le64, val
>> >>>> +     le32    \val
>> >>>> +     le32    (\val >> 32)
>> >>>> +     .endm
>> >>>> +
>> >>>>  #endif       /* __ASM_ASSEMBLER_H */
>> >>>> diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
>> >>>> index 350515276541..211f75e673f4 100644
>> >>>> --- a/arch/arm64/kernel/head.S
>> >>>> +++ b/arch/arm64/kernel/head.S
>> >>>> @@ -51,6 +51,17 @@
>> >>>>  #define KERNEL_START _text
>> >>>>  #define KERNEL_END   _end
>> >>>>
>> >>>> +#ifdef CONFIG_CPU_BIG_ENDIAN
>> >>>> +#define __HEAD_FLAG_BE       1
>> >>>> +#else
>> >>>> +#define __HEAD_FLAG_BE       0
>> >>>> +#endif
>> >>>> +
>> >>>> +#define __HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2)
>> >>>> +
>> >>>> +#define __HEAD_FLAGS ((__HEAD_FLAG_BE << 0) |        \
>> >>>> +                      (__HEAD_FLAG_PAGE_SIZE << 1))
>> >>>> +
>> >>>>  /*
>> >>>>   * Kernel startup entry point.
>> >>>>   * ---------------------------
>> >>>> @@ -83,9 +94,9 @@ efi_head:
>> >>>>       b       stext                           // branch to kernel start, magic
>> >>>>       .long   0                               // reserved
>> >>>>  #endif
>> >>>> -     .quad   _kernel_offset_le               // Image load offset from start of RAM, little-endian
>> >>>> -     .quad   _kernel_size_le                 // Effective size of kernel image, little-endian
>> >>>> -     .quad   _kernel_flags_le                // Informative flags, little-endian
>> >>>> +     le64    TEXT_OFFSET                     // Image load offset from start of RAM, little-endian
>> >>>> +     .long   _kernel_size_le, 0              // Effective size of kernel image, little-endian
>> >>>> +     le64    __HEAD_FLAGS                    // Informative flags, little-endian
>> >>>>       .quad   0                               // reserved
>> >>>>       .quad   0                               // reserved
>> >>>>       .quad   0                               // reserved
>> >>>> diff --git a/arch/arm64/kernel/image.h b/arch/arm64/kernel/image.h
>> >>>> index bc2abb8b1599..bb6b0e69d0a4 100644
>> >>>> --- a/arch/arm64/kernel/image.h
>> >>>> +++ b/arch/arm64/kernel/image.h
>> >>>> @@ -26,41 +26,26 @@
>> >>>>   * There aren't any ELF relocations we can use to endian-swap values known only
>> >>>>   * at link time (e.g. the subtraction of two symbol addresses), so we must get
>> >>>>   * the linker to endian-swap certain values before emitting them.
>> >>>> + * Note that this will not work for 64-bit values: these are resolved using
>> >>>> + * R_AARCH64_ABS64 relocations, which are fixed up at runtime rather than at
>> >>>> + * build time when building the PIE executable (for KASLR).
>> >>>>   */
>> >>>>  #ifdef CONFIG_CPU_BIG_ENDIAN
>> >>>> -#define DATA_LE64(data)                                      \
>> >>>> -     ((((data) & 0x00000000000000ff) << 56) |        \
>> >>>> -      (((data) & 0x000000000000ff00) << 40) |        \
>> >>>> -      (((data) & 0x0000000000ff0000) << 24) |        \
>> >>>> -      (((data) & 0x00000000ff000000) << 8)  |        \
>> >>>> -      (((data) & 0x000000ff00000000) >> 8)  |        \
>> >>>> -      (((data) & 0x0000ff0000000000) >> 24) |        \
>> >>>> -      (((data) & 0x00ff000000000000) >> 40) |        \
>> >>>> -      (((data) & 0xff00000000000000) >> 56))
>> >>>> +#define DATA_LE32(data)                              \
>> >>>> +     ((((data) & 0x000000ff) << 24) |        \
>> >>>> +      (((data) & 0x0000ff00) << 8)  |        \
>> >>>> +      (((data) & 0x00ff0000) >> 8)  |        \
>> >>>> +      (((data) & 0xff000000) >> 24))
>> >>>>  #else
>> >>>> -#define DATA_LE64(data) ((data) & 0xffffffffffffffff)
>> >>>> +#define DATA_LE32(data) ((data) & 0xffffffff)
>> >>>>  #endif
>> >>>>
>> >>>> -#ifdef CONFIG_CPU_BIG_ENDIAN
>> >>>> -#define __HEAD_FLAG_BE       1
>> >>>> -#else
>> >>>> -#define __HEAD_FLAG_BE       0
>> >>>> -#endif
>> >>>> -
>> >>>> -#define __HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2)
>> >>>> -
>> >>>> -#define __HEAD_FLAGS ((__HEAD_FLAG_BE << 0) |        \
>> >>>> -                      (__HEAD_FLAG_PAGE_SIZE << 1))
>> >>>> -
>> >>>>  /*
>> >>>>   * These will output as part of the Image header, which should be little-endian
>> >>>> - * regardless of the endianness of the kernel. While constant values could be
>> >>>> - * endian swapped in head.S, all are done here for consistency.
>> >>>> + * regardless of the endianness of the kernel.
>> >>>>   */
>> >>>>  #define HEAD_SYMBOLS                                         \
>> >>>> -     _kernel_size_le         = DATA_LE64(_end - _text);      \
>> >>>> -     _kernel_offset_le       = DATA_LE64(TEXT_OFFSET);       \
>> >>>> -     _kernel_flags_le        = DATA_LE64(__HEAD_FLAGS);
>> >>>> +     _kernel_size_le         = DATA_LE32(_end - _text);
>> >>>>
>> >>>>  #ifdef CONFIG_EFI
>> >>>>
>> >>>> --
>> >>>> 2.5.0
>> >>>>
>>

[toc] | [prev] | [next] | [standalone]


#1306192 — [PATCH v3 06/21] arm64: pgtable: implement static [pte|pmd|pud]_offset variants

FromArd Biesheuvel <ard.biesheuvel@linaro.org>
Date2016-01-11 14:30 +0100
Subject[PATCH v3 06/21] arm64: pgtable: implement static [pte|pmd|pud]_offset variants
Message-ID<qPKHM-2Wj-25@gated-at.bofh.it>
In reply to#1306179
The page table accessors pte_offset(), pud_offset() and pmd_offset()
rely on __va translations, so they can only be used after the linear
mapping has been installed. For the early fixmap and kasan init routines,
whose page tables are allocated statically in the kernel image, these
functions will return bogus values. So implement pmd_offset_kimg() and
pud_offset_kimg(), which can be used instead before any page tables have
been allocated dynamically.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 arch/arm64/include/asm/pgtable.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 6129f6755081..7b4e16068c9f 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -449,6 +449,9 @@ static inline phys_addr_t pmd_page_paddr(pmd_t pmd)
 
 #define pmd_page(pmd)		pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK))
 
+/* use ONLY for statically allocated translation tables */
+#define pte_offset_kimg(dir,addr)	((pte_t *)__phys_to_kimg(pte_offset_phys((dir), (addr))))
+
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
@@ -492,6 +495,9 @@ static inline phys_addr_t pud_page_paddr(pud_t pud)
 
 #define pud_page(pud)		pfn_to_page(__phys_to_pfn(pud_val(pud) & PHYS_MASK))
 
+/* use ONLY for statically allocated translation tables */
+#define pmd_offset_kimg(dir,addr)	((pmd_t *)__phys_to_kimg(pmd_offset_phys((dir), (addr))))
+
 #else
 
 #define pud_page_paddr(pud)	({ BUILD_BUG(); 0; })
@@ -502,6 +508,8 @@ static inline phys_addr_t pud_page_paddr(pud_t pud)
 #define pmd_set_fixmap_offset(pudp, addr)	((pmd_t *)pudp)
 #define pmd_clear_fixmap()
 
+#define pmd_offset_kimg(dir,addr)	((pmd_t *)dir)
+
 #endif	/* CONFIG_PGTABLE_LEVELS > 2 */
 
 #if CONFIG_PGTABLE_LEVELS > 3
@@ -540,6 +548,9 @@ static inline phys_addr_t pgd_page_paddr(pgd_t pgd)
 
 #define pgd_page(pgd)		pfn_to_page(__phys_to_pfn(pgd_val(pgd) & PHYS_MASK))
 
+/* use ONLY for statically allocated translation tables */
+#define pud_offset_kimg(dir,addr)	((pud_t *)__phys_to_kimg(pud_offset_phys((dir), (addr))))
+
 #else
 
 #define pgd_page_paddr(pgd)	({ BUILD_BUG(); 0;})
@@ -550,6 +561,8 @@ static inline phys_addr_t pgd_page_paddr(pgd_t pgd)
 #define pud_set_fixmap_offset(pgdp, addr)	((pud_t *)pgdp)
 #define pud_clear_fixmap()
 
+#define pud_offset_kimg(dir,addr)	((pud_t *)dir)
+
 #endif  /* CONFIG_PGTABLE_LEVELS > 3 */
 
 #define pgd_ERROR(pgd)		__pgd_error(__FILE__, __LINE__, pgd_val(pgd))
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1306463 — Re: [PATCH v3 06/21] arm64: pgtable: implement static [pte|pmd|pud]_offset variants

FromMark Rutland <mark.rutland@arm.com>
Date2016-01-11 17:30 +0100
SubjectRe: [PATCH v3 06/21] arm64: pgtable: implement static [pte|pmd|pud]_offset variants
Message-ID<qPNvX-4Q9-1@gated-at.bofh.it>
In reply to#1306192
On Mon, Jan 11, 2016 at 02:18:59PM +0100, Ard Biesheuvel wrote:
> The page table accessors pte_offset(), pud_offset() and pmd_offset()
> rely on __va translations, so they can only be used after the linear
> mapping has been installed. For the early fixmap and kasan init routines,
> whose page tables are allocated statically in the kernel image, these
> functions will return bogus values. So implement pmd_offset_kimg() and
> pud_offset_kimg(), which can be used instead before any page tables have
> been allocated dynamically.
> 
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

This looks good to me. One possible suggsetion below, but either way:

Reviewed-by: Mark Rutland <mark.rutland@arm.com>

> ---
>  arch/arm64/include/asm/pgtable.h | 13 +++++++++++++
>  1 file changed, 13 insertions(+)
> 
> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> index 6129f6755081..7b4e16068c9f 100644
> --- a/arch/arm64/include/asm/pgtable.h
> +++ b/arch/arm64/include/asm/pgtable.h
> @@ -449,6 +449,9 @@ static inline phys_addr_t pmd_page_paddr(pmd_t pmd)
>  
>  #define pmd_page(pmd)		pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK))
>  
> +/* use ONLY for statically allocated translation tables */
> +#define pte_offset_kimg(dir,addr)	((pte_t *)__phys_to_kimg(pte_offset_phys((dir), (addr))))
> +

Given that we're probably only going to use this during one-off setup,
maybe it's worth something like:

#define IN_KERNEL_IMAGE(p) ({						\
	unsigned long __p = (unsigned long)p;				\
	KIMAGE_VADDR <= __p && __p < _end;				\
})

#define pte_offset_kimg(dir,addr) ({					\
	BUG_ON(!IN_KERNEL_IMAGE(dir));					\
	((pte_t *)__phys_to_kimg(pte_offset_phys((dir), (addr))));	\
})

That might be overkill, though, given all it does is turn one runtime
failure into another runtime failure.

Mark.

>  /*
>   * Conversion functions: convert a page and protection to a page entry,
>   * and a page entry and page directory to the page they refer to.
> @@ -492,6 +495,9 @@ static inline phys_addr_t pud_page_paddr(pud_t pud)
>  
>  #define pud_page(pud)		pfn_to_page(__phys_to_pfn(pud_val(pud) & PHYS_MASK))
>  
> +/* use ONLY for statically allocated translation tables */
> +#define pmd_offset_kimg(dir,addr)	((pmd_t *)__phys_to_kimg(pmd_offset_phys((dir), (addr))))
> +
>  #else
>  
>  #define pud_page_paddr(pud)	({ BUILD_BUG(); 0; })
> @@ -502,6 +508,8 @@ static inline phys_addr_t pud_page_paddr(pud_t pud)
>  #define pmd_set_fixmap_offset(pudp, addr)	((pmd_t *)pudp)
>  #define pmd_clear_fixmap()
>  
> +#define pmd_offset_kimg(dir,addr)	((pmd_t *)dir)
> +
>  #endif	/* CONFIG_PGTABLE_LEVELS > 2 */
>  
>  #if CONFIG_PGTABLE_LEVELS > 3
> @@ -540,6 +548,9 @@ static inline phys_addr_t pgd_page_paddr(pgd_t pgd)
>  
>  #define pgd_page(pgd)		pfn_to_page(__phys_to_pfn(pgd_val(pgd) & PHYS_MASK))
>  
> +/* use ONLY for statically allocated translation tables */
> +#define pud_offset_kimg(dir,addr)	((pud_t *)__phys_to_kimg(pud_offset_phys((dir), (addr))))
> +
>  #else
>  
>  #define pgd_page_paddr(pgd)	({ BUILD_BUG(); 0;})
> @@ -550,6 +561,8 @@ static inline phys_addr_t pgd_page_paddr(pgd_t pgd)
>  #define pud_set_fixmap_offset(pgdp, addr)	((pud_t *)pgdp)
>  #define pud_clear_fixmap()
>  
> +#define pud_offset_kimg(dir,addr)	((pud_t *)dir)
> +
>  #endif  /* CONFIG_PGTABLE_LEVELS > 3 */
>  
>  #define pgd_ERROR(pgd)		__pgd_error(__FILE__, __LINE__, pgd_val(pgd))
> -- 
> 2.5.0
> 

[toc] | [prev] | [next] | [standalone]


#1306534 — Re: [PATCH v3 06/21] arm64: pgtable: implement static [pte|pmd|pud]_offset variants

FromArd Biesheuvel <ard.biesheuvel@linaro.org>
Date2016-01-11 18:30 +0100
SubjectRe: [PATCH v3 06/21] arm64: pgtable: implement static [pte|pmd|pud]_offset variants
Message-ID<qPOs3-5vv-25@gated-at.bofh.it>
In reply to#1306463
On 11 January 2016 at 17:24, Mark Rutland <mark.rutland@arm.com> wrote:
> On Mon, Jan 11, 2016 at 02:18:59PM +0100, Ard Biesheuvel wrote:
>> The page table accessors pte_offset(), pud_offset() and pmd_offset()
>> rely on __va translations, so they can only be used after the linear
>> mapping has been installed. For the early fixmap and kasan init routines,
>> whose page tables are allocated statically in the kernel image, these
>> functions will return bogus values. So implement pmd_offset_kimg() and
>> pud_offset_kimg(), which can be used instead before any page tables have
>> been allocated dynamically.
>>
>> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>
> This looks good to me. One possible suggsetion below, but either way:
>
> Reviewed-by: Mark Rutland <mark.rutland@arm.com>
>
>> ---
>>  arch/arm64/include/asm/pgtable.h | 13 +++++++++++++
>>  1 file changed, 13 insertions(+)
>>
>> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
>> index 6129f6755081..7b4e16068c9f 100644
>> --- a/arch/arm64/include/asm/pgtable.h
>> +++ b/arch/arm64/include/asm/pgtable.h
>> @@ -449,6 +449,9 @@ static inline phys_addr_t pmd_page_paddr(pmd_t pmd)
>>
>>  #define pmd_page(pmd)                pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK))
>>
>> +/* use ONLY for statically allocated translation tables */
>> +#define pte_offset_kimg(dir,addr)    ((pte_t *)__phys_to_kimg(pte_offset_phys((dir), (addr))))
>> +
>
> Given that we're probably only going to use this during one-off setup,
> maybe it's worth something like:
>
> #define IN_KERNEL_IMAGE(p) ({                                           \
>         unsigned long __p = (unsigned long)p;                           \
>         KIMAGE_VADDR <= __p && __p < _end;                              \
> })
>
> #define pte_offset_kimg(dir,addr) ({                                    \
>         BUG_ON(!IN_KERNEL_IMAGE(dir));                                  \
>         ((pte_t *)__phys_to_kimg(pte_offset_phys((dir), (addr))));      \
> })
>
> That might be overkill, though, given all it does is turn one runtime
> failure into another runtime failure.
>

Yes. I did consider implementing them out of line, with __init
annotations so you at least get complaints if you refer to them from
non-init code, but I don't see how we would ever need these anywhere
beyond fixmap and kasan anyway

>
>>  /*
>>   * Conversion functions: convert a page and protection to a page entry,
>>   * and a page entry and page directory to the page they refer to.
>> @@ -492,6 +495,9 @@ static inline phys_addr_t pud_page_paddr(pud_t pud)
>>
>>  #define pud_page(pud)                pfn_to_page(__phys_to_pfn(pud_val(pud) & PHYS_MASK))
>>
>> +/* use ONLY for statically allocated translation tables */
>> +#define pmd_offset_kimg(dir,addr)    ((pmd_t *)__phys_to_kimg(pmd_offset_phys((dir), (addr))))
>> +
>>  #else
>>
>>  #define pud_page_paddr(pud)  ({ BUILD_BUG(); 0; })
>> @@ -502,6 +508,8 @@ static inline phys_addr_t pud_page_paddr(pud_t pud)
>>  #define pmd_set_fixmap_offset(pudp, addr)    ((pmd_t *)pudp)
>>  #define pmd_clear_fixmap()
>>
>> +#define pmd_offset_kimg(dir,addr)    ((pmd_t *)dir)
>> +
>>  #endif       /* CONFIG_PGTABLE_LEVELS > 2 */
>>
>>  #if CONFIG_PGTABLE_LEVELS > 3
>> @@ -540,6 +548,9 @@ static inline phys_addr_t pgd_page_paddr(pgd_t pgd)
>>
>>  #define pgd_page(pgd)                pfn_to_page(__phys_to_pfn(pgd_val(pgd) & PHYS_MASK))
>>
>> +/* use ONLY for statically allocated translation tables */
>> +#define pud_offset_kimg(dir,addr)    ((pud_t *)__phys_to_kimg(pud_offset_phys((dir), (addr))))
>> +
>>  #else
>>
>>  #define pgd_page_paddr(pgd)  ({ BUILD_BUG(); 0;})
>> @@ -550,6 +561,8 @@ static inline phys_addr_t pgd_page_paddr(pgd_t pgd)
>>  #define pud_set_fixmap_offset(pgdp, addr)    ((pud_t *)pgdp)
>>  #define pud_clear_fixmap()
>>
>> +#define pud_offset_kimg(dir,addr)    ((pud_t *)dir)
>> +
>>  #endif  /* CONFIG_PGTABLE_LEVELS > 3 */
>>
>>  #define pgd_ERROR(pgd)               __pgd_error(__FILE__, __LINE__, pgd_val(pgd))
>> --
>> 2.5.0
>>

[toc] | [prev] | [next] | [standalone]


#1306555 — Re: [PATCH v3 06/21] arm64: pgtable: implement static [pte|pmd|pud]_offset variants

FromMark Rutland <mark.rutland@arm.com>
Date2016-01-11 18:40 +0100
SubjectRe: [PATCH v3 06/21] arm64: pgtable: implement static [pte|pmd|pud]_offset variants
Message-ID<qPOBK-5zs-49@gated-at.bofh.it>
In reply to#1306534
On Mon, Jan 11, 2016 at 06:28:51PM +0100, Ard Biesheuvel wrote:
> On 11 January 2016 at 17:24, Mark Rutland <mark.rutland@arm.com> wrote:
> > On Mon, Jan 11, 2016 at 02:18:59PM +0100, Ard Biesheuvel wrote:
> >> The page table accessors pte_offset(), pud_offset() and pmd_offset()
> >> rely on __va translations, so they can only be used after the linear
> >> mapping has been installed. For the early fixmap and kasan init routines,
> >> whose page tables are allocated statically in the kernel image, these
> >> functions will return bogus values. So implement pmd_offset_kimg() and
> >> pud_offset_kimg(), which can be used instead before any page tables have
> >> been allocated dynamically.
> >>
> >> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> >
> > This looks good to me. One possible suggsetion below, but either way:
> >
> > Reviewed-by: Mark Rutland <mark.rutland@arm.com>
> >
> >> ---
> >>  arch/arm64/include/asm/pgtable.h | 13 +++++++++++++
> >>  1 file changed, 13 insertions(+)
> >>
> >> diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
> >> index 6129f6755081..7b4e16068c9f 100644
> >> --- a/arch/arm64/include/asm/pgtable.h
> >> +++ b/arch/arm64/include/asm/pgtable.h
> >> @@ -449,6 +449,9 @@ static inline phys_addr_t pmd_page_paddr(pmd_t pmd)
> >>
> >>  #define pmd_page(pmd)                pfn_to_page(__phys_to_pfn(pmd_val(pmd) & PHYS_MASK))
> >>
> >> +/* use ONLY for statically allocated translation tables */
> >> +#define pte_offset_kimg(dir,addr)    ((pte_t *)__phys_to_kimg(pte_offset_phys((dir), (addr))))
> >> +
> >
> > Given that we're probably only going to use this during one-off setup,
> > maybe it's worth something like:
> >
> > #define IN_KERNEL_IMAGE(p) ({                                           \
> >         unsigned long __p = (unsigned long)p;                           \
> >         KIMAGE_VADDR <= __p && __p < _end;                              \
> > })
> >
> > #define pte_offset_kimg(dir,addr) ({                                    \
> >         BUG_ON(!IN_KERNEL_IMAGE(dir));                                  \
> >         ((pte_t *)__phys_to_kimg(pte_offset_phys((dir), (addr))));      \
> > })
> >
> > That might be overkill, though, given all it does is turn one runtime
> > failure into another runtime failure.
> >
> 
> Yes. I did consider implementing them out of line, with __init
> annotations so you at least get complaints if you refer to them from
> non-init code, but I don't see how we would ever need these anywhere
> beyond fixmap and kasan anyway

Ok. Let's forget about that for now then. :)

Mark.

[toc] | [prev] | [next] | [standalone]


#1306194 — [PATCH v3 13/21] arm64: allow kernel Image to be loaded anywhere in physical memory

FromArd Biesheuvel <ard.biesheuvel@linaro.org>
Date2016-01-11 14:30 +0100
Subject[PATCH v3 13/21] arm64: allow kernel Image to be loaded anywhere in physical memory
Message-ID<qPKHM-2Wj-29@gated-at.bofh.it>
In reply to#1306179
This relaxes the kernel Image placement requirements, so that it
may be placed at any 2 MB aligned offset in physical memory.

This is accomplished by ignoring PHYS_OFFSET when installing
memblocks, and accounting for the apparent virtual offset of
the kernel Image. As a result, virtual address references
below PAGE_OFFSET are correctly mapped onto physical references
into the kernel Image regardless of where it sits in memory.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 Documentation/arm64/booting.txt         | 20 ++++--
 arch/arm64/include/asm/boot.h           |  6 ++
 arch/arm64/include/asm/kernel-pgtable.h | 11 +++
 arch/arm64/include/asm/kvm_mmu.h        |  2 +-
 arch/arm64/include/asm/memory.h         | 15 +++--
 arch/arm64/kernel/head.S                | 19 ++++--
 arch/arm64/mm/init.c                    | 71 +++++++++++++++++++-
 arch/arm64/mm/mmu.c                     |  3 +
 8 files changed, 125 insertions(+), 22 deletions(-)

diff --git a/Documentation/arm64/booting.txt b/Documentation/arm64/booting.txt
index 701d39d3171a..67484067ce4f 100644
--- a/Documentation/arm64/booting.txt
+++ b/Documentation/arm64/booting.txt
@@ -109,7 +109,13 @@ Header notes:
 			1 - 4K
 			2 - 16K
 			3 - 64K
-  Bits 3-63:	Reserved.
+  Bit 3:	Kernel physical placement
+			0 - 2MB aligned base should be as close as possible
+			    to the base of DRAM, since memory below it is not
+			    accessible
+			1 - 2MB aligned base may be anywhere in physical
+			    memory
+  Bits 4-63:	Reserved.
 
 - When image_size is zero, a bootloader should attempt to keep as much
   memory as possible free for use by the kernel immediately after the
@@ -117,14 +123,14 @@ Header notes:
   depending on selected features, and is effectively unbound.
 
 The Image must be placed text_offset bytes from a 2MB aligned base
-address near the start of usable system RAM and called there. Memory
-below that base address is currently unusable by Linux, and therefore it
-is strongly recommended that this location is the start of system RAM.
-The region between the 2 MB aligned base address and the start of the
-image has no special significance to the kernel, and may be used for
-other purposes.
+address anywhere in usable system RAM and called there. The region
+between the 2 MB aligned base address and the start of the image has no
+special significance to the kernel, and may be used for other purposes.
 At least image_size bytes from the start of the image must be free for
 use by the kernel.
+NOTE: versions prior to v4.6 cannot make use of memory below the
+physical offset of the Image so it is recommended that the Image be
+placed as close as possible to the start of system RAM.
 
 Any memory described to the kernel (even that below the start of the
 image) which is not marked as reserved from the kernel (e.g., with a
diff --git a/arch/arm64/include/asm/boot.h b/arch/arm64/include/asm/boot.h
index 81151b67b26b..ebf2481889c3 100644
--- a/arch/arm64/include/asm/boot.h
+++ b/arch/arm64/include/asm/boot.h
@@ -11,4 +11,10 @@
 #define MIN_FDT_ALIGN		8
 #define MAX_FDT_SIZE		SZ_2M
 
+/*
+ * arm64 requires the kernel image to placed
+ * TEXT_OFFSET bytes beyond a 2 MB aligned base
+ */
+#define MIN_KIMG_ALIGN		SZ_2M
+
 #endif
diff --git a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h
index daa8a7b9917a..dfe4bae463b7 100644
--- a/arch/arm64/include/asm/kernel-pgtable.h
+++ b/arch/arm64/include/asm/kernel-pgtable.h
@@ -80,5 +80,16 @@
 #define SWAPPER_MM_MMUFLAGS	(PTE_ATTRINDX(MT_NORMAL) | SWAPPER_PTE_FLAGS)
 #endif
 
+/*
+ * To make optimal use of block mappings when laying out the linear mapping,
+ * round down the base of physical memory to a size that can be mapped
+ * efficiently, i.e., either PUD_SIZE (4k) or PMD_SIZE (64k), or a multiple that
+ * can be mapped using contiguous bits in the page tables: 32 * PMD_SIZE (16k)
+ */
+#ifdef CONFIG_ARM64_64K_PAGES
+#define ARM64_MEMSTART_ALIGN	SZ_512M
+#else
+#define ARM64_MEMSTART_ALIGN	SZ_1G
+#endif
 
 #endif	/* __ASM_KERNEL_PGTABLE_H */
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 0899026a2821..7e9516365b76 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -73,7 +73,7 @@
 
 #define KERN_TO_HYP(kva)	((unsigned long)kva - PAGE_OFFSET + HYP_PAGE_OFFSET)
 
-#define kvm_ksym_ref(sym)	((void *)&sym - KIMAGE_VADDR + PAGE_OFFSET)
+#define kvm_ksym_ref(sym)	phys_to_virt((u64)&sym - kimage_voffset)
 
 /*
  * We currently only support a 40bit IPA.
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index e45d3141ad98..758fb4a503ef 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -89,10 +89,10 @@
 #define __virt_to_phys(x) ({						\
 	phys_addr_t __x = (phys_addr_t)(x);				\
 	__x >= PAGE_OFFSET ? (__x - PAGE_OFFSET + PHYS_OFFSET) :	\
-			     (__x - KIMAGE_VADDR + PHYS_OFFSET); })
+			     (__x - kimage_voffset); })
 
 #define __phys_to_virt(x)	((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET))
-#define __phys_to_kimg(x)	((unsigned long)((x) - PHYS_OFFSET + KIMAGE_VADDR))
+#define __phys_to_kimg(x)	((unsigned long)((x) + kimage_voffset))
 
 /*
  * Convert a page to/from a physical address
@@ -122,13 +122,14 @@ extern phys_addr_t		memstart_addr;
 /* PHYS_OFFSET - the physical address of the start of memory. */
 #define PHYS_OFFSET		({ memstart_addr; })
 
+/* the offset between the kernel virtual and physical mappings */
+extern u64			kimage_voffset;
+
 /*
- * The maximum physical address that the linear direct mapping
- * of system RAM can cover. (PAGE_OFFSET can be interpreted as
- * a 2's complement signed quantity and negated to derive the
- * maximum size of the linear mapping.)
+ * Allow all memory at the discovery stage. We will clip it later.
  */
-#define MAX_MEMBLOCK_ADDR	({ memstart_addr - PAGE_OFFSET - 1; })
+#define MIN_MEMBLOCK_ADDR	0
+#define MAX_MEMBLOCK_ADDR	U64_MAX
 
 /*
  * PFNs are used to describe any physical page; this means
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 5dc8079cef77..d66aee595170 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -52,15 +52,18 @@
 #define KERNEL_END	_end
 
 #ifdef CONFIG_CPU_BIG_ENDIAN
-#define __HEAD_FLAG_BE	1
+#define __HEAD_FLAG_BE		1
 #else
-#define __HEAD_FLAG_BE	0
+#define __HEAD_FLAG_BE		0
 #endif
 
-#define __HEAD_FLAG_PAGE_SIZE ((PAGE_SHIFT - 10) / 2)
+#define __HEAD_FLAG_PHYS_BASE	1
 
-#define __HEAD_FLAGS	((__HEAD_FLAG_BE << 0) |	\
-			 (__HEAD_FLAG_PAGE_SIZE << 1))
+#define __HEAD_FLAG_PAGE_SIZE	((PAGE_SHIFT - 10) / 2)
+
+#define __HEAD_FLAGS		((__HEAD_FLAG_BE << 0) |	\
+				 (__HEAD_FLAG_PAGE_SIZE << 1) |	\
+				 (__HEAD_FLAG_PHYS_BASE << 3))
 
 /*
  * Kernel startup entry point.
@@ -448,7 +451,11 @@ __mmap_switched:
 	and	x4, x4, #~(THREAD_SIZE - 1)
 	msr	sp_el0, x4			// Save thread_info
 	str_l	x21, __fdt_pointer, x5		// Save FDT pointer
-	str_l	x24, memstart_addr, x6		// Save PHYS_OFFSET
+
+	ldr	x0, =KIMAGE_VADDR		// Save the offset between
+	sub	x24, x0, x24			// the kernel virtual and
+	str_l	x24, kimage_voffset, x0		// physical mappings
+
 	mov	x29, #0
 #ifdef CONFIG_KASAN
 	bl	kasan_early_init
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index baa923bda651..9e89965a2fad 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -35,7 +35,9 @@
 #include <linux/efi.h>
 #include <linux/swiotlb.h>
 
+#include <asm/boot.h>
 #include <asm/fixmap.h>
+#include <asm/kernel-pgtable.h>
 #include <asm/memory.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
@@ -157,9 +159,76 @@ static int __init early_mem(char *p)
 }
 early_param("mem", early_mem);
 
+/*
+ * clip_mem_range() - remove memblock memory between @min and @max until
+ *                    we meet the limit in 'memory_limit'.
+ */
+static void __init clip_mem_range(u64 min, u64 max)
+{
+	u64 mem_size, to_remove;
+	int i;
+
+again:
+	mem_size = memblock_phys_mem_size();
+	if (mem_size <= memory_limit || max <= min)
+		return;
+
+	to_remove = mem_size - memory_limit;
+
+	for (i = memblock.memory.cnt - 1; i >= 0; i--) {
+		struct memblock_region *r = memblock.memory.regions + i;
+		u64 start = max(min, r->base);
+		u64 end = min(max, r->base + r->size);
+
+		if (start >= max || end <= min)
+			continue;
+
+		if (end > min) {
+			u64 size = min(to_remove, end - max(start, min));
+
+			memblock_remove(end - size, size);
+		} else {
+			memblock_remove(start, min(max - start, to_remove));
+		}
+		goto again;
+	}
+}
+
 void __init arm64_memblock_init(void)
 {
-	memblock_enforce_memory_limit(memory_limit);
+	const s64 linear_region_size = -(s64)PAGE_OFFSET;
+
+	/*
+	 * Select a suitable value for the base of physical memory.
+	 */
+	memstart_addr = round_down(memblock_start_of_DRAM(),
+				   ARM64_MEMSTART_ALIGN);
+
+	/*
+	 * Remove the memory that we will not be able to cover
+	 * with the linear mapping.
+	 */
+	memblock_remove(memstart_addr + linear_region_size, ULLONG_MAX);
+
+	if (memory_limit != (phys_addr_t)ULLONG_MAX) {
+		u64 kbase = round_down(__pa(_text), MIN_KIMG_ALIGN);
+		u64 kend = PAGE_ALIGN(__pa(_end));
+		u64 const sz_4g = 0x100000000UL;
+
+		/*
+		 * Clip memory in order of preference:
+		 * - above the kernel and above 4 GB
+		 * - between 4 GB and the start of the kernel (if the kernel
+		 *   is loaded high in memory)
+		 * - between the kernel and 4 GB (if the kernel is loaded
+		 *   low in memory)
+		 * - below 4 GB
+		 */
+		clip_mem_range(max(sz_4g, kend), ULLONG_MAX);
+		clip_mem_range(sz_4g, kbase);
+		clip_mem_range(kend, sz_4g);
+		clip_mem_range(0, min(kbase, sz_4g));
+	}
 
 	/*
 	 * Register the kernel text, kernel data, initrd, and initial
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 0b28f1469f9b..a1fd3414a322 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -46,6 +46,9 @@
 
 u64 idmap_t0sz = TCR_T0SZ(VA_BITS);
 
+u64 kimage_voffset __read_mostly;
+EXPORT_SYMBOL(kimage_voffset);
+
 /*
  * Empty_zero_page is a special page that is used for zero-initialized data
  * and COW.
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1306197 — [PATCH v3 12/21] arm64: avoid dynamic relocations in early boot code

FromArd Biesheuvel <ard.biesheuvel@linaro.org>
Date2016-01-11 14:30 +0100
Subject[PATCH v3 12/21] arm64: avoid dynamic relocations in early boot code
Message-ID<qPKHM-2Wj-35@gated-at.bofh.it>
In reply to#1306179
Before implementing KASLR for arm64 by building a self-relocating PIE
executable, we have to ensure that values we use before the relocation
routine is executed are not subject to dynamic relocation themselves.
This applies not only to virtual addresses, but also to values that are
supplied by the linker at build time and relocated using R_AARCH64_ABS64
relocations.

So instead, use assemble time constants, or force the use of static
relocations by folding the constants into the instructions.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 arch/arm64/kernel/efi-entry.S |  2 +-
 arch/arm64/kernel/head.S      | 39 +++++++++++++-------
 2 files changed, 27 insertions(+), 14 deletions(-)

diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S
index a773db92908b..f82036e02485 100644
--- a/arch/arm64/kernel/efi-entry.S
+++ b/arch/arm64/kernel/efi-entry.S
@@ -61,7 +61,7 @@ ENTRY(entry)
 	 */
 	mov	x20, x0		// DTB address
 	ldr	x0, [sp, #16]	// relocated _text address
-	ldr	x21, =stext_offset
+	movz	x21, #:abs_g0:stext_offset
 	add	x21, x0, x21
 
 	/*
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 211f75e673f4..5dc8079cef77 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -78,12 +78,11 @@
  * in the entry routines.
  */
 	__HEAD
-
+_head:
 	/*
 	 * DO NOT MODIFY. Image header expected by Linux boot-loaders.
 	 */
 #ifdef CONFIG_EFI
-efi_head:
 	/*
 	 * This add instruction has no meaningful effect except that
 	 * its opcode forms the magic "MZ" signature required by UEFI.
@@ -105,14 +104,14 @@ efi_head:
 	.byte	0x4d
 	.byte	0x64
 #ifdef CONFIG_EFI
-	.long	pe_header - efi_head		// Offset to the PE header.
+	.long	pe_header - _head		// Offset to the PE header.
 #else
 	.word	0				// reserved
 #endif
 
 #ifdef CONFIG_EFI
 	.globl	__efistub_stext_offset
-	.set	__efistub_stext_offset, stext - efi_head
+	.set	__efistub_stext_offset, stext - _head
 	.align 3
 pe_header:
 	.ascii	"PE"
@@ -135,7 +134,7 @@ optional_header:
 	.long	_end - stext			// SizeOfCode
 	.long	0				// SizeOfInitializedData
 	.long	0				// SizeOfUninitializedData
-	.long	__efistub_entry - efi_head	// AddressOfEntryPoint
+	.long	__efistub_entry - _head		// AddressOfEntryPoint
 	.long	__efistub_stext_offset		// BaseOfCode
 
 extra_header_fields:
@@ -150,7 +149,7 @@ extra_header_fields:
 	.short	0				// MinorSubsystemVersion
 	.long	0				// Win32VersionValue
 
-	.long	_end - efi_head			// SizeOfImage
+	.long	_end - _head			// SizeOfImage
 
 	// Everything before the kernel image is considered part of the header
 	.long	__efistub_stext_offset		// SizeOfHeaders
@@ -230,11 +229,13 @@ ENTRY(stext)
 	 * On return, the CPU will be ready for the MMU to be turned on and
 	 * the TCR will have been set.
 	 */
-	ldr	x27, =__mmap_switched		// address to jump to after
+	ldr	x27, 0f				// address to jump to after
 						// MMU has been enabled
 	adr_l	lr, __enable_mmu		// return (PIC) address
 	b	__cpu_setup			// initialise processor
 ENDPROC(stext)
+	.align	3
+0:	.quad	__mmap_switched - (_head - TEXT_OFFSET) + KIMAGE_VADDR
 
 /*
  * Preserve the arguments passed by the bootloader in x0 .. x3
@@ -402,7 +403,8 @@ __create_page_tables:
 	mov	x0, x26				// swapper_pg_dir
 	ldr	x5, =KIMAGE_VADDR
 	create_pgd_entry x0, x5, x3, x6
-	ldr	x6, =KERNEL_END			// __va(KERNEL_END)
+	ldr	w6, kernel_img_size
+	add	x6, x6, x5
 	mov	x3, x24				// phys offset
 	create_block_map x0, x7, x3, x5, x6
 
@@ -419,6 +421,9 @@ __create_page_tables:
 	mov	lr, x27
 	ret
 ENDPROC(__create_page_tables)
+
+kernel_img_size:
+	.long	_end - (_head - TEXT_OFFSET)
 	.ltorg
 
 /*
@@ -426,6 +431,10 @@ ENDPROC(__create_page_tables)
  */
 	.set	initial_sp, init_thread_union + THREAD_START_SP
 __mmap_switched:
+	adr_l	x8, vectors			// load VBAR_EL1 with virtual
+	msr	vbar_el1, x8			// vector table address
+	isb
+
 	// Clear BSS
 	adr_l	x0, __bss_start
 	mov	x1, xzr
@@ -612,13 +621,19 @@ ENTRY(secondary_startup)
 	adrp	x26, swapper_pg_dir
 	bl	__cpu_setup			// initialise processor
 
-	ldr	x21, =secondary_data
-	ldr	x27, =__secondary_switched	// address to jump to after enabling the MMU
+	ldr	x8, =KIMAGE_VADDR
+	ldr	w9, 0f
+	sub	x27, x8, w9, sxtw		// address to jump to after enabling the MMU
 	b	__enable_mmu
 ENDPROC(secondary_startup)
+0:	.long	(_text - TEXT_OFFSET) - __secondary_switched
 
 ENTRY(__secondary_switched)
-	ldr	x0, [x21]			// get secondary_data.stack
+	adr_l	x5, vectors
+	msr	vbar_el1, x5
+	isb
+
+	ldr_l	x0, secondary_data		// get secondary_data.stack
 	mov	sp, x0
 	and	x0, x0, #~(THREAD_SIZE - 1)
 	msr	sp_el0, x0			// save thread_info
@@ -643,8 +658,6 @@ __enable_mmu:
 	ubfx	x2, x1, #ID_AA64MMFR0_TGRAN_SHIFT, 4
 	cmp	x2, #ID_AA64MMFR0_TGRAN_SUPPORTED
 	b.ne	__no_granule_support
-	ldr	x5, =vectors
-	msr	vbar_el1, x5
 	msr	ttbr0_el1, x25			// load TTBR0
 	msr	ttbr1_el1, x26			// load TTBR1
 	isb
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1309494 — Re: [PATCH v3 12/21] arm64: avoid dynamic relocations in early boot code

FromMark Rutland <mark.rutland@arm.com>
Date2016-01-14 18:20 +0100
SubjectRe: [PATCH v3 12/21] arm64: avoid dynamic relocations in early boot code
Message-ID<qQTJ0-1H2-19@gated-at.bofh.it>
In reply to#1306197
On Mon, Jan 11, 2016 at 02:19:05PM +0100, Ard Biesheuvel wrote:
> Before implementing KASLR for arm64 by building a self-relocating PIE
> executable, we have to ensure that values we use before the relocation
> routine is executed are not subject to dynamic relocation themselves.
> This applies not only to virtual addresses, but also to values that are
> supplied by the linker at build time and relocated using R_AARCH64_ABS64
> relocations.
> 
> So instead, use assemble time constants, or force the use of static
> relocations by folding the constants into the instructions.
> 
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

I think we lose a bit of legibility due to the hoops we jump through for
the new literals. However, it is correct, and I've not managed to come
up with anything nicer.

FWIW:

Reviewed-by: Mark Rutland <mark.rutland@arm.com>

Thanks,
Mark.

> ---
>  arch/arm64/kernel/efi-entry.S |  2 +-
>  arch/arm64/kernel/head.S      | 39 +++++++++++++-------
>  2 files changed, 27 insertions(+), 14 deletions(-)
> 
> diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S
> index a773db92908b..f82036e02485 100644
> --- a/arch/arm64/kernel/efi-entry.S
> +++ b/arch/arm64/kernel/efi-entry.S
> @@ -61,7 +61,7 @@ ENTRY(entry)
>  	 */
>  	mov	x20, x0		// DTB address
>  	ldr	x0, [sp, #16]	// relocated _text address
> -	ldr	x21, =stext_offset
> +	movz	x21, #:abs_g0:stext_offset
>  	add	x21, x0, x21
>  
>  	/*
> diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
> index 211f75e673f4..5dc8079cef77 100644
> --- a/arch/arm64/kernel/head.S
> +++ b/arch/arm64/kernel/head.S
> @@ -78,12 +78,11 @@
>   * in the entry routines.
>   */
>  	__HEAD
> -
> +_head:
>  	/*
>  	 * DO NOT MODIFY. Image header expected by Linux boot-loaders.
>  	 */
>  #ifdef CONFIG_EFI
> -efi_head:
>  	/*
>  	 * This add instruction has no meaningful effect except that
>  	 * its opcode forms the magic "MZ" signature required by UEFI.
> @@ -105,14 +104,14 @@ efi_head:
>  	.byte	0x4d
>  	.byte	0x64
>  #ifdef CONFIG_EFI
> -	.long	pe_header - efi_head		// Offset to the PE header.
> +	.long	pe_header - _head		// Offset to the PE header.
>  #else
>  	.word	0				// reserved
>  #endif
>  
>  #ifdef CONFIG_EFI
>  	.globl	__efistub_stext_offset
> -	.set	__efistub_stext_offset, stext - efi_head
> +	.set	__efistub_stext_offset, stext - _head
>  	.align 3
>  pe_header:
>  	.ascii	"PE"
> @@ -135,7 +134,7 @@ optional_header:
>  	.long	_end - stext			// SizeOfCode
>  	.long	0				// SizeOfInitializedData
>  	.long	0				// SizeOfUninitializedData
> -	.long	__efistub_entry - efi_head	// AddressOfEntryPoint
> +	.long	__efistub_entry - _head		// AddressOfEntryPoint
>  	.long	__efistub_stext_offset		// BaseOfCode
>  
>  extra_header_fields:
> @@ -150,7 +149,7 @@ extra_header_fields:
>  	.short	0				// MinorSubsystemVersion
>  	.long	0				// Win32VersionValue
>  
> -	.long	_end - efi_head			// SizeOfImage
> +	.long	_end - _head			// SizeOfImage
>  
>  	// Everything before the kernel image is considered part of the header
>  	.long	__efistub_stext_offset		// SizeOfHeaders
> @@ -230,11 +229,13 @@ ENTRY(stext)
>  	 * On return, the CPU will be ready for the MMU to be turned on and
>  	 * the TCR will have been set.
>  	 */
> -	ldr	x27, =__mmap_switched		// address to jump to after
> +	ldr	x27, 0f				// address to jump to after
>  						// MMU has been enabled
>  	adr_l	lr, __enable_mmu		// return (PIC) address
>  	b	__cpu_setup			// initialise processor
>  ENDPROC(stext)
> +	.align	3
> +0:	.quad	__mmap_switched - (_head - TEXT_OFFSET) + KIMAGE_VADDR
>  
>  /*
>   * Preserve the arguments passed by the bootloader in x0 .. x3
> @@ -402,7 +403,8 @@ __create_page_tables:
>  	mov	x0, x26				// swapper_pg_dir
>  	ldr	x5, =KIMAGE_VADDR
>  	create_pgd_entry x0, x5, x3, x6
> -	ldr	x6, =KERNEL_END			// __va(KERNEL_END)
> +	ldr	w6, kernel_img_size
> +	add	x6, x6, x5
>  	mov	x3, x24				// phys offset
>  	create_block_map x0, x7, x3, x5, x6
>  
> @@ -419,6 +421,9 @@ __create_page_tables:
>  	mov	lr, x27
>  	ret
>  ENDPROC(__create_page_tables)
> +
> +kernel_img_size:
> +	.long	_end - (_head - TEXT_OFFSET)
>  	.ltorg
>  
>  /*
> @@ -426,6 +431,10 @@ ENDPROC(__create_page_tables)
>   */
>  	.set	initial_sp, init_thread_union + THREAD_START_SP
>  __mmap_switched:
> +	adr_l	x8, vectors			// load VBAR_EL1 with virtual
> +	msr	vbar_el1, x8			// vector table address
> +	isb
> +
>  	// Clear BSS
>  	adr_l	x0, __bss_start
>  	mov	x1, xzr
> @@ -612,13 +621,19 @@ ENTRY(secondary_startup)
>  	adrp	x26, swapper_pg_dir
>  	bl	__cpu_setup			// initialise processor
>  
> -	ldr	x21, =secondary_data
> -	ldr	x27, =__secondary_switched	// address to jump to after enabling the MMU
> +	ldr	x8, =KIMAGE_VADDR
> +	ldr	w9, 0f
> +	sub	x27, x8, w9, sxtw		// address to jump to after enabling the MMU
>  	b	__enable_mmu
>  ENDPROC(secondary_startup)
> +0:	.long	(_text - TEXT_OFFSET) - __secondary_switched
>  
>  ENTRY(__secondary_switched)
> -	ldr	x0, [x21]			// get secondary_data.stack
> +	adr_l	x5, vectors
> +	msr	vbar_el1, x5
> +	isb
> +
> +	ldr_l	x0, secondary_data		// get secondary_data.stack
>  	mov	sp, x0
>  	and	x0, x0, #~(THREAD_SIZE - 1)
>  	msr	sp_el0, x0			// save thread_info
> @@ -643,8 +658,6 @@ __enable_mmu:
>  	ubfx	x2, x1, #ID_AA64MMFR0_TGRAN_SHIFT, 4
>  	cmp	x2, #ID_AA64MMFR0_TGRAN_SUPPORTED
>  	b.ne	__no_granule_support
> -	ldr	x5, =vectors
> -	msr	vbar_el1, x5
>  	msr	ttbr0_el1, x25			// load TTBR0
>  	msr	ttbr1_el1, x26			// load TTBR1
>  	isb
> -- 
> 2.5.0
> 

[toc] | [prev] | [next] | [standalone]


#1306199 — [PATCH v3 15/21] arm64: split elf relocs into a separate header.

FromArd Biesheuvel <ard.biesheuvel@linaro.org>
Date2016-01-11 14:30 +0100
Subject[PATCH v3 15/21] arm64: split elf relocs into a separate header.
Message-ID<qPKHN-2Wj-39@gated-at.bofh.it>
In reply to#1306179
From: Mark Rutland <mark.rutland@arm.com>

Currently, asm/elf.h contains a mixture of simple constants, C structure
definitions, and some constants defined in terms of constants from other
headers (which are themselves mixtures).

To enable the use of AArch64 ELF reloc constants from assembly code (as
we will need for relocatable kernel support), we need an include without
C structure definitions or includes of other files with such definitions.

This patch factors out the relocs into a new header specifically for ELF
reloc types.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 arch/arm64/include/asm/elf.h        | 54 +--------------
 arch/arm64/include/asm/elf_relocs.h | 73 ++++++++++++++++++++
 2 files changed, 74 insertions(+), 53 deletions(-)

diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index faad6df49e5b..e4b3cdcaf597 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -16,6 +16,7 @@
 #ifndef __ASM_ELF_H
 #define __ASM_ELF_H
 
+#include <asm/elf_relocs.h>
 #include <asm/hwcap.h>
 
 /*
@@ -34,59 +35,6 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 typedef struct user_fpsimd_state elf_fpregset_t;
 
 /*
- * AArch64 static relocation types.
- */
-
-/* Miscellaneous. */
-#define R_ARM_NONE			0
-#define R_AARCH64_NONE			256
-
-/* Data. */
-#define R_AARCH64_ABS64			257
-#define R_AARCH64_ABS32			258
-#define R_AARCH64_ABS16			259
-#define R_AARCH64_PREL64		260
-#define R_AARCH64_PREL32		261
-#define R_AARCH64_PREL16		262
-
-/* Instructions. */
-#define R_AARCH64_MOVW_UABS_G0		263
-#define R_AARCH64_MOVW_UABS_G0_NC	264
-#define R_AARCH64_MOVW_UABS_G1		265
-#define R_AARCH64_MOVW_UABS_G1_NC	266
-#define R_AARCH64_MOVW_UABS_G2		267
-#define R_AARCH64_MOVW_UABS_G2_NC	268
-#define R_AARCH64_MOVW_UABS_G3		269
-
-#define R_AARCH64_MOVW_SABS_G0		270
-#define R_AARCH64_MOVW_SABS_G1		271
-#define R_AARCH64_MOVW_SABS_G2		272
-
-#define R_AARCH64_LD_PREL_LO19		273
-#define R_AARCH64_ADR_PREL_LO21		274
-#define R_AARCH64_ADR_PREL_PG_HI21	275
-#define R_AARCH64_ADR_PREL_PG_HI21_NC	276
-#define R_AARCH64_ADD_ABS_LO12_NC	277
-#define R_AARCH64_LDST8_ABS_LO12_NC	278
-
-#define R_AARCH64_TSTBR14		279
-#define R_AARCH64_CONDBR19		280
-#define R_AARCH64_JUMP26		282
-#define R_AARCH64_CALL26		283
-#define R_AARCH64_LDST16_ABS_LO12_NC	284
-#define R_AARCH64_LDST32_ABS_LO12_NC	285
-#define R_AARCH64_LDST64_ABS_LO12_NC	286
-#define R_AARCH64_LDST128_ABS_LO12_NC	299
-
-#define R_AARCH64_MOVW_PREL_G0		287
-#define R_AARCH64_MOVW_PREL_G0_NC	288
-#define R_AARCH64_MOVW_PREL_G1		289
-#define R_AARCH64_MOVW_PREL_G1_NC	290
-#define R_AARCH64_MOVW_PREL_G2		291
-#define R_AARCH64_MOVW_PREL_G2_NC	292
-#define R_AARCH64_MOVW_PREL_G3		293
-
-/*
  * These are used to set parameters in the core dumps.
  */
 #define ELF_CLASS	ELFCLASS64
diff --git a/arch/arm64/include/asm/elf_relocs.h b/arch/arm64/include/asm/elf_relocs.h
new file mode 100644
index 000000000000..3f6b93099011
--- /dev/null
+++ b/arch/arm64/include/asm/elf_relocs.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_ELF_RELOCS_H
+#define __ASM_ELF_RELOCS_H
+
+/*
+ * AArch64 static relocation types.
+ */
+
+/* Miscellaneous. */
+#define R_ARM_NONE			0
+#define R_AARCH64_NONE			256
+
+/* Data. */
+#define R_AARCH64_ABS64			257
+#define R_AARCH64_ABS32			258
+#define R_AARCH64_ABS16			259
+#define R_AARCH64_PREL64		260
+#define R_AARCH64_PREL32		261
+#define R_AARCH64_PREL16		262
+
+/* Instructions. */
+#define R_AARCH64_MOVW_UABS_G0		263
+#define R_AARCH64_MOVW_UABS_G0_NC	264
+#define R_AARCH64_MOVW_UABS_G1		265
+#define R_AARCH64_MOVW_UABS_G1_NC	266
+#define R_AARCH64_MOVW_UABS_G2		267
+#define R_AARCH64_MOVW_UABS_G2_NC	268
+#define R_AARCH64_MOVW_UABS_G3		269
+
+#define R_AARCH64_MOVW_SABS_G0		270
+#define R_AARCH64_MOVW_SABS_G1		271
+#define R_AARCH64_MOVW_SABS_G2		272
+
+#define R_AARCH64_LD_PREL_LO19		273
+#define R_AARCH64_ADR_PREL_LO21		274
+#define R_AARCH64_ADR_PREL_PG_HI21	275
+#define R_AARCH64_ADR_PREL_PG_HI21_NC	276
+#define R_AARCH64_ADD_ABS_LO12_NC	277
+#define R_AARCH64_LDST8_ABS_LO12_NC	278
+
+#define R_AARCH64_TSTBR14		279
+#define R_AARCH64_CONDBR19		280
+#define R_AARCH64_JUMP26		282
+#define R_AARCH64_CALL26		283
+#define R_AARCH64_LDST16_ABS_LO12_NC	284
+#define R_AARCH64_LDST32_ABS_LO12_NC	285
+#define R_AARCH64_LDST64_ABS_LO12_NC	286
+#define R_AARCH64_LDST128_ABS_LO12_NC	299
+
+#define R_AARCH64_MOVW_PREL_G0		287
+#define R_AARCH64_MOVW_PREL_G0_NC	288
+#define R_AARCH64_MOVW_PREL_G1		289
+#define R_AARCH64_MOVW_PREL_G1_NC	290
+#define R_AARCH64_MOVW_PREL_G2		291
+#define R_AARCH64_MOVW_PREL_G2_NC	292
+#define R_AARCH64_MOVW_PREL_G3		293
+
+#endif /* __ASM_ELF_RELOCS_H */
+
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1306200 — [PATCH v3 09/21] extable: add support for relative extables to search and sort routines

FromArd Biesheuvel <ard.biesheuvel@linaro.org>
Date2016-01-11 14:30 +0100
Subject[PATCH v3 09/21] extable: add support for relative extables to search and sort routines
Message-ID<qPKHN-2Wj-41@gated-at.bofh.it>
In reply to#1306179
This adds support to the generic search_extable() and sort_extable()
implementations for dealing with exception table entries whose fields
contain relative offsets rather than absolute addresses.

Acked-by: Helge Deller <deller@gmx.de>
Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Acked-by: H. Peter Anvin <hpa@linux.intel.com>
Acked-by: Tony Luck <tony.luck@intel.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 lib/extable.c | 50 ++++++++++++++++----
 1 file changed, 41 insertions(+), 9 deletions(-)

diff --git a/lib/extable.c b/lib/extable.c
index 4cac81ec225e..0be02ad561e9 100644
--- a/lib/extable.c
+++ b/lib/extable.c
@@ -14,7 +14,37 @@
 #include <linux/sort.h>
 #include <asm/uaccess.h>
 
+#ifndef ARCH_HAS_RELATIVE_EXTABLE
+#define ex_to_insn(x)	((x)->insn)
+#else
+static inline unsigned long ex_to_insn(const struct exception_table_entry *x)
+{
+	return (unsigned long)&x->insn + x->insn;
+}
+#endif
+
 #ifndef ARCH_HAS_SORT_EXTABLE
+#ifndef ARCH_HAS_RELATIVE_EXTABLE
+#define swap_ex		NULL
+#else
+static void swap_ex(void *a, void *b, int size)
+{
+	struct exception_table_entry *x = a, *y = b, tmp;
+	int delta = b - a;
+
+	tmp = *x;
+	x->insn = y->insn + delta;
+	y->insn = tmp.insn - delta;
+
+#ifdef swap_ex_entry_fixup
+	swap_ex_entry_fixup(x, y, tmp, delta);
+#else
+	x->fixup = y->fixup + delta;
+	y->fixup = tmp.fixup - delta;
+#endif
+}
+#endif /* ARCH_HAS_RELATIVE_EXTABLE */
+
 /*
  * The exception table needs to be sorted so that the binary
  * search that we use to find entries in it works properly.
@@ -26,9 +56,9 @@ static int cmp_ex(const void *a, const void *b)
 	const struct exception_table_entry *x = a, *y = b;
 
 	/* avoid overflow */
-	if (x->insn > y->insn)
+	if (ex_to_insn(x) > ex_to_insn(y))
 		return 1;
-	if (x->insn < y->insn)
+	if (ex_to_insn(x) < ex_to_insn(y))
 		return -1;
 	return 0;
 }
@@ -37,7 +67,7 @@ void sort_extable(struct exception_table_entry *start,
 		  struct exception_table_entry *finish)
 {
 	sort(start, finish - start, sizeof(struct exception_table_entry),
-	     cmp_ex, NULL);
+	     cmp_ex, swap_ex);
 }
 
 #ifdef CONFIG_MODULES
@@ -48,13 +78,15 @@ void sort_extable(struct exception_table_entry *start,
 void trim_init_extable(struct module *m)
 {
 	/*trim the beginning*/
-	while (m->num_exentries && within_module_init(m->extable[0].insn, m)) {
+	while (m->num_exentries &&
+	       within_module_init(ex_to_insn(&m->extable[0]), m)) {
 		m->extable++;
 		m->num_exentries--;
 	}
 	/*trim the end*/
 	while (m->num_exentries &&
-		within_module_init(m->extable[m->num_exentries-1].insn, m))
+	       within_module_init(ex_to_insn(&m->extable[m->num_exentries - 1]),
+				  m))
 		m->num_exentries--;
 }
 #endif /* CONFIG_MODULES */
@@ -81,13 +113,13 @@ search_extable(const struct exception_table_entry *first,
 		 * careful, the distance between value and insn
 		 * can be larger than MAX_LONG:
 		 */
-		if (mid->insn < value)
+		if (ex_to_insn(mid) < value)
 			first = mid + 1;
-		else if (mid->insn > value)
+		else if (ex_to_insn(mid) > value)
 			last = mid - 1;
 		else
 			return mid;
-        }
-        return NULL;
+	}
+	return NULL;
 }
 #endif
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1306201 — [PATCH v3 10/21] arm64: switch to relative exception tables

FromArd Biesheuvel <ard.biesheuvel@linaro.org>
Date2016-01-11 14:30 +0100
Subject[PATCH v3 10/21] arm64: switch to relative exception tables
Message-ID<qPKHN-2Wj-43@gated-at.bofh.it>
In reply to#1306179
Instead of using absolute addresses for both the exception location
and the fixup, use offsets relative to the exception table entry values.
Not only does this cut the size of the exception table in half, it is
also a prerequisite for KASLR, since absolute exception table entries
are subject to dynamic relocation, which is incompatible with the sorting
of the exception table that occurs at build time.

This patch also introduces the _ASM_EXTABLE preprocessor macro (which
exists on x86 as well) and its _asm_extable assembly counterpart, as
shorthands to emit exception table entries.

Acked-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 arch/arm64/include/asm/assembler.h      | 15 +++++++---
 arch/arm64/include/asm/futex.h          | 12 +++-----
 arch/arm64/include/asm/uaccess.h        | 30 +++++++++++---------
 arch/arm64/include/asm/word-at-a-time.h |  7 ++---
 arch/arm64/kernel/armv8_deprecated.c    |  7 ++---
 arch/arm64/mm/extable.c                 |  2 +-
 scripts/sortextable.c                   |  2 +-
 7 files changed, 38 insertions(+), 37 deletions(-)

diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index bb7b72734c24..d8bfcc1ce923 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -94,12 +94,19 @@
 	dmb	\opt
 	.endm
 
+/*
+ * Emit an entry into the exception table
+ */
+	.macro		_asm_extable, from, to
+	.pushsection	__ex_table, "a"
+	.align		3
+	.long		(\from - .), (\to - .)
+	.popsection
+	.endm
+
 #define USER(l, x...)				\
 9999:	x;					\
-	.section __ex_table,"a";		\
-	.align	3;				\
-	.quad	9999b,l;			\
-	.previous
+	_asm_extable	9999b, l
 
 /*
  * Register aliases.
diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h
index 007a69fc4f40..1ab15a3b5a0e 100644
--- a/arch/arm64/include/asm/futex.h
+++ b/arch/arm64/include/asm/futex.h
@@ -42,10 +42,8 @@
 "4:	mov	%w0, %w5\n"						\
 "	b	3b\n"							\
 "	.popsection\n"							\
-"	.pushsection __ex_table,\"a\"\n"				\
-"	.align	3\n"							\
-"	.quad	1b, 4b, 2b, 4b\n"					\
-"	.popsection\n"							\
+	_ASM_EXTABLE(1b, 4b)						\
+	_ASM_EXTABLE(2b, 4b)						\
 	ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN,		\
 		    CONFIG_ARM64_PAN)					\
 	: "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp)	\
@@ -133,10 +131,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
 "4:	mov	%w0, %w6\n"
 "	b	3b\n"
 "	.popsection\n"
-"	.pushsection __ex_table,\"a\"\n"
-"	.align	3\n"
-"	.quad	1b, 4b, 2b, 4b\n"
-"	.popsection\n"
+	_ASM_EXTABLE(1b, 4b)
+	_ASM_EXTABLE(2b, 4b)
 	: "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp)
 	: "r" (oldval), "r" (newval), "Ir" (-EFAULT)
 	: "memory");
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index b2ede967fe7d..dc11577fab7e 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -36,11 +36,11 @@
 #define VERIFY_WRITE 1
 
 /*
- * The exception table consists of pairs of addresses: the first is the
- * address of an instruction that is allowed to fault, and the second is
- * the address at which the program should continue.  No registers are
- * modified, so it is entirely up to the continuation code to figure out
- * what to do.
+ * The exception table consists of pairs of relative offsets: the first
+ * is the relative offset to an instruction that is allowed to fault,
+ * and the second is the relative offset at which the program should
+ * continue. No registers are modified, so it is entirely up to the
+ * continuation code to figure out what to do.
  *
  * All the routines below use bits of fixup code that are out of line
  * with the main instruction path.  This means when everything is well,
@@ -50,9 +50,11 @@
 
 struct exception_table_entry
 {
-	unsigned long insn, fixup;
+	int insn, fixup;
 };
 
+#define ARCH_HAS_RELATIVE_EXTABLE
+
 extern int fixup_exception(struct pt_regs *regs);
 
 #define KERNEL_DS	(-1UL)
@@ -105,6 +107,12 @@ static inline void set_fs(mm_segment_t fs)
 #define access_ok(type, addr, size)	__range_ok(addr, size)
 #define user_addr_max			get_fs
 
+#define _ASM_EXTABLE(from, to)						\
+	"	.pushsection	__ex_table, \"a\"\n"			\
+	"	.align		3\n"					\
+	"	.long		(" #from " - .), (" #to " - .)\n"	\
+	"	.popsection\n"
+
 /*
  * The "__xxx" versions of the user access functions do not verify the address
  * space - it must have been done previously with a separate "access_ok()"
@@ -123,10 +131,7 @@ static inline void set_fs(mm_segment_t fs)
 	"	mov	%1, #0\n"					\
 	"	b	2b\n"						\
 	"	.previous\n"						\
-	"	.section __ex_table,\"a\"\n"				\
-	"	.align	3\n"						\
-	"	.quad	1b, 3b\n"					\
-	"	.previous"						\
+	_ASM_EXTABLE(1b, 3b)						\
 	: "+r" (err), "=&r" (x)						\
 	: "r" (addr), "i" (-EFAULT))
 
@@ -190,10 +195,7 @@ do {									\
 	"3:	mov	%w0, %3\n"					\
 	"	b	2b\n"						\
 	"	.previous\n"						\
-	"	.section __ex_table,\"a\"\n"				\
-	"	.align	3\n"						\
-	"	.quad	1b, 3b\n"					\
-	"	.previous"						\
+	_ASM_EXTABLE(1b, 3b)						\
 	: "+r" (err)							\
 	: "r" (x), "r" (addr), "i" (-EFAULT))
 
diff --git a/arch/arm64/include/asm/word-at-a-time.h b/arch/arm64/include/asm/word-at-a-time.h
index aab5bf09e9d9..2b79b8a89457 100644
--- a/arch/arm64/include/asm/word-at-a-time.h
+++ b/arch/arm64/include/asm/word-at-a-time.h
@@ -16,6 +16,8 @@
 #ifndef __ASM_WORD_AT_A_TIME_H
 #define __ASM_WORD_AT_A_TIME_H
 
+#include <asm/uaccess.h>
+
 #ifndef __AARCH64EB__
 
 #include <linux/kernel.h>
@@ -81,10 +83,7 @@ static inline unsigned long load_unaligned_zeropad(const void *addr)
 #endif
 	"	b	2b\n"
 	"	.popsection\n"
-	"	.pushsection __ex_table,\"a\"\n"
-	"	.align	3\n"
-	"	.quad	1b, 3b\n"
-	"	.popsection"
+	_ASM_EXTABLE(1b, 3b)
 	: "=&r" (ret), "=&r" (offset)
 	: "r" (addr), "Q" (*(unsigned long *)addr));
 
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index 3e01207917b1..c37202c0c838 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -297,11 +297,8 @@ static void __init register_insn_emulation_sysctl(struct ctl_table *table)
 	"4:	mov		%w0, %w5\n"			\
 	"	b		3b\n"				\
 	"	.popsection"					\
-	"	.pushsection	 __ex_table,\"a\"\n"		\
-	"	.align		3\n"				\
-	"	.quad		0b, 4b\n"			\
-	"	.quad		1b, 4b\n"			\
-	"	.popsection\n"					\
+	_ASM_EXTABLE(0b, 4b)					\
+	_ASM_EXTABLE(1b, 4b)					\
 	ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN,	\
 		CONFIG_ARM64_PAN)				\
 	: "=&r" (res), "+r" (data), "=&r" (temp)		\
diff --git a/arch/arm64/mm/extable.c b/arch/arm64/mm/extable.c
index 79444279ba8c..81acd4706878 100644
--- a/arch/arm64/mm/extable.c
+++ b/arch/arm64/mm/extable.c
@@ -11,7 +11,7 @@ int fixup_exception(struct pt_regs *regs)
 
 	fixup = search_exception_tables(instruction_pointer(regs));
 	if (fixup)
-		regs->pc = fixup->fixup;
+		regs->pc = (unsigned long)&fixup->fixup + fixup->fixup;
 
 	return fixup != NULL;
 }
diff --git a/scripts/sortextable.c b/scripts/sortextable.c
index c2423d913b46..af247c70fb66 100644
--- a/scripts/sortextable.c
+++ b/scripts/sortextable.c
@@ -282,12 +282,12 @@ do_file(char const *const fname)
 	case EM_386:
 	case EM_X86_64:
 	case EM_S390:
+	case EM_AARCH64:
 		custom_sort = sort_relative_table;
 		break;
 	case EM_ARCOMPACT:
 	case EM_ARCV2:
 	case EM_ARM:
-	case EM_AARCH64:
 	case EM_MICROBLAZE:
 	case EM_MIPS:
 	case EM_XTENSA:
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1306202 — [PATCH v3 19/21] efi: stub: add implementation of efi_random_alloc()

FromArd Biesheuvel <ard.biesheuvel@linaro.org>
Date2016-01-11 14:30 +0100
Subject[PATCH v3 19/21] efi: stub: add implementation of efi_random_alloc()
Message-ID<qPKHN-2Wj-47@gated-at.bofh.it>
In reply to#1306179
This implements efi_random_alloc(), which allocates a chunk of memory of
a certain size at a certain alignment, and uses the random_seed argument
it receives to randomize the offset of the allocation.

This is implemented by iterating over the UEFI memory map, counting the
number of suitable slots (aligned offsets) within each region, and picking
a random number between 0 and 'number of slots - 1' to select the slot,
This should guarantee that each possible offset is chosen equally likely.

Suggested-by: Kees Cook <keescook@chromium.org>
Cc: Matt Fleming <matt@codeblueprint.co.uk>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 drivers/firmware/efi/libstub/efistub.h |  4 +
 drivers/firmware/efi/libstub/random.c  | 85 ++++++++++++++++++++
 2 files changed, 89 insertions(+)

diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 206b7252b9d1..7a38e29da53d 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -46,4 +46,8 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
 efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table,
 				  unsigned long size, u8 *out);
 
+efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg,
+			      unsigned long size, unsigned long align_bits,
+			      unsigned long *addr, unsigned long random_seed);
+
 #endif
diff --git a/drivers/firmware/efi/libstub/random.c b/drivers/firmware/efi/libstub/random.c
index f539b1e31459..d4829824508c 100644
--- a/drivers/firmware/efi/libstub/random.c
+++ b/drivers/firmware/efi/libstub/random.c
@@ -33,3 +33,88 @@ efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table,
 
 	return rng->get_rng(rng, NULL, size, out);
 }
+
+/*
+ * Return a weight for a memory entry depending on how many offsets it covers
+ * that are suitably aligned and supply enough room for the allocation.
+ */
+static unsigned long get_entry_weight(efi_memory_desc_t *md, unsigned long size,
+				      unsigned long align_bits)
+{
+	u64 start, end;
+
+	if (md->type != EFI_CONVENTIONAL_MEMORY)
+		return 0;
+
+	if (!(md->attribute & EFI_MEMORY_WB))
+		return 0;
+
+	start = round_up(md->phys_addr, 1 << align_bits);
+	end = round_down(md->phys_addr + md->num_pages * EFI_PAGE_SIZE - size,
+			 1 << align_bits);
+
+	if (start >= end)
+		return 0;
+
+	return (end - start) >> align_bits;
+}
+
+/*
+ * The UEFI memory descriptors have a virtual address field that is only used
+ * when installing the virtual mapping using SetVirtualAddressMap(). Since it
+ * is unused here, we can reuse it to keep track of each descriptor's weight.
+ */
+#define MD_WEIGHT(md)	((md)->virt_addr)
+
+efi_status_t efi_random_alloc(efi_system_table_t *sys_table_arg,
+			      unsigned long size, unsigned long align_bits,
+			      unsigned long *addr, unsigned long random_seed)
+{
+	unsigned long map_size, desc_size, max_weight = 0, target;
+	efi_memory_desc_t *memory_map;
+	efi_status_t status = EFI_NOT_FOUND;
+	int l;
+
+	status = efi_get_memory_map(sys_table_arg, &memory_map, &map_size,
+				    &desc_size, NULL, NULL);
+	if (status != EFI_SUCCESS)
+		return status;
+
+	/* assign each entry in the memory map a weight */
+	for (l = 0; l < map_size; l += desc_size) {
+		efi_memory_desc_t *md = (void *)memory_map + l;
+		unsigned long weight;
+
+		weight = get_entry_weight(md, size, align_bits);
+		MD_WEIGHT(md) = weight;
+		max_weight += weight;
+	}
+
+	/* find a random number between 0 and max_weight */
+	target = (max_weight * (u16)random_seed) >> 16;
+
+	/* find the entry whose accumulated weight covers the target */
+	for (l = 0; l < map_size; l += desc_size) {
+		efi_memory_desc_t *md = (void *)memory_map + l;
+
+		if (target < MD_WEIGHT(md)) {
+			unsigned long pages;
+
+			*addr = round_up(md->phys_addr, 1 << align_bits) +
+				(target << align_bits);
+			pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+
+			status = efi_call_early(allocate_pages,
+						EFI_ALLOCATE_ADDRESS,
+						EFI_LOADER_DATA,
+						pages,
+						(efi_physical_addr_t *)addr);
+			break;
+		}
+		target -= MD_WEIGHT(md);
+	}
+
+	efi_call_early(free_pool, memory_map);
+
+	return status;
+}
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1306204 — [PATCH v3 18/21] efi: stub: implement efi_get_random_bytes() based on EFI_RNG_PROTOCOL

FromArd Biesheuvel <ard.biesheuvel@linaro.org>
Date2016-01-11 14:30 +0100
Subject[PATCH v3 18/21] efi: stub: implement efi_get_random_bytes() based on EFI_RNG_PROTOCOL
Message-ID<qPKHN-2Wj-49@gated-at.bofh.it>
In reply to#1306179
This exposes the firmware's implementation of EFI_RNG_PROTOCOL via a new
function efi_get_random_bytes().

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 drivers/firmware/efi/libstub/Makefile  |  2 +-
 drivers/firmware/efi/libstub/efistub.h |  3 ++
 drivers/firmware/efi/libstub/random.c  | 35 ++++++++++++++++++++
 include/linux/efi.h                    |  5 ++-
 4 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index c0ddd1b8dca3..9f0c813d739c 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -23,7 +23,7 @@ KBUILD_CFLAGS			:= $(cflags-y) -DDISABLE_BRANCH_PROFILING \
 GCOV_PROFILE			:= n
 KASAN_SANITIZE			:= n
 
-lib-y				:= efi-stub-helper.o
+lib-y				:= efi-stub-helper.o random.o
 
 # include the stub's generic dependencies from lib/ when building for ARM/arm64
 arm-deps := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c sort.c
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 6b6548fda089..206b7252b9d1 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -43,4 +43,7 @@ void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
 		     unsigned long desc_size, efi_memory_desc_t *runtime_map,
 		     int *count);
 
+efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table,
+				  unsigned long size, u8 *out);
+
 #endif
diff --git a/drivers/firmware/efi/libstub/random.c b/drivers/firmware/efi/libstub/random.c
new file mode 100644
index 000000000000..f539b1e31459
--- /dev/null
+++ b/drivers/firmware/efi/libstub/random.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 Linaro Ltd;  <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/efi.h>
+#include <asm/efi.h>
+
+#include "efistub.h"
+
+struct efi_rng_protocol_t {
+	efi_status_t (*get_info)(struct efi_rng_protocol_t *,
+				 unsigned long *, efi_guid_t *);
+	efi_status_t (*get_rng)(struct efi_rng_protocol_t *,
+				efi_guid_t *, unsigned long, u8 *out);
+};
+
+efi_status_t efi_get_random_bytes(efi_system_table_t *sys_table,
+				  unsigned long size, u8 *out)
+{
+	efi_guid_t rng_proto = EFI_RNG_PROTOCOL_GUID;
+	efi_status_t status;
+	struct efi_rng_protocol_t *rng;
+
+	status = sys_table->boottime->locate_protocol(&rng_proto, NULL,
+						      (void **)&rng);
+	if (status != EFI_SUCCESS)
+		return status;
+
+	return rng->get_rng(rng, NULL, size, out);
+}
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 569b5a866bb1..13783fdc9bdd 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -299,7 +299,7 @@ typedef struct {
 	void *open_protocol_information;
 	void *protocols_per_handle;
 	void *locate_handle_buffer;
-	void *locate_protocol;
+	efi_status_t (*locate_protocol)(efi_guid_t *, void *, void **);
 	void *install_multiple_protocol_interfaces;
 	void *uninstall_multiple_protocol_interfaces;
 	void *calculate_crc32;
@@ -599,6 +599,9 @@ void efi_native_runtime_setup(void);
 #define EFI_PROPERTIES_TABLE_GUID \
     EFI_GUID(  0x880aaca3, 0x4adc, 0x4a04, 0x90, 0x79, 0xb7, 0x47, 0x34, 0x08, 0x25, 0xe5 )
 
+#define EFI_RNG_PROTOCOL_GUID \
+    EFI_GUID(  0x3152bca5, 0xeade, 0x433d, 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 )
+
 typedef struct {
 	efi_guid_t guid;
 	u64 table;
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1306206 — [PATCH v3 20/21] efi: stub: use high allocation for converted command line

FromArd Biesheuvel <ard.biesheuvel@linaro.org>
Date2016-01-11 14:30 +0100
Subject[PATCH v3 20/21] efi: stub: use high allocation for converted command line
Message-ID<qPKHO-2Wj-55@gated-at.bofh.it>
In reply to#1306179
Before we can move the command line processing before the allocation
of the kernel, which is required for detecting the 'nokaslr' option
which controls that allocation, move the converted command line higher
up in memory, to prevent it from interfering with the kernel itself.

Since x86 needs the address to fit in 32 bits, use UINT_MAX as the upper
bound there. Otherwise, use ULONG_MAX (i.e., no limit)

Cc: Matt Fleming <matt@codeblueprint.co.uk>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 arch/x86/include/asm/efi.h                     |  2 ++
 drivers/firmware/efi/libstub/efi-stub-helper.c | 14 +++++++++++++-
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 0010c78c4998..08b1f2f6ea50 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -25,6 +25,8 @@
 #define EFI32_LOADER_SIGNATURE	"EL32"
 #define EFI64_LOADER_SIGNATURE	"EL64"
 
+#define MAX_CMDLINE_ADDRESS	UINT_MAX
+
 #ifdef CONFIG_X86_32
 
 
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index f07d4a67fa76..2a7a3015d7e0 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -649,6 +649,10 @@ static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n)
 	return dst;
 }
 
+#ifndef MAX_CMDLINE_ADDRESS
+#define MAX_CMDLINE_ADDRESS	ULONG_MAX
+#endif
+
 /*
  * Convert the unicode UEFI command line to ASCII to pass to kernel.
  * Size of memory allocated return in *cmd_line_len.
@@ -684,7 +688,15 @@ char *efi_convert_cmdline(efi_system_table_t *sys_table_arg,
 
 	options_bytes++;	/* NUL termination */
 
-	status = efi_low_alloc(sys_table_arg, options_bytes, 0, &cmdline_addr);
+	/*
+	 * Allocate a buffer for the converted command line as high up
+	 * in memory as is feasible: x86 needs the command line allocation
+	 * to be below 4 GB, but non-x86 architectures may not have any
+	 * memory there. So prefer below 4 GB, and allocate anywhere if
+	 * that fails.
+	 */
+	status = efi_high_alloc(sys_table_arg, options_bytes, 0,
+				&cmdline_addr, MAX_CMDLINE_ADDRESS);
 	if (status != EFI_SUCCESS)
 		return NULL;
 
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1306207 — [PATCH v3 21/21] arm64: efi: invoke EFI_RNG_PROTOCOL to supply KASLR randomness

FromArd Biesheuvel <ard.biesheuvel@linaro.org>
Date2016-01-11 14:30 +0100
Subject[PATCH v3 21/21] arm64: efi: invoke EFI_RNG_PROTOCOL to supply KASLR randomness
Message-ID<qPKHO-2Wj-57@gated-at.bofh.it>
In reply to#1306179
Since arm64 does not use a decompressor that supplies an execution
environment where it is feasible to some extent to provide a source of
randomness, the arm64 KASLR kernel depends on the bootloader to supply
some random bits in register x1 upon kernel entry.

On UEFI systems, we can use the EFI_RNG_PROTOCOL, if supplied, to obtain
some random bits. At the same time, use it to randomize the offset of the
kernel Image in physical memory.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 arch/arm64/Kconfig                             |  5 ++
 arch/arm64/kernel/efi-entry.S                  |  7 +-
 drivers/firmware/efi/libstub/arm-stub.c        | 17 ++---
 drivers/firmware/efi/libstub/arm64-stub.c      | 67 +++++++++++++++-----
 drivers/firmware/efi/libstub/efi-stub-helper.c | 10 +++
 drivers/firmware/efi/libstub/efistub.h         |  2 +
 6 files changed, 82 insertions(+), 26 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 7fa5b74ee80d..ba347302308b 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -734,6 +734,11 @@ config RANDOMIZE_BASE
 	  It is the bootloader's job to provide entropy, by passing a
 	  random value in x1 at kernel entry.
 
+	  When booting via the UEFI stub, it will invoke the firmware's
+	  EFI_RNG_PROTOCOL implementation (if available) to supply entropy
+	  to the kernel proper. In addition, it will randomise the physical
+	  location of the kernel Image as well.
+
 	  If unsure, say N.
 
 
diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S
index f82036e02485..f41073dde7e0 100644
--- a/arch/arm64/kernel/efi-entry.S
+++ b/arch/arm64/kernel/efi-entry.S
@@ -110,7 +110,7 @@ ENTRY(entry)
 2:
 	/* Jump to kernel entry point */
 	mov	x0, x20
-	mov	x1, xzr
+	ldr	x1, efi_rnd
 	mov	x2, xzr
 	mov	x3, xzr
 	br	x21
@@ -119,6 +119,9 @@ efi_load_fail:
 	mov	x0, #EFI_LOAD_ERROR
 	ldp	x29, x30, [sp], #32
 	ret
+ENDPROC(entry)
+
+ENTRY(efi_rnd)
+	.quad	0, 0
 
 entry_end:
-ENDPROC(entry)
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c
index 950c87f5d279..c39e04a1e8aa 100644
--- a/drivers/firmware/efi/libstub/arm-stub.c
+++ b/drivers/firmware/efi/libstub/arm-stub.c
@@ -207,14 +207,6 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
 		pr_efi_err(sys_table, "Failed to find DRAM base\n");
 		goto fail;
 	}
-	status = handle_kernel_image(sys_table, image_addr, &image_size,
-				     &reserve_addr,
-				     &reserve_size,
-				     dram_base, image);
-	if (status != EFI_SUCCESS) {
-		pr_efi_err(sys_table, "Failed to relocate kernel\n");
-		goto fail;
-	}
 
 	/*
 	 * Get the command line from EFI, using the LOADED_IMAGE
@@ -231,6 +223,15 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table,
 	if (status != EFI_SUCCESS)
 		pr_efi_err(sys_table, "Failed to parse EFI cmdline options\n");
 
+	status = handle_kernel_image(sys_table, image_addr, &image_size,
+				     &reserve_addr,
+				     &reserve_size,
+				     dram_base, image);
+	if (status != EFI_SUCCESS) {
+		pr_efi_err(sys_table, "Failed to relocate kernel\n");
+		goto fail;
+	}
+
 	/*
 	 * Unauthenticated device tree data is a security hazard, so
 	 * ignore 'dtb=' unless UEFI Secure Boot is disabled.
diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c
index 78dfbd34b6bf..96d43bed098f 100644
--- a/drivers/firmware/efi/libstub/arm64-stub.c
+++ b/drivers/firmware/efi/libstub/arm64-stub.c
@@ -13,6 +13,13 @@
 #include <asm/efi.h>
 #include <asm/sections.h>
 
+#include "efistub.h"
+
+extern struct {
+	u64	virt_seed;
+	u64	phys_seed;
+} efi_rnd;
+
 efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg,
 					unsigned long *image_addr,
 					unsigned long *image_size,
@@ -27,6 +34,22 @@ efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg,
 	void *old_image_addr = (void *)*image_addr;
 	unsigned long preferred_offset;
 
+	if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
+		if (!__nokaslr) {
+			status = efi_get_random_bytes(sys_table_arg,
+						      sizeof(efi_rnd),
+						      (u8 *)&efi_rnd);
+			if (status == EFI_NOT_FOUND) {
+				pr_efi(sys_table_arg, "EFI_RNG_PROTOCOL unavailable, no randomness supplied\n");
+			} else if (status != EFI_SUCCESS) {
+				pr_efi_err(sys_table_arg, "efi_get_random_bytes() failed\n");
+				return status;
+			}
+		} else {
+			pr_efi(sys_table_arg, "KASLR disabled on kernel command line\n");
+		}
+	}
+
 	/*
 	 * The preferred offset of the kernel Image is TEXT_OFFSET bytes beyond
 	 * a 2 MB aligned base, which itself may be lower than dram_base, as
@@ -36,13 +59,22 @@ efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg,
 	if (preferred_offset < dram_base)
 		preferred_offset += SZ_2M;
 
-	/* Relocate the image, if required. */
 	kernel_size = _edata - _text;
-	if (*image_addr != preferred_offset) {
-		kernel_memsize = kernel_size + (_end - _edata);
+	kernel_memsize = kernel_size + (_end - _edata);
+
+	if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && efi_rnd.phys_seed != 0) {
+		/*
+		 * If KASLR is enabled, and we have some randomness available,
+		 * locate the kernel at a randomized offset in physical memory.
+		 */
+		status = efi_random_alloc(sys_table_arg, kernel_size,
+					  ilog2(MIN_KIMG_ALIGN), reserve_addr,
+					  efi_rnd.phys_seed);
 
+		*image_addr = *reserve_addr + TEXT_OFFSET;
+	} else {
 		/*
-		 * First, try a straight allocation at the preferred offset.
+		 * Else, try a straight allocation at the preferred offset.
 		 * This will work around the issue where, if dram_base == 0x0,
 		 * efi_low_alloc() refuses to allocate at 0x0 (to prevent the
 		 * address of the allocation to be mistaken for a FAIL return
@@ -52,27 +84,30 @@ efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg,
 		 * Mustang), we can still place the kernel at the address
 		 * 'dram_base + TEXT_OFFSET'.
 		 */
+		if (*image_addr == preferred_offset)
+			return EFI_SUCCESS;
+
 		*image_addr = *reserve_addr = preferred_offset;
 		nr_pages = round_up(kernel_memsize, EFI_ALLOC_ALIGN) /
 			   EFI_PAGE_SIZE;
 		status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS,
 					EFI_LOADER_DATA, nr_pages,
 					(efi_physical_addr_t *)reserve_addr);
-		if (status != EFI_SUCCESS) {
-			kernel_memsize += TEXT_OFFSET;
-			status = efi_low_alloc(sys_table_arg, kernel_memsize,
-					       SZ_2M, reserve_addr);
+	}
 
-			if (status != EFI_SUCCESS) {
-				pr_efi_err(sys_table_arg, "Failed to relocate kernel\n");
-				return status;
-			}
-			*image_addr = *reserve_addr + TEXT_OFFSET;
+	if (status != EFI_SUCCESS) {
+		kernel_memsize += TEXT_OFFSET;
+		status = efi_low_alloc(sys_table_arg, kernel_memsize,
+				       SZ_2M, reserve_addr);
+
+		if (status != EFI_SUCCESS) {
+			pr_efi_err(sys_table_arg, "Failed to relocate kernel\n");
+			return status;
 		}
-		memcpy((void *)*image_addr, old_image_addr, kernel_size);
-		*reserve_size = kernel_memsize;
+		*image_addr = *reserve_addr + TEXT_OFFSET;
 	}
-
+	memcpy((void *)*image_addr, old_image_addr, kernel_size);
+	*reserve_size = kernel_memsize;
 
 	return EFI_SUCCESS;
 }
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index 2a7a3015d7e0..e8a3b8cd53cc 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -32,6 +32,10 @@
 
 static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE;
 
+#ifdef CONFIG_RANDOMIZE_BASE
+bool __nokaslr;
+#endif
+
 /*
  * Allow the platform to override the allocation granularity: this allows
  * systems that have the capability to run with a larger page size to deal
@@ -317,6 +321,12 @@ efi_status_t efi_parse_options(char *cmdline)
 {
 	char *str;
 
+#ifdef CONFIG_RANDOMIZE_BASE
+	str = strstr(cmdline, "nokaslr");
+	if (str && (str == cmdline || *(str - 1) == ' '))
+		__nokaslr = true;
+#endif
+
 	/*
 	 * If no EFI parameters were specified on the cmdline we've got
 	 * nothing to do.
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 7a38e29da53d..250ed4737298 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -5,6 +5,8 @@
 /* error code which can't be mistaken for valid address */
 #define EFI_ERROR	(~0UL)
 
+extern bool __nokaslr;
+
 void efi_char16_printk(efi_system_table_t *, efi_char16_t *);
 
 efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image,
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1306759

FromKees Cook <keescook@chromium.org>
Date2016-01-11 23:10 +0100
Message-ID<qPSP1-7w-37@gated-at.bofh.it>
In reply to#1306179
On Mon, Jan 11, 2016 at 5:18 AM, Ard Biesheuvel
<ard.biesheuvel@linaro.org> wrote:
> This series implements KASLR for arm64, by building the kernel as a PIE
> executable that can relocate itself at runtime, and moving it to a random
> offset in the vmalloc area. v2 and up also implement physical randomization,
> i.e., it allows the kernel to deal with being loaded at any physical offset
> (modulo the required alignment), and invokes the EFI_RNG_PROTOCOL from the
> UEFI stub to obtain random bits and perform the actual randomization of the
> physical load address.

I will continue cheering! :)

> Changes since v2:
> - Incorporated feedback from Marc Zyngier into the KVM patch (#5)
> - Dropped the pgdir section and the patch that memblock_reserve()'s the kernel
>   sections at a smaller granularity. This is no longer necessary with the pgdir
>   section gone. This also fixes an issue spotted by James Morse where the fixmap
>   page tables are not zeroed correctly; these have been moved back to the .bss
>   section.
> - Got rid of all ifdef'ery regarding the number of translation levels in the
>   changed .c files, by introducing new definitions in pgtable.h (#3, #6)
> - Fixed KAsan support, which was broken by all earlier versions.
> - Moved module region along with the virtually randomized kernel, so that module
>   addresses become unpredictable as well, and we only have to rely on veneers in
>   the PLTs when the module region is exhausted (which is somewhat more likely
>   since the module region is now shared with other uses of the vmalloc area)

Just to make sure I understand: this means that the offset between
kernel and modules remains static? It may still be useful to bump
modules as well, just so that leaking a module address doesn't
compromise the base kernel image address too. Don't block the series
for this, though. It's a minor nit. :)

-Kees

> - Added support for the 'nokaslr' command line option. This affects the
>   randomization performed by the stub, and results in a warning if passed while
>   the bootloader also presented a random seed for virtual KASLR in register x1.
> - The .text/.rodata sections of the kernel are no longer aliased in the linear
>   region with a writable mapping.
> - Added a separate image header flag for kernel images that may be loaded at any
>   2 MB aligned offset (+ TEXT_OFFSET)
> - The KASLR displacement is now corrected if it results in the kernel image
>   intersecting a PUD/PMD boundary (4k and 16k/64k granule kernels, respectively)
> - Split out UEFI stub random routines into separate patches.
> - Implemented a weight based EFI random allocation routine so that each suitable
>   offset in available memory is equally likely to be selected (as suggested by
>   Kees Cook)
> - Reused CONFIG_RELOCATABLE and CONFIG_RANDOMIZE_BASE instead of introducing
>   new Kconfig symbols to describe the same functionality.
> - Reimplemented mem= logic so memory is clipped from the top first.
>
> Changes since v1/RFC:
> - This series now implements fully independent virtual and physical address
>   randomization at load time. I have recycled some patches from this series:
>   http://thread.gmane.org/gmane.linux.ports.arm.kernel/455151, and updated the
>   final UEFI stub patch to randomize the physical address as well.
> - Added a patch to deal with the way KVM on arm64 makes assumptions about the
>   relation between kernel symbols and the linear mapping (on which the HYP
>   mapping is based), as these assumptions cease to be valid once we move the
>   kernel Image out of the linear mapping.
> - Updated the module PLT patch so it works on BE kernels as well.
> - Moved the constant Image header values to head.S, and updated the linker
>   script to provide the kernel size using R_AARCH64_ABS32 relocation rather
>   than a R_AARCH64_ABS64 relocation, since those are always resolved at build
>   time. This allows me to get rid of the post-build perl script to swab header
>   values on BE kernels.
> - Minor style tweaks.
>
> Notes:
> - These patches apply on top of Mark Rutland's pagetable rework series:
>   http://thread.gmane.org/gmane.linux.ports.arm.kernel/462438
> - The arm64 Image is uncompressed by default, and the Elf64_Rela format uses
>   24 bytes per relocation entry. This results in considerable bloat (i.e., a
>   couple of MBs worth of relocation data in an .init section). However, no
>   build time postprocessing is required, we rely fully on the toolchain to
>   produce the image
> - We have to rely on the bootloader to supply some randomness in register x1
>   upon kernel entry. Since we have no decompressor, it is simply not feasible
>   to collect randomness in the head.S code path before mapping the kernel and
>   enabling the MMU.
> - The EFI_RNG_PROTOCOL that is invoked in patch #13 to supply randomness on
>   UEFI systems is not universally available. A QEMU/KVM firmware image that
>   implements a pseudo-random version is available here:
>   http://people.linaro.org/~ard.biesheuvel/QEMU_EFI.fd.aarch64-rng.bz2
>   (requires access to PMCCNTR_EL0 and support for AES instructions)
>   See below for instructions how to run the pseudo-random version on real
>   hardware.
> - Only mildly tested. Help appreciated.
>
> Code can be found here:
> git://git.linaro.org/people/ard.biesheuvel/linux-arm.git arm64-kaslr-v3
> https://git.linaro.org/people/ard.biesheuvel/linux-arm.git/shortlog/refs/heads/arm64-kaslr-v3
>
> Patch #1 updates the OF code to allow the minimum memblock physical address to
> be overridden by the arch.
>
> Patch #2 introduces KIMAGE_VADDR as the base of the kernel virtual region.
>
> Patch #3 introduces dummy pud_index() and pmd_index() macros that are intended
> to be optimized away if the configured number of translation levels does not
> actually use them.
>
> Patch #4 rewrites early_fixmap_init() so it does not rely on the linear mapping
> (i.e., the use of phys_to_virt() is avoided)
>
> Patch #5 updates KVM on arm64 so it can deal with kernel symbols whose addresses
> are not covered by the linear mapping.
>
> Patch #6 introduces pte_offset_kimg(), pmd_offset_kimg() and pud_offset_kimg()
> that allow statically allocated page tables (i.e., by fixmap and kasan) to be
> traversed before the linear mapping is installed.
>
> Patch #7 moves the kernel virtual mapping to the vmalloc area, along with the
> module region which is kept right below it, as before.
>
> Patch #8 adds support for PLTs in modules so that relative branches can be
> resolved via a PLT if the target is out of range. This is required for KASLR,
> since modules may be loaded far away from the core kernel.
>
> Patch #9 and #10 move arm64 to the a new generic relative version of the extable
> implementation so that it no longer contains absolute addresses that require
> fixing up at relocation time, but uses relative offsets instead.
>
> Patch #11 reverts some changes to the Image header population code so we no
> longer depend on the linker to populate the header fields. This is necessary
> since the R_AARCH64_ABS64 relocations that are emitted for these fields are not
> resolved at build time for PIE executables.
>
> Patch #12 updates the code in head.S that needs to execute before relocation to
> avoid the use of values that are subject to dynamic relocation. These values
> will not be populated in PIE executables.
>
> Patch #13 allows the kernel Image to be loaded anywhere in physical memory, by
> decoupling PHYS_OFFSET from the base of the kernel image.
>
> Patch #14 redefines SWAPPER_TABLE_SHIFT in a way that allows it to be used from
> assembler code regardless of the number of configured translation levels.
>
> Patch #15 (from Mark Rutland) moves the ELF relocation type #defines to a
> separate file so we can use it from head.S later
>
> Patch #16 updates scripts/sortextable.c so it accepts ET_DYN (relocatable)
> executables as well as ET_EXEC (static) executables.
>
> Patch #17 implements the core KASLR, by taking randomness supplied in register
> x1 and using it to move the kernel inside the vmalloc area.
>
> Patch #18 implements efi_get_random_bytes() based on the EFI_RNG_PROTOCOL
>
> Patch #19 implements efi_random_alloc()
>
> Patch #20 moves the allocation for the converted command line (UTF-16 to ASCII)
> away from the base of memory. This is necessary since for parsing
>
> Patch #21 implements the actual KASLR, by randomizing the kernel physical
> address, and passing entropy in x1 so that the kernel proper can relocate itself
> virtually.
>
> Ard Biesheuvel (20):
>   of/fdt: make memblock minimum physical address arch configurable
>   arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
>   arm64: pgtable: add dummy pud_index() and pmd_index() definitions
>   arm64: decouple early fixmap init from linear mapping
>   arm64: kvm: deal with kernel symbols outside of linear mapping
>   arm64: pgtable: implement static [pte|pmd|pud]_offset variants
>   arm64: move kernel image to base of vmalloc area
>   arm64: add support for module PLTs
>   extable: add support for relative extables to search and sort routines
>   arm64: switch to relative exception tables
>   arm64: avoid R_AARCH64_ABS64 relocations for Image header fields
>   arm64: avoid dynamic relocations in early boot code
>   arm64: allow kernel Image to be loaded anywhere in physical memory
>   arm64: redefine SWAPPER_TABLE_SHIFT for use in asm code
>   scripts/sortextable: add support for ET_DYN binaries
>   arm64: add support for a relocatable kernel and KASLR
>   efi: stub: implement efi_get_random_bytes() based on EFI_RNG_PROTOCOL
>   efi: stub: add implementation of efi_random_alloc()
>   efi: stub: use high allocation for converted command line
>   arm64: efi: invoke EFI_RNG_PROTOCOL to supply KASLR randomness
>
> Mark Rutland (1):
>   arm64: split elf relocs into a separate header.
>
>  Documentation/arm64/booting.txt                |  34 ++++-
>  arch/arm/include/asm/kvm_asm.h                 |   2 +
>  arch/arm/include/asm/kvm_mmu.h                 |   2 +
>  arch/arm/kvm/arm.c                             |   5 +-
>  arch/arm/kvm/mmu.c                             |   8 +-
>  arch/arm64/Kconfig                             |  40 +++++
>  arch/arm64/Makefile                            |  10 +-
>  arch/arm64/include/asm/assembler.h             |  30 +++-
>  arch/arm64/include/asm/boot.h                  |   6 +
>  arch/arm64/include/asm/elf.h                   |  54 +------
>  arch/arm64/include/asm/elf_relocs.h            |  75 ++++++++++
>  arch/arm64/include/asm/futex.h                 |  12 +-
>  arch/arm64/include/asm/kasan.h                 |  20 +--
>  arch/arm64/include/asm/kernel-pgtable.h        |  20 ++-
>  arch/arm64/include/asm/kvm_asm.h               |  19 ++-
>  arch/arm64/include/asm/kvm_host.h              |   8 +-
>  arch/arm64/include/asm/kvm_mmu.h               |   2 +
>  arch/arm64/include/asm/memory.h                |  38 +++--
>  arch/arm64/include/asm/module.h                |  11 ++
>  arch/arm64/include/asm/pgtable.h               |  22 ++-
>  arch/arm64/include/asm/uaccess.h               |  30 ++--
>  arch/arm64/include/asm/virt.h                  |   4 -
>  arch/arm64/include/asm/word-at-a-time.h        |   7 +-
>  arch/arm64/kernel/Makefile                     |   1 +
>  arch/arm64/kernel/armv8_deprecated.c           |   7 +-
>  arch/arm64/kernel/efi-entry.S                  |   9 +-
>  arch/arm64/kernel/head.S                       | 155 +++++++++++++++++---
>  arch/arm64/kernel/image.h                      |  37 ++---
>  arch/arm64/kernel/module-plts.c                | 137 +++++++++++++++++
>  arch/arm64/kernel/module.c                     |  15 +-
>  arch/arm64/kernel/module.lds                   |   4 +
>  arch/arm64/kernel/setup.c                      |  44 +++++-
>  arch/arm64/kernel/vmlinux.lds.S                |  13 +-
>  arch/arm64/kvm/debug.c                         |   1 +
>  arch/arm64/kvm/hyp.S                           |   6 +-
>  arch/arm64/mm/dump.c                           |  12 +-
>  arch/arm64/mm/extable.c                        |   2 +-
>  arch/arm64/mm/init.c                           |  91 ++++++++++--
>  arch/arm64/mm/kasan_init.c                     |  21 ++-
>  arch/arm64/mm/mmu.c                            |  95 +++++++-----
>  arch/x86/include/asm/efi.h                     |   2 +
>  drivers/firmware/efi/libstub/Makefile          |   2 +-
>  drivers/firmware/efi/libstub/arm-stub.c        |  17 ++-
>  drivers/firmware/efi/libstub/arm64-stub.c      |  67 +++++++--
>  drivers/firmware/efi/libstub/efi-stub-helper.c |  24 ++-
>  drivers/firmware/efi/libstub/efistub.h         |   9 ++
>  drivers/firmware/efi/libstub/random.c          | 120 +++++++++++++++
>  drivers/of/fdt.c                               |   5 +-
>  include/linux/efi.h                            |   5 +-
>  lib/extable.c                                  |  50 +++++--
>  scripts/sortextable.c                          |  10 +-
>  51 files changed, 1111 insertions(+), 309 deletions(-)
>  create mode 100644 arch/arm64/include/asm/elf_relocs.h
>  create mode 100644 arch/arm64/kernel/module-plts.c
>  create mode 100644 arch/arm64/kernel/module.lds
>  create mode 100644 drivers/firmware/efi/libstub/random.c
>
> EFI_RNG_PROTOCOL on real hardware
> =================================
>
> To test whether your UEFI implements the EFI_RNG_PROTOCOL, download the
> following executable and run it from the UEFI Shell:
> http://people.linaro.org/~ard.biesheuvel/RngTest.efi
>
> FS0:\> rngtest
> UEFI RNG Protocol Testing :
> ----------------------------
>  -- Locate UEFI RNG Protocol : [Fail - Status = Not Found]
>
> If your UEFI does not implement the EFI_RNG_PROTOCOL, you can download and
> install the pseudo-random version that uses the generic timer and PMCCNTR_EL0
> values and permutes them using a couple of rounds of AES.
> http://people.linaro.org/~ard.biesheuvel/RngDxe.efi
>
> NOTE: not for production!! This is a quick and dirty hack to test the KASLR
> code, and is not suitable for anything else.
>
> FS0:\> rngdxe
> FS0:\> rngtest
> UEFI RNG Protocol Testing :
> ----------------------------
>  -- Locate UEFI RNG Protocol : [Pass]
>  -- Call RNG->GetInfo() interface :
>      >> Supported RNG Algorithm (Count = 2) :
>           0) 44F0DE6E-4D8C-4045-A8C7-4DD168856B9E
>           1) E43176D7-B6E8-4827-B784-7FFDC4B68561
>  -- Call RNG->GetRNG() interface :
>      >> RNG with default algorithm : [Pass]
>      >> RNG with SP800-90-HMAC-256 : [Fail - Status = Unsupported]
>      >> RNG with SP800-90-Hash-256 : [Fail - Status = Unsupported]
>      >> RNG with SP800-90-CTR-256 : [Pass]
>      >> RNG with X9.31-3DES : [Fail - Status = Unsupported]
>      >> RNG with X9.31-AES : [Fail - Status = Unsupported]
>      >> RNG with RAW Entropy : [Pass]
>  -- Random Number Generation Test with default RNG Algorithm (20 Rounds):
>           01) - 27
>           02) - 61E8
>           03) - 496FD8
>           04) - DDD793BF
>           05) - B6C37C8E23
>           06) - 4D183C604A96
>           07) - 9363311DB61298
>           08) - 5715A7294F4E436E
>           09) - F0D4D7BAA0DD52318E
>           10) - C88C6EBCF4C0474D87C3
>           11) - B5594602B482A643932172
>           12) - CA7573F704B2089B726B9CF1
>           13) - A93E9451CB533DCFBA87B97C33
>           14) - 45AA7B83DB6044F7BBAB031F0D24
>           15) - 3DD7A4D61F34ADCB400B5976730DCF
>           16) - 4DD168D21FAB8F59708330D6A9BEB021
>           17) - 4BBB225E61C465F174254159467E65939F
>           18) - 030A156C9616337A20070941E702827DA8E1
>           19) - AB0FC11C9A4E225011382A9D164D9D55CA2B64
>           20) - 72B9B4735DC445E5DA6AF88DE965B7E87CB9A23C



-- 
Kees Cook
Chrome OS & Brillo Security

[toc] | [prev] | [next] | [standalone]


#1307043

FromArd Biesheuvel <ard.biesheuvel@linaro.org>
Date2016-01-12 08:20 +0100
Message-ID<qQ1pg-61J-5@gated-at.bofh.it>
In reply to#1306759
On 11 January 2016 at 23:07, Kees Cook <keescook@chromium.org> wrote:
> On Mon, Jan 11, 2016 at 5:18 AM, Ard Biesheuvel
> <ard.biesheuvel@linaro.org> wrote:
>> This series implements KASLR for arm64, by building the kernel as a PIE
>> executable that can relocate itself at runtime, and moving it to a random
>> offset in the vmalloc area. v2 and up also implement physical randomization,
>> i.e., it allows the kernel to deal with being loaded at any physical offset
>> (modulo the required alignment), and invokes the EFI_RNG_PROTOCOL from the
>> UEFI stub to obtain random bits and perform the actual randomization of the
>> physical load address.
>
> I will continue cheering! :)
>

:-)

>> Changes since v2:
>> - Incorporated feedback from Marc Zyngier into the KVM patch (#5)
>> - Dropped the pgdir section and the patch that memblock_reserve()'s the kernel
>>   sections at a smaller granularity. This is no longer necessary with the pgdir
>>   section gone. This also fixes an issue spotted by James Morse where the fixmap
>>   page tables are not zeroed correctly; these have been moved back to the .bss
>>   section.
>> - Got rid of all ifdef'ery regarding the number of translation levels in the
>>   changed .c files, by introducing new definitions in pgtable.h (#3, #6)
>> - Fixed KAsan support, which was broken by all earlier versions.
>> - Moved module region along with the virtually randomized kernel, so that module
>>   addresses become unpredictable as well, and we only have to rely on veneers in
>>   the PLTs when the module region is exhausted (which is somewhat more likely
>>   since the module region is now shared with other uses of the vmalloc area)
>
> Just to make sure I understand: this means that the offset between
> kernel and modules remains static? It may still be useful to bump
> modules as well, just so that leaking a module address doesn't
> compromise the base kernel image address too. Don't block the series
> for this, though. It's a minor nit. :)
>

Well, the module region could be any 128 MB memory region that also
covers the [_stext, _etext) interval. This would still allow all
modules to branch to all other modules and the core kernel without
resorting to indirect PLT jumps.
IOW, I think I can work around this quite easily.

>> - Added support for the 'nokaslr' command line option. This affects the
>>   randomization performed by the stub, and results in a warning if passed while
>>   the bootloader also presented a random seed for virtual KASLR in register x1.
>> - The .text/.rodata sections of the kernel are no longer aliased in the linear
>>   region with a writable mapping.
>> - Added a separate image header flag for kernel images that may be loaded at any
>>   2 MB aligned offset (+ TEXT_OFFSET)
>> - The KASLR displacement is now corrected if it results in the kernel image
>>   intersecting a PUD/PMD boundary (4k and 16k/64k granule kernels, respectively)
>> - Split out UEFI stub random routines into separate patches.
>> - Implemented a weight based EFI random allocation routine so that each suitable
>>   offset in available memory is equally likely to be selected (as suggested by
>>   Kees Cook)
>> - Reused CONFIG_RELOCATABLE and CONFIG_RANDOMIZE_BASE instead of introducing
>>   new Kconfig symbols to describe the same functionality.
>> - Reimplemented mem= logic so memory is clipped from the top first.
>>
>> Changes since v1/RFC:
>> - This series now implements fully independent virtual and physical address
>>   randomization at load time. I have recycled some patches from this series:
>>   http://thread.gmane.org/gmane.linux.ports.arm.kernel/455151, and updated the
>>   final UEFI stub patch to randomize the physical address as well.
>> - Added a patch to deal with the way KVM on arm64 makes assumptions about the
>>   relation between kernel symbols and the linear mapping (on which the HYP
>>   mapping is based), as these assumptions cease to be valid once we move the
>>   kernel Image out of the linear mapping.
>> - Updated the module PLT patch so it works on BE kernels as well.
>> - Moved the constant Image header values to head.S, and updated the linker
>>   script to provide the kernel size using R_AARCH64_ABS32 relocation rather
>>   than a R_AARCH64_ABS64 relocation, since those are always resolved at build
>>   time. This allows me to get rid of the post-build perl script to swab header
>>   values on BE kernels.
>> - Minor style tweaks.
>>
>> Notes:
>> - These patches apply on top of Mark Rutland's pagetable rework series:
>>   http://thread.gmane.org/gmane.linux.ports.arm.kernel/462438
>> - The arm64 Image is uncompressed by default, and the Elf64_Rela format uses
>>   24 bytes per relocation entry. This results in considerable bloat (i.e., a
>>   couple of MBs worth of relocation data in an .init section). However, no
>>   build time postprocessing is required, we rely fully on the toolchain to
>>   produce the image
>> - We have to rely on the bootloader to supply some randomness in register x1
>>   upon kernel entry. Since we have no decompressor, it is simply not feasible
>>   to collect randomness in the head.S code path before mapping the kernel and
>>   enabling the MMU.
>> - The EFI_RNG_PROTOCOL that is invoked in patch #13 to supply randomness on
>>   UEFI systems is not universally available. A QEMU/KVM firmware image that
>>   implements a pseudo-random version is available here:
>>   http://people.linaro.org/~ard.biesheuvel/QEMU_EFI.fd.aarch64-rng.bz2
>>   (requires access to PMCCNTR_EL0 and support for AES instructions)
>>   See below for instructions how to run the pseudo-random version on real
>>   hardware.
>> - Only mildly tested. Help appreciated.
>>
>> Code can be found here:
>> git://git.linaro.org/people/ard.biesheuvel/linux-arm.git arm64-kaslr-v3
>> https://git.linaro.org/people/ard.biesheuvel/linux-arm.git/shortlog/refs/heads/arm64-kaslr-v3
>>
>> Patch #1 updates the OF code to allow the minimum memblock physical address to
>> be overridden by the arch.
>>
>> Patch #2 introduces KIMAGE_VADDR as the base of the kernel virtual region.
>>
>> Patch #3 introduces dummy pud_index() and pmd_index() macros that are intended
>> to be optimized away if the configured number of translation levels does not
>> actually use them.
>>
>> Patch #4 rewrites early_fixmap_init() so it does not rely on the linear mapping
>> (i.e., the use of phys_to_virt() is avoided)
>>
>> Patch #5 updates KVM on arm64 so it can deal with kernel symbols whose addresses
>> are not covered by the linear mapping.
>>
>> Patch #6 introduces pte_offset_kimg(), pmd_offset_kimg() and pud_offset_kimg()
>> that allow statically allocated page tables (i.e., by fixmap and kasan) to be
>> traversed before the linear mapping is installed.
>>
>> Patch #7 moves the kernel virtual mapping to the vmalloc area, along with the
>> module region which is kept right below it, as before.
>>
>> Patch #8 adds support for PLTs in modules so that relative branches can be
>> resolved via a PLT if the target is out of range. This is required for KASLR,
>> since modules may be loaded far away from the core kernel.
>>
>> Patch #9 and #10 move arm64 to the a new generic relative version of the extable
>> implementation so that it no longer contains absolute addresses that require
>> fixing up at relocation time, but uses relative offsets instead.
>>
>> Patch #11 reverts some changes to the Image header population code so we no
>> longer depend on the linker to populate the header fields. This is necessary
>> since the R_AARCH64_ABS64 relocations that are emitted for these fields are not
>> resolved at build time for PIE executables.
>>
>> Patch #12 updates the code in head.S that needs to execute before relocation to
>> avoid the use of values that are subject to dynamic relocation. These values
>> will not be populated in PIE executables.
>>
>> Patch #13 allows the kernel Image to be loaded anywhere in physical memory, by
>> decoupling PHYS_OFFSET from the base of the kernel image.
>>
>> Patch #14 redefines SWAPPER_TABLE_SHIFT in a way that allows it to be used from
>> assembler code regardless of the number of configured translation levels.
>>
>> Patch #15 (from Mark Rutland) moves the ELF relocation type #defines to a
>> separate file so we can use it from head.S later
>>
>> Patch #16 updates scripts/sortextable.c so it accepts ET_DYN (relocatable)
>> executables as well as ET_EXEC (static) executables.
>>
>> Patch #17 implements the core KASLR, by taking randomness supplied in register
>> x1 and using it to move the kernel inside the vmalloc area.
>>
>> Patch #18 implements efi_get_random_bytes() based on the EFI_RNG_PROTOCOL
>>
>> Patch #19 implements efi_random_alloc()
>>
>> Patch #20 moves the allocation for the converted command line (UTF-16 to ASCII)
>> away from the base of memory. This is necessary since for parsing
>>
>> Patch #21 implements the actual KASLR, by randomizing the kernel physical
>> address, and passing entropy in x1 so that the kernel proper can relocate itself
>> virtually.
>>
>> Ard Biesheuvel (20):
>>   of/fdt: make memblock minimum physical address arch configurable
>>   arm64: introduce KIMAGE_VADDR as the virtual base of the kernel region
>>   arm64: pgtable: add dummy pud_index() and pmd_index() definitions
>>   arm64: decouple early fixmap init from linear mapping
>>   arm64: kvm: deal with kernel symbols outside of linear mapping
>>   arm64: pgtable: implement static [pte|pmd|pud]_offset variants
>>   arm64: move kernel image to base of vmalloc area
>>   arm64: add support for module PLTs
>>   extable: add support for relative extables to search and sort routines
>>   arm64: switch to relative exception tables
>>   arm64: avoid R_AARCH64_ABS64 relocations for Image header fields
>>   arm64: avoid dynamic relocations in early boot code
>>   arm64: allow kernel Image to be loaded anywhere in physical memory
>>   arm64: redefine SWAPPER_TABLE_SHIFT for use in asm code
>>   scripts/sortextable: add support for ET_DYN binaries
>>   arm64: add support for a relocatable kernel and KASLR
>>   efi: stub: implement efi_get_random_bytes() based on EFI_RNG_PROTOCOL
>>   efi: stub: add implementation of efi_random_alloc()
>>   efi: stub: use high allocation for converted command line
>>   arm64: efi: invoke EFI_RNG_PROTOCOL to supply KASLR randomness
>>
>> Mark Rutland (1):
>>   arm64: split elf relocs into a separate header.
>>
>>  Documentation/arm64/booting.txt                |  34 ++++-
>>  arch/arm/include/asm/kvm_asm.h                 |   2 +
>>  arch/arm/include/asm/kvm_mmu.h                 |   2 +
>>  arch/arm/kvm/arm.c                             |   5 +-
>>  arch/arm/kvm/mmu.c                             |   8 +-
>>  arch/arm64/Kconfig                             |  40 +++++
>>  arch/arm64/Makefile                            |  10 +-
>>  arch/arm64/include/asm/assembler.h             |  30 +++-
>>  arch/arm64/include/asm/boot.h                  |   6 +
>>  arch/arm64/include/asm/elf.h                   |  54 +------
>>  arch/arm64/include/asm/elf_relocs.h            |  75 ++++++++++
>>  arch/arm64/include/asm/futex.h                 |  12 +-
>>  arch/arm64/include/asm/kasan.h                 |  20 +--
>>  arch/arm64/include/asm/kernel-pgtable.h        |  20 ++-
>>  arch/arm64/include/asm/kvm_asm.h               |  19 ++-
>>  arch/arm64/include/asm/kvm_host.h              |   8 +-
>>  arch/arm64/include/asm/kvm_mmu.h               |   2 +
>>  arch/arm64/include/asm/memory.h                |  38 +++--
>>  arch/arm64/include/asm/module.h                |  11 ++
>>  arch/arm64/include/asm/pgtable.h               |  22 ++-
>>  arch/arm64/include/asm/uaccess.h               |  30 ++--
>>  arch/arm64/include/asm/virt.h                  |   4 -
>>  arch/arm64/include/asm/word-at-a-time.h        |   7 +-
>>  arch/arm64/kernel/Makefile                     |   1 +
>>  arch/arm64/kernel/armv8_deprecated.c           |   7 +-
>>  arch/arm64/kernel/efi-entry.S                  |   9 +-
>>  arch/arm64/kernel/head.S                       | 155 +++++++++++++++++---
>>  arch/arm64/kernel/image.h                      |  37 ++---
>>  arch/arm64/kernel/module-plts.c                | 137 +++++++++++++++++
>>  arch/arm64/kernel/module.c                     |  15 +-
>>  arch/arm64/kernel/module.lds                   |   4 +
>>  arch/arm64/kernel/setup.c                      |  44 +++++-
>>  arch/arm64/kernel/vmlinux.lds.S                |  13 +-
>>  arch/arm64/kvm/debug.c                         |   1 +
>>  arch/arm64/kvm/hyp.S                           |   6 +-
>>  arch/arm64/mm/dump.c                           |  12 +-
>>  arch/arm64/mm/extable.c                        |   2 +-
>>  arch/arm64/mm/init.c                           |  91 ++++++++++--
>>  arch/arm64/mm/kasan_init.c                     |  21 ++-
>>  arch/arm64/mm/mmu.c                            |  95 +++++++-----
>>  arch/x86/include/asm/efi.h                     |   2 +
>>  drivers/firmware/efi/libstub/Makefile          |   2 +-
>>  drivers/firmware/efi/libstub/arm-stub.c        |  17 ++-
>>  drivers/firmware/efi/libstub/arm64-stub.c      |  67 +++++++--
>>  drivers/firmware/efi/libstub/efi-stub-helper.c |  24 ++-
>>  drivers/firmware/efi/libstub/efistub.h         |   9 ++
>>  drivers/firmware/efi/libstub/random.c          | 120 +++++++++++++++
>>  drivers/of/fdt.c                               |   5 +-
>>  include/linux/efi.h                            |   5 +-
>>  lib/extable.c                                  |  50 +++++--
>>  scripts/sortextable.c                          |  10 +-
>>  51 files changed, 1111 insertions(+), 309 deletions(-)
>>  create mode 100644 arch/arm64/include/asm/elf_relocs.h
>>  create mode 100644 arch/arm64/kernel/module-plts.c
>>  create mode 100644 arch/arm64/kernel/module.lds
>>  create mode 100644 drivers/firmware/efi/libstub/random.c
>>
>> EFI_RNG_PROTOCOL on real hardware
>> =================================
>>
>> To test whether your UEFI implements the EFI_RNG_PROTOCOL, download the
>> following executable and run it from the UEFI Shell:
>> http://people.linaro.org/~ard.biesheuvel/RngTest.efi
>>
>> FS0:\> rngtest
>> UEFI RNG Protocol Testing :
>> ----------------------------
>>  -- Locate UEFI RNG Protocol : [Fail - Status = Not Found]
>>
>> If your UEFI does not implement the EFI_RNG_PROTOCOL, you can download and
>> install the pseudo-random version that uses the generic timer and PMCCNTR_EL0
>> values and permutes them using a couple of rounds of AES.
>> http://people.linaro.org/~ard.biesheuvel/RngDxe.efi
>>
>> NOTE: not for production!! This is a quick and dirty hack to test the KASLR
>> code, and is not suitable for anything else.
>>
>> FS0:\> rngdxe
>> FS0:\> rngtest
>> UEFI RNG Protocol Testing :
>> ----------------------------
>>  -- Locate UEFI RNG Protocol : [Pass]
>>  -- Call RNG->GetInfo() interface :
>>      >> Supported RNG Algorithm (Count = 2) :
>>           0) 44F0DE6E-4D8C-4045-A8C7-4DD168856B9E
>>           1) E43176D7-B6E8-4827-B784-7FFDC4B68561
>>  -- Call RNG->GetRNG() interface :
>>      >> RNG with default algorithm : [Pass]
>>      >> RNG with SP800-90-HMAC-256 : [Fail - Status = Unsupported]
>>      >> RNG with SP800-90-Hash-256 : [Fail - Status = Unsupported]
>>      >> RNG with SP800-90-CTR-256 : [Pass]
>>      >> RNG with X9.31-3DES : [Fail - Status = Unsupported]
>>      >> RNG with X9.31-AES : [Fail - Status = Unsupported]
>>      >> RNG with RAW Entropy : [Pass]
>>  -- Random Number Generation Test with default RNG Algorithm (20 Rounds):
>>           01) - 27
>>           02) - 61E8
>>           03) - 496FD8
>>           04) - DDD793BF
>>           05) - B6C37C8E23
>>           06) - 4D183C604A96
>>           07) - 9363311DB61298
>>           08) - 5715A7294F4E436E
>>           09) - F0D4D7BAA0DD52318E
>>           10) - C88C6EBCF4C0474D87C3
>>           11) - B5594602B482A643932172
>>           12) - CA7573F704B2089B726B9CF1
>>           13) - A93E9451CB533DCFBA87B97C33
>>           14) - 45AA7B83DB6044F7BBAB031F0D24
>>           15) - 3DD7A4D61F34ADCB400B5976730DCF
>>           16) - 4DD168D21FAB8F59708330D6A9BEB021
>>           17) - 4BBB225E61C465F174254159467E65939F
>>           18) - 030A156C9616337A20070941E702827DA8E1
>>           19) - AB0FC11C9A4E225011382A9D164D9D55CA2B64
>>           20) - 72B9B4735DC445E5DA6AF88DE965B7E87CB9A23C
>
>
>
> --
> Kees Cook
> Chrome OS & Brillo Security

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

Back to top | Article view | linux.kernel


csiph-web