* [PATCH v3 0/6] x86: Rid .head.text of all abs references
@ 2024-11-25 17:04 Ard Biesheuvel
2024-11-25 17:04 ` [PATCH v3 1/6] x86/sev: Avoid WARN()s and panic()s in early boot code Ard Biesheuvel
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2024-11-25 17:04 UTC (permalink / raw)
To: linux-kernel
Cc: x86, Ard Biesheuvel, Tom Lendacky, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, Andy Lutomirski, Arnd Bergmann,
Kees Cook, Brian Gerst, Kevin Loughlin
From: Ard Biesheuvel <ardb@kernel.org>
This series removes the last remaining absolute symbol references from
.head.text. Doing so is necessary because code in this section may be
called from a 1:1 mapping of memory, which deviates from the mapping
this code was linked and/or relocated to run at. This is not something
that the toolchains support: even PIC/PIE code is still assumed to
execute from the same mapping that it was relocated to run from by the
startup code or dynamic loader. This means we are basically on our own
here, and need to add measures to ensure the code works as expected in
this manner.
Given that the startup code needs to create the kernel virtual mapping
in the page tables, early references to some kernel virtual addresses
are valid even if they cannot be dereferenced yet. To avoid having to
make this distinction at build time, patches #2 and #3 replace such
valid references with RIP-relative references with an offset applied.
Patch #1 removes some absolute references from .head.text that don't
need to be there in the first place.
Changes since v2:
- drop Xen changes, which have been merged in the meantime
- update patch #1 with feedback from Tom
- reorganize the .text section and emit .head.text into a separate
output section for easier diagnostics
- update the 'relocs' tool to reject absolute ELF relocations in
.head.text
Changes since v1/RFC:
- rename va_offset to p2v_offset
- take PA of _text in C code directly
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Kees Cook <keescook@chromium.org>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Kevin Loughlin <kevinloughlin@google.com>
Ard Biesheuvel (6):
x86/sev: Avoid WARN()s and panic()s in early boot code
x86/boot/64: Determine VA/PA offset before entering C code
x86/boot/64: Avoid intentional absolute symbol references in
.head.text
x86/kernel: Move ENTRY_TEXT to the start of the image
x86/boot: Move .head.text into its own output section
x86/boot: Reject absolute references in .head.text
arch/x86/coco/sev/core.c | 15 +++-----
arch/x86/coco/sev/shared.c | 9 ++---
arch/x86/include/asm/setup.h | 2 +-
arch/x86/kernel/head64.c | 38 ++++++++++++--------
arch/x86/kernel/head_64.S | 12 +++++--
arch/x86/kernel/vmlinux.lds.S | 29 ++++++++-------
arch/x86/tools/relocs.c | 8 ++++-
7 files changed, 66 insertions(+), 47 deletions(-)
--
2.47.0.371.ga323438b13-goog
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 1/6] x86/sev: Avoid WARN()s and panic()s in early boot code
2024-11-25 17:04 [PATCH v3 0/6] x86: Rid .head.text of all abs references Ard Biesheuvel
@ 2024-11-25 17:04 ` Ard Biesheuvel
2024-11-25 17:04 ` [PATCH v3 2/6] x86/boot/64: Determine VA/PA offset before entering C code Ard Biesheuvel
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2024-11-25 17:04 UTC (permalink / raw)
To: linux-kernel
Cc: x86, Ard Biesheuvel, Tom Lendacky, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, Andy Lutomirski, Arnd Bergmann,
Kees Cook, Brian Gerst, Kevin Loughlin
From: Ard Biesheuvel <ardb@kernel.org>
Using WARN() or panic() while executing from the early 1:1 mapping is
unlikely to do anything useful: the string literals are passed using
their kernel virtual addresses which are not even mapped yet. But even
if they were, calling into the printk() machinery from the early 1:1
mapped code is not going to get very far.
So drop the WARN()s entirely, and replace panic() with a deadloop.
Link: https://lore.kernel.org/all/6904c198-9047-14bb-858e-38b531589379@amd.com/T/#u
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/coco/sev/core.c | 15 +++++----------
arch/x86/coco/sev/shared.c | 9 +++++----
2 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c
index c5b0148b8c0a..499b41953e3c 100644
--- a/arch/x86/coco/sev/core.c
+++ b/arch/x86/coco/sev/core.c
@@ -777,15 +777,10 @@ early_set_pages_state(unsigned long vaddr, unsigned long paddr,
val = sev_es_rd_ghcb_msr();
- if (WARN(GHCB_RESP_CODE(val) != GHCB_MSR_PSC_RESP,
- "Wrong PSC response code: 0x%x\n",
- (unsigned int)GHCB_RESP_CODE(val)))
+ if (GHCB_RESP_CODE(val) != GHCB_MSR_PSC_RESP)
goto e_term;
- if (WARN(GHCB_MSR_PSC_RESP_VAL(val),
- "Failed to change page state to '%s' paddr 0x%lx error 0x%llx\n",
- op == SNP_PAGE_STATE_PRIVATE ? "private" : "shared",
- paddr, GHCB_MSR_PSC_RESP_VAL(val)))
+ if (GHCB_MSR_PSC_RESP_VAL(val))
goto e_term;
/* Page validation must be performed after changing to private */
@@ -821,7 +816,7 @@ void __head early_snp_set_memory_private(unsigned long vaddr, unsigned long padd
early_set_pages_state(vaddr, paddr, npages, SNP_PAGE_STATE_PRIVATE);
}
-void __init early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr,
+void __head early_snp_set_memory_shared(unsigned long vaddr, unsigned long paddr,
unsigned long npages)
{
/*
@@ -2361,8 +2356,8 @@ static __head void svsm_setup(struct cc_blob_sev_info *cc_info)
call.rax = SVSM_CORE_CALL(SVSM_CORE_REMAP_CA);
call.rcx = pa;
ret = svsm_perform_call_protocol(&call);
- if (ret)
- panic("Can't remap the SVSM CA, ret=%d, rax_out=0x%llx\n", ret, call.rax_out);
+ while (ret)
+ cpu_relax(); /* too early to panic */
RIP_REL_REF(boot_svsm_caa) = (struct svsm_ca *)pa;
RIP_REL_REF(boot_svsm_caa_pa) = pa;
diff --git a/arch/x86/coco/sev/shared.c b/arch/x86/coco/sev/shared.c
index 71de53194089..afb7ffc355fe 100644
--- a/arch/x86/coco/sev/shared.c
+++ b/arch/x86/coco/sev/shared.c
@@ -1243,7 +1243,7 @@ static void svsm_pval_terminate(struct svsm_pvalidate_call *pc, int ret, u64 svs
__pval_terminate(pfn, action, page_size, ret, svsm_ret);
}
-static void svsm_pval_4k_page(unsigned long paddr, bool validate)
+static void __head svsm_pval_4k_page(unsigned long paddr, bool validate)
{
struct svsm_pvalidate_call *pc;
struct svsm_call call = {};
@@ -1275,12 +1275,13 @@ static void svsm_pval_4k_page(unsigned long paddr, bool validate)
ret = svsm_perform_call_protocol(&call);
if (ret)
- svsm_pval_terminate(pc, ret, call.rax_out);
+ sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PVALIDATE);
native_local_irq_restore(flags);
}
-static void pvalidate_4k_page(unsigned long vaddr, unsigned long paddr, bool validate)
+static void __head pvalidate_4k_page(unsigned long vaddr, unsigned long paddr,
+ bool validate)
{
int ret;
@@ -1293,7 +1294,7 @@ static void pvalidate_4k_page(unsigned long vaddr, unsigned long paddr, bool val
} else {
ret = pvalidate(vaddr, RMP_PG_SIZE_4K, validate);
if (ret)
- __pval_terminate(PHYS_PFN(paddr), validate, RMP_PG_SIZE_4K, ret, 0);
+ sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_PVALIDATE);
}
}
--
2.47.0.371.ga323438b13-goog
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 2/6] x86/boot/64: Determine VA/PA offset before entering C code
2024-11-25 17:04 [PATCH v3 0/6] x86: Rid .head.text of all abs references Ard Biesheuvel
2024-11-25 17:04 ` [PATCH v3 1/6] x86/sev: Avoid WARN()s and panic()s in early boot code Ard Biesheuvel
@ 2024-11-25 17:04 ` Ard Biesheuvel
2024-11-25 17:04 ` [PATCH v3 3/6] x86/boot/64: Avoid intentional absolute symbol references in .head.text Ard Biesheuvel
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2024-11-25 17:04 UTC (permalink / raw)
To: linux-kernel
Cc: x86, Ard Biesheuvel, Tom Lendacky, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, Andy Lutomirski, Arnd Bergmann,
Kees Cook, Brian Gerst, Kevin Loughlin
From: Ard Biesheuvel <ardb@kernel.org>
Implicit absolute symbol references (e.g., taking the address of a
global variable) must be avoided in the C code that runs from the early
1:1 mapping of the kernel, given that this is a practice that violates
assumptions on the part of the toolchain. I.e., RIP-relative and
absolute references are expected to produce the same values, and so the
compiler is free to choose either. However, the code currently assumes
that RIP-relative references are never emitted here.
So an explicit virtual-to-physical offset needs to be used instead to
derive the kernel virtual addresses of _text and _end, instead of simply
taking the addresses and assuming that the compiler will not choose to
use a RIP-relative references in this particular case.
Currently, phys_base is already used to perform such calculations, but
it is derived from the kernel virtual address of _text, which is taken
using an implicit absolute symbol reference. So instead, derive this
VA-to-PA offset in asm code, and pass it to the C startup code.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/include/asm/setup.h | 2 +-
arch/x86/kernel/head64.c | 8 +++++---
arch/x86/kernel/head_64.S | 12 +++++++++---
3 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h
index 0667b2a88614..85f4fde3515c 100644
--- a/arch/x86/include/asm/setup.h
+++ b/arch/x86/include/asm/setup.h
@@ -49,7 +49,7 @@ extern unsigned long saved_video_mode;
extern void reserve_standard_io_resources(void);
extern void i386_reserve_resources(void);
-extern unsigned long __startup_64(unsigned long physaddr, struct boot_params *bp);
+extern unsigned long __startup_64(unsigned long p2v_offset, struct boot_params *bp);
extern void startup_64_setup_gdt_idt(void);
extern void early_setup_idt(void);
extern void __init do_early_exception(struct pt_regs *regs, int trapnr);
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index 4b9d4557fc94..a7cd4053eeb3 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -138,12 +138,14 @@ static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdv
* doesn't have to generate PC-relative relocations when accessing globals from
* that function. Clang actually does not generate them, which leads to
* boot-time crashes. To work around this problem, every global pointer must
- * be accessed using RIP_REL_REF().
+ * be accessed using RIP_REL_REF(). Kernel virtual addresses can be determined
+ * by subtracting p2v_offset from the RIP-relative address.
*/
-unsigned long __head __startup_64(unsigned long physaddr,
+unsigned long __head __startup_64(unsigned long p2v_offset,
struct boot_params *bp)
{
pmd_t (*early_pgts)[PTRS_PER_PMD] = RIP_REL_REF(early_dynamic_pgts);
+ unsigned long physaddr = (unsigned long)&RIP_REL_REF(_text);
unsigned long pgtable_flags;
unsigned long load_delta;
pgdval_t *pgd;
@@ -163,7 +165,7 @@ unsigned long __head __startup_64(unsigned long physaddr,
* Compute the delta between the address I am compiled to run at
* and the address I am actually running at.
*/
- load_delta = physaddr - (unsigned long)(_text - __START_KERNEL_map);
+ load_delta = __START_KERNEL_map + p2v_offset;
RIP_REL_REF(phys_base) = load_delta;
/* Is the address not 2M aligned? */
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 56163e2124cf..31345e0ba006 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -94,13 +94,19 @@ SYM_CODE_START_NOALIGN(startup_64)
/* Sanitize CPU configuration */
call verify_cpu
+ /*
+ * Derive the kernel's physical-to-virtual offset from the physical and
+ * virtual addresses of common_startup_64().
+ */
+ leaq common_startup_64(%rip), %rdi
+ subq .Lcommon_startup_64(%rip), %rdi
+
/*
* Perform pagetable fixups. Additionally, if SME is active, encrypt
* the kernel and retrieve the modifier (SME encryption mask if SME
* is active) to be added to the initial pgdir entry that will be
* programmed into CR3.
*/
- leaq _text(%rip), %rdi
movq %r15, %rsi
call __startup_64
@@ -128,11 +134,11 @@ SYM_CODE_START_NOALIGN(startup_64)
/* Branch to the common startup code at its kernel virtual address */
ANNOTATE_RETPOLINE_SAFE
- jmp *0f(%rip)
+ jmp *.Lcommon_startup_64(%rip)
SYM_CODE_END(startup_64)
__INITRODATA
-0: .quad common_startup_64
+SYM_DATA_LOCAL(.Lcommon_startup_64, .quad common_startup_64)
.text
SYM_CODE_START(secondary_startup_64)
--
2.47.0.371.ga323438b13-goog
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 3/6] x86/boot/64: Avoid intentional absolute symbol references in .head.text
2024-11-25 17:04 [PATCH v3 0/6] x86: Rid .head.text of all abs references Ard Biesheuvel
2024-11-25 17:04 ` [PATCH v3 1/6] x86/sev: Avoid WARN()s and panic()s in early boot code Ard Biesheuvel
2024-11-25 17:04 ` [PATCH v3 2/6] x86/boot/64: Determine VA/PA offset before entering C code Ard Biesheuvel
@ 2024-11-25 17:04 ` Ard Biesheuvel
2024-11-25 17:04 ` [PATCH v3 4/6] x86/kernel: Move ENTRY_TEXT to the start of the image Ard Biesheuvel
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2024-11-25 17:04 UTC (permalink / raw)
To: linux-kernel
Cc: x86, Ard Biesheuvel, Tom Lendacky, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, Andy Lutomirski, Arnd Bergmann,
Kees Cook, Brian Gerst, Kevin Loughlin
From: Ard Biesheuvel <ardb@kernel.org>
The code in .head.text executes from a 1:1 mapping and cannot generally
refer to global variables using their kernel virtual addresses. However,
there are some occurrences of such references that are valid: the kernel
virtual addresses of _text and _end are needed to populate the page
tables correctly, and some other section markers are used in a similar
way.
To avoid the need for making exceptions to the rule that .head.text must
not contain any absolute symbol references, derive these addresses from
the RIP-relative 1:1 mapped physical addresses, which can be safely
determined using RIP_REL_REF().
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/kernel/head64.c | 30 ++++++++++++--------
1 file changed, 18 insertions(+), 12 deletions(-)
diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c
index a7cd4053eeb3..54f9a8faf212 100644
--- a/arch/x86/kernel/head64.c
+++ b/arch/x86/kernel/head64.c
@@ -91,9 +91,11 @@ static inline bool check_la57_support(void)
return true;
}
-static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdval_t *pmd)
+static unsigned long __head sme_postprocess_startup(struct boot_params *bp,
+ pmdval_t *pmd,
+ unsigned long p2v_offset)
{
- unsigned long vaddr, vaddr_end;
+ unsigned long paddr, paddr_end;
int i;
/* Encrypt the kernel and related (if SME is active) */
@@ -106,10 +108,10 @@ static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdv
* attribute.
*/
if (sme_get_me_mask()) {
- vaddr = (unsigned long)__start_bss_decrypted;
- vaddr_end = (unsigned long)__end_bss_decrypted;
+ paddr = (unsigned long)&RIP_REL_REF(__start_bss_decrypted);
+ paddr_end = (unsigned long)&RIP_REL_REF(__end_bss_decrypted);
- for (; vaddr < vaddr_end; vaddr += PMD_SIZE) {
+ for (; paddr < paddr_end; paddr += PMD_SIZE) {
/*
* On SNP, transition the page to shared in the RMP table so that
* it is consistent with the page table attribute change.
@@ -118,11 +120,11 @@ static unsigned long __head sme_postprocess_startup(struct boot_params *bp, pmdv
* mapping (kernel .text). PVALIDATE, by way of
* early_snp_set_memory_shared(), requires a valid virtual
* address but the kernel is currently running off of the identity
- * mapping so use __pa() to get a *currently* valid virtual address.
+ * mapping so use the PA to get a *currently* valid virtual address.
*/
- early_snp_set_memory_shared(__pa(vaddr), __pa(vaddr), PTRS_PER_PMD);
+ early_snp_set_memory_shared(paddr, paddr, PTRS_PER_PMD);
- i = pmd_index(vaddr);
+ i = pmd_index(paddr - p2v_offset);
pmd[i] -= sme_get_me_mask();
}
}
@@ -146,6 +148,7 @@ unsigned long __head __startup_64(unsigned long p2v_offset,
{
pmd_t (*early_pgts)[PTRS_PER_PMD] = RIP_REL_REF(early_dynamic_pgts);
unsigned long physaddr = (unsigned long)&RIP_REL_REF(_text);
+ unsigned long va_text, va_end;
unsigned long pgtable_flags;
unsigned long load_delta;
pgdval_t *pgd;
@@ -172,6 +175,9 @@ unsigned long __head __startup_64(unsigned long p2v_offset,
if (load_delta & ~PMD_MASK)
for (;;);
+ va_text = physaddr - p2v_offset;
+ va_end = (unsigned long)&RIP_REL_REF(_end) - p2v_offset;
+
/* Include the SME encryption mask in the fixup value */
load_delta += sme_get_me_mask();
@@ -232,7 +238,7 @@ unsigned long __head __startup_64(unsigned long p2v_offset,
pmd_entry += sme_get_me_mask();
pmd_entry += physaddr;
- for (i = 0; i < DIV_ROUND_UP(_end - _text, PMD_SIZE); i++) {
+ for (i = 0; i < DIV_ROUND_UP(va_end - va_text, PMD_SIZE); i++) {
int idx = i + (physaddr >> PMD_SHIFT);
pmd[idx % PTRS_PER_PMD] = pmd_entry + i * PMD_SIZE;
@@ -257,11 +263,11 @@ unsigned long __head __startup_64(unsigned long p2v_offset,
pmd = &RIP_REL_REF(level2_kernel_pgt)->pmd;
/* invalidate pages before the kernel image */
- for (i = 0; i < pmd_index((unsigned long)_text); i++)
+ for (i = 0; i < pmd_index(va_text); i++)
pmd[i] &= ~_PAGE_PRESENT;
/* fixup pages that are part of the kernel image */
- for (; i <= pmd_index((unsigned long)_end); i++)
+ for (; i <= pmd_index(va_end); i++)
if (pmd[i] & _PAGE_PRESENT)
pmd[i] += load_delta;
@@ -269,7 +275,7 @@ unsigned long __head __startup_64(unsigned long p2v_offset,
for (; i < PTRS_PER_PMD; i++)
pmd[i] &= ~_PAGE_PRESENT;
- return sme_postprocess_startup(bp, pmd);
+ return sme_postprocess_startup(bp, pmd, p2v_offset);
}
/* Wipe all early page tables except for the kernel symbol map */
--
2.47.0.371.ga323438b13-goog
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 4/6] x86/kernel: Move ENTRY_TEXT to the start of the image
2024-11-25 17:04 [PATCH v3 0/6] x86: Rid .head.text of all abs references Ard Biesheuvel
` (2 preceding siblings ...)
2024-11-25 17:04 ` [PATCH v3 3/6] x86/boot/64: Avoid intentional absolute symbol references in .head.text Ard Biesheuvel
@ 2024-11-25 17:04 ` Ard Biesheuvel
2024-11-25 17:04 ` [PATCH v3 5/6] x86/boot: Move .head.text into its own output section Ard Biesheuvel
2024-11-25 17:04 ` [PATCH v3 6/6] x86/boot: Reject absolute references in .head.text Ard Biesheuvel
5 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2024-11-25 17:04 UTC (permalink / raw)
To: linux-kernel
Cc: x86, Ard Biesheuvel, Tom Lendacky, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, Andy Lutomirski, Arnd Bergmann,
Kees Cook, Brian Gerst, Kevin Loughlin
From: Ard Biesheuvel <ardb@kernel.org>
Since commit
7734a0f31e99 ("x86/boot: Robustify calling startup_{32,64}() from the decompressor code")
it is no longer necessary for .head.text to appear at the start of the
image.
Considering that ENTRY_TEXT needs to appear PMD-aligned, move it to the
start of the image, where the alignment requirement is trivially met.
Doing so removes the need to place ENTRY_TEXT at the end of .text and
right before .rodata, which appears PMD aligned as well. This will allow
.head.text to be moved into a separate output section in a subsequent
patch, without incurring more padding overhead.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/kernel/vmlinux.lds.S | 26 ++++++++++----------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 68efd8cd8bf1..c98bc91bafef 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -121,19 +121,6 @@ SECTIONS
.text : AT(ADDR(.text) - LOAD_OFFSET) {
_text = .;
_stext = .;
- /* bootstrapping code */
- HEAD_TEXT
- TEXT_TEXT
- SCHED_TEXT
- LOCK_TEXT
- KPROBES_TEXT
- SOFTIRQENTRY_TEXT
-#ifdef CONFIG_MITIGATION_RETPOLINE
- *(.text..__x86.indirect_thunk)
- *(.text..__x86.return_thunk)
-#endif
- STATIC_CALL_TEXT
-
ALIGN_ENTRY_TEXT_BEGIN
*(.text..__x86.rethunk_untrain)
ENTRY_TEXT
@@ -147,6 +134,19 @@ SECTIONS
*(.text..__x86.rethunk_safe)
#endif
ALIGN_ENTRY_TEXT_END
+
+ /* bootstrapping code */
+ HEAD_TEXT
+ TEXT_TEXT
+ SCHED_TEXT
+ LOCK_TEXT
+ KPROBES_TEXT
+ SOFTIRQENTRY_TEXT
+#ifdef CONFIG_MITIGATION_RETPOLINE
+ *(.text..__x86.indirect_thunk)
+ *(.text..__x86.return_thunk)
+#endif
+ STATIC_CALL_TEXT
*(.gnu.warning)
} :text = 0xcccccccc
--
2.47.0.371.ga323438b13-goog
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 5/6] x86/boot: Move .head.text into its own output section
2024-11-25 17:04 [PATCH v3 0/6] x86: Rid .head.text of all abs references Ard Biesheuvel
` (3 preceding siblings ...)
2024-11-25 17:04 ` [PATCH v3 4/6] x86/kernel: Move ENTRY_TEXT to the start of the image Ard Biesheuvel
@ 2024-11-25 17:04 ` Ard Biesheuvel
2024-11-25 17:04 ` [PATCH v3 6/6] x86/boot: Reject absolute references in .head.text Ard Biesheuvel
5 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2024-11-25 17:04 UTC (permalink / raw)
To: linux-kernel
Cc: x86, Ard Biesheuvel, Tom Lendacky, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, Andy Lutomirski, Arnd Bergmann,
Kees Cook, Brian Gerst, Kevin Loughlin
From: Ard Biesheuvel <ardb@kernel.org>
In order to be able to double check that vmlinux is emitted without
absolute symbol references in .head.text, it needs to be distinguishable
from the rest of .text in the ELF metadata.
So move .head.text into its own ELF section.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/kernel/vmlinux.lds.S | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index c98bc91bafef..9c194df2c8e4 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -135,8 +135,6 @@ SECTIONS
#endif
ALIGN_ENTRY_TEXT_END
- /* bootstrapping code */
- HEAD_TEXT
TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
@@ -151,6 +149,11 @@ SECTIONS
} :text = 0xcccccccc
+ /* bootstrapping code */
+ .head.text : AT(ADDR(.head.text) - LOAD_OFFSET) {
+ HEAD_TEXT
+ } :text = 0xcccccccc
+
/* End of text section, which should occupy whole number of pages */
_etext = .;
. = ALIGN(PAGE_SIZE);
--
2.47.0.371.ga323438b13-goog
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 6/6] x86/boot: Reject absolute references in .head.text
2024-11-25 17:04 [PATCH v3 0/6] x86: Rid .head.text of all abs references Ard Biesheuvel
` (4 preceding siblings ...)
2024-11-25 17:04 ` [PATCH v3 5/6] x86/boot: Move .head.text into its own output section Ard Biesheuvel
@ 2024-11-25 17:04 ` Ard Biesheuvel
5 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2024-11-25 17:04 UTC (permalink / raw)
To: linux-kernel
Cc: x86, Ard Biesheuvel, Tom Lendacky, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, Dave Hansen, Andy Lutomirski, Arnd Bergmann,
Kees Cook, Brian Gerst, Kevin Loughlin
From: Ard Biesheuvel <ardb@kernel.org>
The .head.text section used to contain asm code that bootstrapped the
page tables and switched to the kernel virtual address space before
executing C code. The asm code carefully avoided dereferencing absolute
symbol references, as those will fault before the page tables are
installed.
Today, the .head.text section contains lots of C code too, and getting
the compiler to reason about absolute addresses taken from, e.g.,
section markers such as _text[] or _end[] but never use such absolute
references to access global variables [*] is intractible.
So instead, forbid the use of absolute references in .head.text
entirely, and rely on explicit arithmetic involving VA-to-PA offsets
generated by the asm startup code to construct virtual addresses where
needed (e.g., to construct the page tables).
Note that the 'relocs' tool is only used on the core kernel image when
building a relocatable image, but this is the default, and so adding the
check there is sufficient to catch new occurrences of code that use
absolute references before the kernel mapping is up.
[*] it is feasible when using PIC codegen but there is strong pushback
to using this for all of the core kernel, and using it only for
.head.text is not straight-forward.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/tools/relocs.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index 27441e5863b2..e937be979ec8 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -841,10 +841,10 @@ static int is_percpu_sym(ElfW(Sym) *sym, const char *symname)
static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
const char *symname)
{
+ int headtext = !strcmp(sec_name(sec->shdr.sh_info), ".head.text");
unsigned r_type = ELF64_R_TYPE(rel->r_info);
ElfW(Addr) offset = rel->r_offset;
int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname);
-
if (sym->st_shndx == SHN_UNDEF)
return 0;
@@ -900,6 +900,12 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
break;
}
+ if (headtext) {
+ die("Absolute reference to symbol '%s' not permitted in .head.text\n",
+ symname);
+ break;
+ }
+
/*
* Relocation offsets for 64 bit kernels are output
* as 32 bits and sign extended back to 64 bits when
--
2.47.0.371.ga323438b13-goog
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2024-11-25 17:04 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-11-25 17:04 [PATCH v3 0/6] x86: Rid .head.text of all abs references Ard Biesheuvel
2024-11-25 17:04 ` [PATCH v3 1/6] x86/sev: Avoid WARN()s and panic()s in early boot code Ard Biesheuvel
2024-11-25 17:04 ` [PATCH v3 2/6] x86/boot/64: Determine VA/PA offset before entering C code Ard Biesheuvel
2024-11-25 17:04 ` [PATCH v3 3/6] x86/boot/64: Avoid intentional absolute symbol references in .head.text Ard Biesheuvel
2024-11-25 17:04 ` [PATCH v3 4/6] x86/kernel: Move ENTRY_TEXT to the start of the image Ard Biesheuvel
2024-11-25 17:04 ` [PATCH v3 5/6] x86/boot: Move .head.text into its own output section Ard Biesheuvel
2024-11-25 17:04 ` [PATCH v3 6/6] x86/boot: Reject absolute references in .head.text Ard Biesheuvel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®