Skip to contentSkip to conversation

arm64: align randomized TEXT_OFFSET on 4 kB boundary

PATCH New Ard Biesheuvel 3 participants 4 messages Aug 13, 2014 – Aug 14, 2014 arm64

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 arm64: align randomized TEXT_OFFSET on 4 kB boundary

When booting via UEFI, the kernel Image is loaded at a 4 kB boundary and the embedded EFI stub is executed in place. The EFI stub relocates the Image to reside TEXT_OFFSET bytes above a 2 MB boundary, and jumps into the kernel proper.

In AArch64, PC relative symbol references are emitted using adrp/add or adrp/ldr pairs, where the offset into a 4 kB page is resolved using a separate :lo12: relocation. This implicitly assumes that the code will always be executed at the same relative offset with respect to a 4 kB boundary, or the references will point to the wrong address.

This means we should link the kernel at a 4 kB aligned base address in order to remain compatible with the base address the UEFI loader uses when doing the initial load of Image. So update the code that generates TEXT_OFFSET to choose a multiple of 4 kB.

At the same time, update the code so it chooses from the interval [0..2MB) as the author originally intended.

---
 arch/arm64/Makefile      | 2 +-
 arch/arm64/kernel/head.S | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)
arch/arm64/Makefile +1 -1
index 57833546bf00..2df5e5daeebe 100644
@@ -39,7 +39,7 @@ head-y		:= arch/arm64/kernel/head.o
 
 # The byte offset of the kernel image in RAM from the start of RAM.
 ifeq ($(CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET), y)
-TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%04x0\n", int(65535 * rand())}')
+TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%03x000\n", int(512 * rand())}')
 else
 TEXT_OFFSET := 0x00080000
 endif
arch/arm64/kernel/head.S +4 -4
index b6ca95aee348..ae055a18b04a 100644
@@ -38,11 +38,11 @@
 
 #define KERNEL_RAM_VADDR	(PAGE_OFFSET + TEXT_OFFSET)
 
-#if (TEXT_OFFSET & 0xf) != 0
-#error TEXT_OFFSET must be at least 16B aligned
-#elif (PAGE_OFFSET & 0xfffff) != 0
+#if (TEXT_OFFSET & 0xfff) != 0
+#error TEXT_OFFSET must be at least 4kB aligned
+#elif (PAGE_OFFSET & 0x1fffff) != 0
 #error PAGE_OFFSET must be at least 2MB aligned
-#elif TEXT_OFFSET > 0xfffff
+#elif TEXT_OFFSET > 0x1fffff
 #error TEXT_OFFSET must be less than 2MB
 #endif
 
Signature · 1 line
1.8.3.2
reviewer
#1 lore raw

PATCH 1/1 arm64: align randomized TEXT_OFFSET on 4 kB boundary

Hi Ard,

Quoted 43 lines · Ard Biesheuvel

When booting via UEFI, the kernel Image is loaded at a 4 kB boundary and the embedded EFI stub is executed in place. The EFI stub relocates the Image to reside TEXT_OFFSET bytes above a 2 MB boundary, and jumps into the kernel proper.

In AArch64, PC relative symbol references are emitted using adrp/add or adrp/ldr pairs, where the offset into a 4 kB page is resolved using a separate :lo12: relocation. This implicitly assumes that the code will always be executed at the same relative offset with respect to a 4 kB boundary, or the references will point to the wrong address.

This means we should link the kernel at a 4 kB aligned base address in order to remain compatible with the base address the UEFI loader uses when doing the initial load of Image. So update the code that generates TEXT_OFFSET to choose a multiple of 4 kB.

At the same time, update the code so it chooses from the interval [0..2MB) as the author originally intended.

---
 arch/arm64/Makefile      | 2 +-
 arch/arm64/kernel/head.S | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)
arch/arm64/Makefile +1 -1
index 57833546bf00..2df5e5daeebe 100644
@@ -39,7 +39,7 @@ head-y		:= arch/arm64/kernel/head.o
 
 # The byte offset of the kernel image in RAM from the start of RAM.
 ifeq ($(CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET), y)
-TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%04x0\n", int(65535 * rand())}')
+TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%03x000\n", int(512 * rand())}')
 else
 TEXT_OFFSET := 0x00080000
 endif
arch/arm64/kernel/head.S +0 -0
index b6ca95aee348..ae055a18b04a 100644

arch/arm64/kernel/head.S line 42

Quoted 8 lines
arch/arm64/kernel/head.S +2 -3
@@ -38,11 +38,11 @@
 
 #define KERNEL_RAM_VADDR	(PAGE_OFFSET + TEXT_OFFSET)
 
-#if (TEXT_OFFSET & 0xf) != 0
-#error TEXT_OFFSET must be at least 16B aligned
-#elif (PAGE_OFFSET & 0xfffff) != 0
+#if (TEXT_OFFSET & 0xfff) != 0
+#error TEXT_OFFSET must be at least 4kB aligned

Minor nit, but can we have "KB" here to match "MB"?

arch/arm64/kernel/head.S line 47

Quoted 6 lines
arch/arm64/kernel/head.S +2 -1
+#elif (PAGE_OFFSET & 0x1fffff) != 0
 #error PAGE_OFFSET must be at least 2MB aligned
-#elif TEXT_OFFSET > 0xfffff
+#elif TEXT_OFFSET > 0x1fffff
 #error TEXT_OFFSET must be less than 2MB
 #endif

I thought I'd left wording in Kconfig.debug, but that doesn't seem to be the case. This looks sane to me, so:

Catalin, can you pick this up? Without it UEFI boot can be broken by ARM64_RANDOMIZE_TEXT_OFFSET.

Cheers,
Mark.

#2 lore raw

PATCH 1/1 arm64: align randomized TEXT_OFFSET on 4 kB boundary

Quoted 49 lines · Mark Rutland

Hi Ard,

Quoted 46 lines · Ard Biesheuvel

When booting via UEFI, the kernel Image is loaded at a 4 kB boundary and the embedded EFI stub is executed in place. The EFI stub relocates the Image to reside TEXT_OFFSET bytes above a 2 MB boundary, and jumps into the kernel proper.

In AArch64, PC relative symbol references are emitted using adrp/add or adrp/ldr pairs, where the offset into a 4 kB page is resolved using a separate :lo12: relocation. This implicitly assumes that the code will always be executed at the same relative offset with respect to a 4 kB boundary, or the references will point to the wrong address.

This means we should link the kernel at a 4 kB aligned base address in order to remain compatible with the base address the UEFI loader uses when doing the initial load of Image. So update the code that generates TEXT_OFFSET to choose a multiple of 4 kB.

At the same time, update the code so it chooses from the interval [0..2MB) as the author originally intended.

---
 arch/arm64/Makefile      | 2 +-
 arch/arm64/kernel/head.S | 8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)
arch/arm64/Makefile +1 -1
index 57833546bf00..2df5e5daeebe 100644
@@ -39,7 +39,7 @@ head-y              := arch/arm64/kernel/head.o
 
 # The byte offset of the kernel image in RAM from the start of RAM.
 ifeq ($(CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET), y)
-TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%04x0\n", int(65535 * rand())}')
+TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%03x000\n", int(512 * rand())}')
 else
 TEXT_OFFSET := 0x00080000
 endif
arch/arm64/kernel/head.S +0 -0
index b6ca95aee348..ae055a18b04a 100644
@@ -38,11 +38,11 @@
 
 #define KERNEL_RAM_VADDR     (PAGE_OFFSET + TEXT_OFFSET)
 
Quoted 8 lines

arch/arm64/kernel/head.S line 42

Quoted 5 lines
arch/arm64/kernel/head.S +2 -3
-#if (TEXT_OFFSET & 0xf) != 0
-#error TEXT_OFFSET must be at least 16B aligned
-#elif (PAGE_OFFSET & 0xfffff) != 0
+#if (TEXT_OFFSET & 0xfff) != 0
+#error TEXT_OFFSET must be at least 4kB aligned

Minor nit, but can we have "KB" here to match "MB"?

Ack

Quoted 10 lines

arch/arm64/kernel/head.S line 47

Quoted 6 lines
arch/arm64/kernel/head.S +2 -1
+#elif (PAGE_OFFSET & 0x1fffff) != 0
 #error PAGE_OFFSET must be at least 2MB aligned
-#elif TEXT_OFFSET > 0xfffff
+#elif TEXT_OFFSET > 0x1fffff
 #error TEXT_OFFSET must be less than 2MB
 #endif

I thought I'd left wording in Kconfig.debug, but that doesn't seem to be the case. This looks sane to me, so:

Quoted 5 lines

Catalin, can you pick this up? Without it UEFI boot can be broken by ARM64_RANDOMIZE_TEXT_OFFSET.

I assume the above change does not require a v2.

Signature · 1 line
Ard.
maintainer
#3 lore raw

PATCH 1/1 arm64: align randomized TEXT_OFFSET on 4 kB boundary

Quoted 30 lines · Ard Biesheuvel
Quoted 9 lines · Mark Rutland
Quoted 8 lines · Ard Biesheuvel
arch/arm64/kernel/head.S +0 -0
index b6ca95aee348..ae055a18b04a 100644
@@ -38,11 +38,11 @@
 
 #define KERNEL_RAM_VADDR     (PAGE_OFFSET + TEXT_OFFSET)
 
Quoted 7 lines

arch/arm64/kernel/head.S line 42

Quoted 5 lines
arch/arm64/kernel/head.S +2 -3
-#if (TEXT_OFFSET & 0xf) != 0
-#error TEXT_OFFSET must be at least 16B aligned
-#elif (PAGE_OFFSET & 0xfffff) != 0
+#if (TEXT_OFFSET & 0xfff) != 0
+#error TEXT_OFFSET must be at least 4kB aligned

Minor nit, but can we have "KB" here to match "MB"?

Ack

Quoted 10 lines

arch/arm64/kernel/head.S line 47

Quoted 6 lines
arch/arm64/kernel/head.S +2 -1
+#elif (PAGE_OFFSET & 0x1fffff) != 0
 #error PAGE_OFFSET must be at least 2MB aligned
-#elif TEXT_OFFSET > 0xfffff
+#elif TEXT_OFFSET > 0x1fffff
 #error TEXT_OFFSET must be less than 2MB
 #endif

I thought I'd left wording in Kconfig.debug, but that doesn't seem to be the case. This looks sane to me, so:

Quoted 6 lines
Quoted 4 lines

Catalin, can you pick this up? Without it UEFI boot can be broken by ARM64_RANDOMIZE_TEXT_OFFSET.

I assume the above change does not require a v2.

I can fix it up. Thanks.

Signature · 1 line
Catalin