2023-10-26 16:02:13

by Brian Gerst

[permalink] [raw]
Subject: [PATCH v2 00/11] x86-64: Stack protector and percpu improvements

Currently, x86-64 uses an unusual percpu layout, where the percpu section
is linked at absolute address 0. The reason behind this is that older GCC
versions placed the stack protector (if enabled) at a fixed offset from the
GS segment base. Since the GS segement is also used for percpu variables,
this forced the current layout.

GCC since version 8.1 supports a configurable location for the stack
protector value, which allows removal of the restriction on how the percpu
section is linked. This allows the percpu section to be linked
normally, like most other architectures. In turn, this allows removal
of code that was needed to support the zero-based percpu section.

v2:
- Include PVH boot in GSBASE changes.
- Split out removal of 64-bit test script to give full context on why
it's not needed anymore.
- Formatting and comment cleanups.

Brian Gerst (11):
x86/stackprotector/32: Remove stack protector test script
x86/stackprotector/64: Remove stack protector test script
x86/boot: Disable stack protector for early boot code
x86/pvh: Use fixed_percpu_data for early boot GSBASE
x86/stackprotector/64: Convert stack protector to normal percpu
variable
x86/percpu/64: Remove fixed_percpu_data
x86/percpu/64: Use relative percpu offsets
x86/boot/64: Remove inverse relocations
x86/percpu/64: Remove INIT_PER_CPU macros
percpu: Remove PER_CPU_FIRST_SECTION
kallsyms: Remove KALLSYMS_ABSOLUTE_PERCPU

arch/x86/Kconfig | 7 +-
arch/x86/Makefile | 19 +--
arch/x86/boot/compressed/misc.c | 14 +--
arch/x86/entry/entry_64.S | 2 +-
arch/x86/include/asm/percpu.h | 22 ----
arch/x86/include/asm/processor.h | 28 +----
arch/x86/include/asm/stackprotector.h | 37 ++----
arch/x86/kernel/Makefile | 2 +
arch/x86/kernel/asm-offsets_64.c | 6 -
arch/x86/kernel/cpu/common.c | 8 +-
arch/x86/kernel/head_64.S | 10 +-
arch/x86/kernel/irq_64.c | 1 -
arch/x86/kernel/setup_percpu.c | 12 +-
arch/x86/kernel/vmlinux.lds.S | 35 ------
arch/x86/platform/pvh/head.S | 4 +-
arch/x86/tools/relocs.c | 136 +---------------------
arch/x86/xen/xen-head.S | 6 +-
include/asm-generic/vmlinux.lds.h | 1 -
include/linux/percpu-defs.h | 12 --
init/Kconfig | 11 +-
kernel/kallsyms.c | 12 +-
scripts/gcc-x86_32-has-stack-protector.sh | 8 --
scripts/gcc-x86_64-has-stack-protector.sh | 4 -
scripts/kallsyms.c | 80 +++----------
scripts/link-vmlinux.sh | 4 -
25 files changed, 61 insertions(+), 420 deletions(-)
delete mode 100755 scripts/gcc-x86_32-has-stack-protector.sh
delete mode 100755 scripts/gcc-x86_64-has-stack-protector.sh

--
2.41.0


2023-10-26 16:02:18

by Brian Gerst

[permalink] [raw]
Subject: [PATCH v2 05/11] x86/stackprotector/64: Convert stack protector to normal percpu variable

Older versions of GCC fixed the location of the stack protector canary
at %gs:40. This constraint forced the percpu section to be linked at
virtual address 0 so that the canary could be the first data object in
the percpu section. Supporting the zero-based percpu section requires
additional code to handle relocations for RIP-relative references to
percpu data, extra complexity to kallsyms, and workarounds for linker
bugs due to the use of absolute symbols.

Since version 8.1, GCC has options to configure the location of the
canary value. This allows the canary to be turned into a normal
percpu variable and removes the constraint that the percpu section
be zero-based.

Signed-off-by: Brian Gerst <[email protected]>
---
arch/x86/Kconfig | 5 ++--
arch/x86/Makefile | 19 +++++++++-----
arch/x86/entry/entry_64.S | 2 +-
arch/x86/include/asm/processor.h | 15 +----------
arch/x86/include/asm/stackprotector.h | 37 +++++----------------------
arch/x86/kernel/asm-offsets_64.c | 6 -----
arch/x86/kernel/cpu/common.c | 4 +--
arch/x86/kernel/head_64.S | 3 +--
arch/x86/xen/xen-head.S | 3 +--
9 files changed, 26 insertions(+), 68 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 92144c6f26d2..c95e0ce557da 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -410,12 +410,11 @@ config PGTABLE_LEVELS

config CC_HAS_SANE_STACKPROTECTOR
bool
- default y if 64BIT
+ default $(cc-option,-mstack-protector-guard-reg=gs -mstack-protector-guard-symbol=__stack_chk_guard) if 64BIT
default $(cc-option,-mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard)
help
We have to make sure stack protector is unconditionally disabled if
- the compiler produces broken code or if it does not let us control
- the segment on 32-bit kernels.
+ the compiler does not allow control of the segment and symbol.

menu "Processor type and features"

diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 22e41d9dbc23..6ab8b4419f41 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -111,13 +111,7 @@ ifeq ($(CONFIG_X86_32),y)
# temporary until string.h is fixed
KBUILD_CFLAGS += -ffreestanding

- ifeq ($(CONFIG_STACKPROTECTOR),y)
- ifeq ($(CONFIG_SMP),y)
- KBUILD_CFLAGS += -mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard
- else
- KBUILD_CFLAGS += -mstack-protector-guard=global
- endif
- endif
+ percpu_seg := fs
else
BITS := 64
UTS_MACHINE := x86_64
@@ -167,6 +161,17 @@ else
KBUILD_CFLAGS += -mcmodel=kernel
KBUILD_RUSTFLAGS += -Cno-redzone=y
KBUILD_RUSTFLAGS += -Ccode-model=kernel
+
+ percpu_seg := gs
+endif
+
+ifeq ($(CONFIG_STACKPROTECTOR),y)
+ ifeq ($(CONFIG_SMP),y)
+ KBUILD_CFLAGS += -mstack-protector-guard-reg=$(percpu_seg)
+ KBUILD_CFLAGS += -mstack-protector-guard-symbol=__stack_chk_guard
+ else
+ KBUILD_CFLAGS += -mstack-protector-guard=global
+ endif
endif

#
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index 1a88ad8a7b48..cddcc236aaae 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -190,7 +190,7 @@ SYM_FUNC_START(__switch_to_asm)

#ifdef CONFIG_STACKPROTECTOR
movq TASK_stack_canary(%rsi), %rbx
- movq %rbx, PER_CPU_VAR(fixed_percpu_data + FIXED_stack_canary)
+ movq %rbx, PER_CPU_VAR(__stack_chk_guard)
#endif

/*
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 4b130d894cb6..2b6531d90273 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -394,16 +394,7 @@ struct irq_stack {

#ifdef CONFIG_X86_64
struct fixed_percpu_data {
- /*
- * GCC hardcodes the stack canary as %gs:40. Since the
- * irq_stack is the object at %gs:0, we reserve the bottom
- * 48 bytes of the irq stack for the canary.
- *
- * Once we are willing to require -mstack-protector-guard-symbol=
- * support for x86_64 stackprotector, we can get rid of this.
- */
char gs_base[40];
- unsigned long stack_canary;
};

DECLARE_PER_CPU_FIRST(struct fixed_percpu_data, fixed_percpu_data) __visible;
@@ -418,11 +409,7 @@ extern asmlinkage void entry_SYSCALL32_ignore(void);

/* Save actual FS/GS selectors and bases to current->thread */
void current_save_fsgs(void);
-#else /* X86_64 */
-#ifdef CONFIG_STACKPROTECTOR
-DECLARE_PER_CPU(unsigned long, __stack_chk_guard);
-#endif
-#endif /* !X86_64 */
+#endif /* X86_64 */

struct perf_event;

diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h
index 00473a650f51..33abbd29ea26 100644
--- a/arch/x86/include/asm/stackprotector.h
+++ b/arch/x86/include/asm/stackprotector.h
@@ -2,26 +2,13 @@
/*
* GCC stack protector support.
*
- * Stack protector works by putting predefined pattern at the start of
+ * Stack protector works by putting a predefined pattern at the start of
* the stack frame and verifying that it hasn't been overwritten when
- * returning from the function. The pattern is called stack canary
- * and unfortunately gcc historically required it to be at a fixed offset
- * from the percpu segment base. On x86_64, the offset is 40 bytes.
+ * returning from the function. The pattern is called the stack canary
+ * and is a unique value for each task.
*
- * The same segment is shared by percpu area and stack canary. On
- * x86_64, percpu symbols are zero based and %gs (64-bit) points to the
- * base of percpu area. The first occupant of the percpu area is always
- * fixed_percpu_data which contains stack_canary at the appropriate
- * offset. On x86_32, the stack canary is just a regular percpu
- * variable.
- *
- * Putting percpu data in %fs on 32-bit is a minor optimization compared to
- * using %gs. Since 32-bit userspace normally has %fs == 0, we are likely
- * to load 0 into %fs on exit to usermode, whereas with percpu data in
- * %gs, we are likely to load a non-null %gs on return to user mode.
- *
- * Once we are willing to require GCC 8.1 or better for 64-bit stackprotector
- * support, we can remove some of this complexity.
+ * GCC is configured to read the stack canary value from the __stack_chk_guard
+ * per-cpu variable, which is changed on task switch.
*/

#ifndef _ASM_STACKPROTECTOR_H
@@ -36,6 +23,8 @@

#include <linux/sched.h>

+DECLARE_PER_CPU(unsigned long, __stack_chk_guard);
+
/*
* Initialize the stackprotector canary value.
*
@@ -51,25 +40,13 @@ static __always_inline void boot_init_stack_canary(void)
{
unsigned long canary = get_random_canary();

-#ifdef CONFIG_X86_64
- BUILD_BUG_ON(offsetof(struct fixed_percpu_data, stack_canary) != 40);
-#endif
-
current->stack_canary = canary;
-#ifdef CONFIG_X86_64
- this_cpu_write(fixed_percpu_data.stack_canary, canary);
-#else
this_cpu_write(__stack_chk_guard, canary);
-#endif
}

static inline void cpu_init_stack_canary(int cpu, struct task_struct *idle)
{
-#ifdef CONFIG_X86_64
- per_cpu(fixed_percpu_data.stack_canary, cpu) = idle->stack_canary;
-#else
per_cpu(__stack_chk_guard, cpu) = idle->stack_canary;
-#endif
}

#else /* STACKPROTECTOR */
diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c
index bb65371ea9df..590b6cd0eac0 100644
--- a/arch/x86/kernel/asm-offsets_64.c
+++ b/arch/x86/kernel/asm-offsets_64.c
@@ -54,11 +54,5 @@ int main(void)
BLANK();
#undef ENTRY

- BLANK();
-
-#ifdef CONFIG_STACKPROTECTOR
- OFFSET(FIXED_stack_canary, fixed_percpu_data, stack_canary);
- BLANK();
-#endif
return 0;
}
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 9058da9ae011..fb8f0371ffc3 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -2104,15 +2104,13 @@ void syscall_init(void)
X86_EFLAGS_AC|X86_EFLAGS_ID);
}

-#else /* CONFIG_X86_64 */
+#endif /* CONFIG_X86_64 */

#ifdef CONFIG_STACKPROTECTOR
DEFINE_PER_CPU(unsigned long, __stack_chk_guard);
EXPORT_PER_CPU_SYMBOL(__stack_chk_guard);
#endif

-#endif /* CONFIG_X86_64 */
-
/*
* Clear all 6 debug registers:
*/
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 3dcabbc49149..0d94d2a091fe 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -345,8 +345,7 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL)

/* Set up %gs.
*
- * The base of %gs always points to fixed_percpu_data. If the
- * stack protector canary is enabled, it is located at %gs:40.
+ * The base of %gs always points to fixed_percpu_data.
* Note that, on SMP, the boot cpu uses init data section until
* the per cpu areas are set up.
*/
diff --git a/arch/x86/xen/xen-head.S b/arch/x86/xen/xen-head.S
index a0ea285878db..30f27e757354 100644
--- a/arch/x86/xen/xen-head.S
+++ b/arch/x86/xen/xen-head.S
@@ -53,8 +53,7 @@ SYM_CODE_START(startup_xen)

/* Set up %gs.
*
- * The base of %gs always points to fixed_percpu_data. If the
- * stack protector canary is enabled, it is located at %gs:40.
+ * The base of %gs always points to fixed_percpu_data.
* Note that, on SMP, the boot cpu uses init data section until
* the per cpu areas are set up.
*/
--
2.41.0

2023-10-26 16:02:28

by Brian Gerst

[permalink] [raw]
Subject: [PATCH v2 02/11] x86/stackprotector/64: Remove stack protector test script

This test for the stack protector was added in 2006 to make sure the
compiler had the PR28281 patch applied. With GCC 5.1 being the minimum
supported compiler now, it is no longer necessary.

Signed-off-by: Brian Gerst <[email protected]>
---
arch/x86/Kconfig | 2 +-
scripts/gcc-x86_64-has-stack-protector.sh | 4 ----
2 files changed, 1 insertion(+), 5 deletions(-)
delete mode 100755 scripts/gcc-x86_64-has-stack-protector.sh

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 039872be1630..92144c6f26d2 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -410,7 +410,7 @@ config PGTABLE_LEVELS

config CC_HAS_SANE_STACKPROTECTOR
bool
- default $(success,$(srctree)/scripts/gcc-x86_64-has-stack-protector.sh $(CC) $(CLANG_FLAGS)) if 64BIT
+ default y if 64BIT
default $(cc-option,-mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard)
help
We have to make sure stack protector is unconditionally disabled if
diff --git a/scripts/gcc-x86_64-has-stack-protector.sh b/scripts/gcc-x86_64-has-stack-protector.sh
deleted file mode 100755
index 75e4e22b986a..000000000000
--- a/scripts/gcc-x86_64-has-stack-protector.sh
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-
-echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -m64 -O0 -mcmodel=kernel -fno-PIE -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
--
2.41.0

2023-10-26 16:02:33

by Brian Gerst

[permalink] [raw]
Subject: [PATCH v2 06/11] x86/percpu/64: Remove fixed_percpu_data

Now that the stack protector canary value is a normal percpu variable,
fixed_percpu_data is unused and can be removed.

Signed-off-by: Brian Gerst <[email protected]>
---
arch/x86/include/asm/processor.h | 13 +++++--------
arch/x86/kernel/cpu/common.c | 4 ----
arch/x86/kernel/head_64.S | 11 ++++++-----
arch/x86/kernel/vmlinux.lds.S | 6 ------
arch/x86/platform/pvh/head.S | 7 ++++++-
arch/x86/tools/relocs.c | 1 -
arch/x86/xen/xen-head.S | 11 ++++++++---
7 files changed, 25 insertions(+), 28 deletions(-)

diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 2b6531d90273..d5a4044dba8f 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -393,16 +393,13 @@ struct irq_stack {
} __aligned(IRQ_STACK_SIZE);

#ifdef CONFIG_X86_64
-struct fixed_percpu_data {
- char gs_base[40];
-};
-
-DECLARE_PER_CPU_FIRST(struct fixed_percpu_data, fixed_percpu_data) __visible;
-DECLARE_INIT_PER_CPU(fixed_percpu_data);
-
static inline unsigned long cpu_kernelmode_gs_base(int cpu)
{
- return (unsigned long)per_cpu(fixed_percpu_data.gs_base, cpu);
+#ifdef CONFIG_SMP
+ return per_cpu_offset(cpu);
+#else
+ return 0;
+#endif
}

extern asmlinkage void entry_SYSCALL32_ignore(void);
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index fb8f0371ffc3..32ae76cf4508 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -2052,10 +2052,6 @@ EXPORT_PER_CPU_SYMBOL(pcpu_hot);
EXPORT_PER_CPU_SYMBOL(const_pcpu_hot);

#ifdef CONFIG_X86_64
-DEFINE_PER_CPU_FIRST(struct fixed_percpu_data,
- fixed_percpu_data) __aligned(PAGE_SIZE) __visible;
-EXPORT_PER_CPU_SYMBOL_GPL(fixed_percpu_data);
-
static void wrmsrl_cstar(unsigned long val)
{
/*
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 0d94d2a091fe..f2453eb38417 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -72,9 +72,14 @@ SYM_CODE_START_NOALIGN(startup_64)

/* Setup GSBASE to allow stack canary access for C code */
movl $MSR_GS_BASE, %ecx
- leaq INIT_PER_CPU_VAR(fixed_percpu_data)(%rip), %rdx
+#ifdef CONFIG_SMP
+ leaq __per_cpu_load(%rip), %rdx
movl %edx, %eax
shrq $32, %rdx
+#else
+ xorl %eax, %eax
+ xorl %edx, %edx
+#endif
wrmsr

call startup_64_setup_env
@@ -345,14 +350,10 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL)

/* Set up %gs.
*
- * The base of %gs always points to fixed_percpu_data.
* Note that, on SMP, the boot cpu uses init data section until
* the per cpu areas are set up.
*/
movl $MSR_GS_BASE,%ecx
-#ifndef CONFIG_SMP
- leaq INIT_PER_CPU_VAR(fixed_percpu_data)(%rip), %rdx
-#endif
movl %edx, %eax
shrq $32, %rdx
wrmsr
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 1239be7cc8d8..e6126cd21615 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -510,14 +510,8 @@ SECTIONS
*/
#define INIT_PER_CPU(x) init_per_cpu__##x = ABSOLUTE(x) + __per_cpu_load
INIT_PER_CPU(gdt_page);
-INIT_PER_CPU(fixed_percpu_data);
INIT_PER_CPU(irq_stack_backing_store);

-#ifdef CONFIG_SMP
-. = ASSERT((fixed_percpu_data == 0),
- "fixed_percpu_data is not at start of per-cpu area");
-#endif
-
#ifdef CONFIG_CPU_UNRET_ENTRY
. = ASSERT((retbleed_return_thunk & 0x3f) == 0, "retbleed_return_thunk not cacheline-aligned");
#endif
diff --git a/arch/x86/platform/pvh/head.S b/arch/x86/platform/pvh/head.S
index be8d973c0528..d215b16bf89f 100644
--- a/arch/x86/platform/pvh/head.S
+++ b/arch/x86/platform/pvh/head.S
@@ -96,9 +96,14 @@ SYM_CODE_START_LOCAL(pvh_start_xen)
1:
/* Set base address in stack canary descriptor. */
mov $MSR_GS_BASE,%ecx
- lea INIT_PER_CPU_VAR(fixed_percpu_data)(%rip), %rdx
+#ifdef CONFIG_SMP
+ lea __per_cpu_load(%rip), %rdx
mov %edx, %eax
shr $32, %rdx
+#else
+ xor %eax, %eax
+ xor %edx, %edx
+#endif
wrmsr

call xen_prepare_pvh
diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index d30949e25ebd..3ccd9d4fcf9c 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -811,7 +811,6 @@ static void percpu_init(void)
* __per_cpu_load
*
* The "gold" linker incorrectly associates:
- * init_per_cpu__fixed_percpu_data
* init_per_cpu__gdt_page
*/
static int is_percpu_sym(ElfW(Sym) *sym, const char *symname)
diff --git a/arch/x86/xen/xen-head.S b/arch/x86/xen/xen-head.S
index 30f27e757354..9ce0d9d268bb 100644
--- a/arch/x86/xen/xen-head.S
+++ b/arch/x86/xen/xen-head.S
@@ -53,13 +53,18 @@ SYM_CODE_START(startup_xen)

/* Set up %gs.
*
- * The base of %gs always points to fixed_percpu_data.
* Note that, on SMP, the boot cpu uses init data section until
* the per cpu areas are set up.
*/
movl $MSR_GS_BASE,%ecx
- movq $INIT_PER_CPU_VAR(fixed_percpu_data),%rax
- cdq
+#ifdef CONFIG_SMP
+ leaq __per_cpu_load(%rip), %rdx
+ movl %edx, %eax
+ shrq $32, %rdx
+#else
+ xorl %eax, %eax
+ xorl %edx, %edx
+#endif
wrmsr

mov %rsi, %rdi
--
2.41.0

2023-10-26 16:02:34

by Brian Gerst

[permalink] [raw]
Subject: [PATCH v2 09/11] x86/percpu/64: Remove INIT_PER_CPU macros

The load and link addresses of percpu variables are now the same, so
these macros are no longer necessary.

Signed-off-by: Brian Gerst <[email protected]>
---
arch/x86/include/asm/percpu.h | 22 ----------------------
arch/x86/kernel/irq_64.c | 1 -
arch/x86/kernel/vmlinux.lds.S | 7 -------
arch/x86/tools/relocs.c | 1 -
4 files changed, 31 deletions(-)

diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h
index b86b27d15e52..7a176381ee01 100644
--- a/arch/x86/include/asm/percpu.h
+++ b/arch/x86/include/asm/percpu.h
@@ -20,12 +20,6 @@

#define PER_CPU_VAR(var) __percpu(var)__percpu_rel

-#ifdef CONFIG_X86_64_SMP
-#define INIT_PER_CPU_VAR(var) init_per_cpu__##var
-#else
-#define INIT_PER_CPU_VAR(var) var
-#endif
-
#else /* ...!ASSEMBLY */

#include <linux/kernel.h>
@@ -96,22 +90,6 @@
#define __percpu_arg(x) __percpu_prefix "%" #x
#define __force_percpu_arg(x) __force_percpu_prefix "%" #x

-/*
- * Initialized pointers to per-cpu variables needed for the boot
- * processor need to use these macros to get the proper address
- * offset from __per_cpu_load on SMP.
- *
- * There also must be an entry in vmlinux_64.lds.S
- */
-#define DECLARE_INIT_PER_CPU(var) \
- extern typeof(var) init_per_cpu_var(var)
-
-#ifdef CONFIG_X86_64_SMP
-#define init_per_cpu_var(var) init_per_cpu__##var
-#else
-#define init_per_cpu_var(var) var
-#endif
-
/* For arch-specific code, we can use direct single-insn ops (they
* don't give an lvalue though). */

diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c
index fe0c859873d1..30424f9876bc 100644
--- a/arch/x86/kernel/irq_64.c
+++ b/arch/x86/kernel/irq_64.c
@@ -26,7 +26,6 @@
#include <asm/apic.h>

DEFINE_PER_CPU_PAGE_ALIGNED(struct irq_stack, irq_stack_backing_store) __visible;
-DECLARE_INIT_PER_CPU(irq_stack_backing_store);

#ifdef CONFIG_VMAP_STACK
/*
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index efa4885060b5..9aea7b6b02c7 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -482,13 +482,6 @@ SECTIONS
"kernel image bigger than KERNEL_IMAGE_SIZE");

#ifdef CONFIG_X86_64
-/*
- * Per-cpu symbols which need to be offset from __per_cpu_load
- * for the boot processor.
- */
-#define INIT_PER_CPU(x) init_per_cpu__##x = ABSOLUTE(x)
-INIT_PER_CPU(gdt_page);
-INIT_PER_CPU(irq_stack_backing_store);

#ifdef CONFIG_CPU_UNRET_ENTRY
. = ASSERT((retbleed_return_thunk & 0x3f) == 0, "retbleed_return_thunk not cacheline-aligned");
diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index 7feb63179b62..931d90aa814c 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -83,7 +83,6 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
"__initramfs_start|"
"(jiffies|jiffies_64)|"
#if ELF_BITS == 64
- "init_per_cpu__.*|"
"__end_rodata_hpage_align|"
#endif
"__vvar_page|"
--
2.41.0

2023-10-26 16:02:35

by Brian Gerst

[permalink] [raw]
Subject: [PATCH v2 03/11] x86/boot: Disable stack protector for early boot code

On 64-bit, this will prevent crashes when the canary access is changed
from %gs:40 to %gs:__stack_chk_guard(%rip). RIP-relative addresses from
the identity-mapped early boot code will target the wrong address with
zero-based percpu. KASLR could then shift that address to an unmapped
page causing a crash on boot.

This early boot code runs well before userspace is active and does not
need stack protector enabled.

Signed-off-by: Brian Gerst <[email protected]>
---
arch/x86/kernel/Makefile | 2 ++
1 file changed, 2 insertions(+)

diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 0000325ab98f..aff619054e17 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -39,6 +39,8 @@ KMSAN_SANITIZE_nmi.o := n
KCOV_INSTRUMENT_head$(BITS).o := n
KCOV_INSTRUMENT_sev.o := n

+CFLAGS_head32.o := -fno-stack-protector
+CFLAGS_head64.o := -fno-stack-protector
CFLAGS_irq.o := -I $(srctree)/$(src)/../include/asm/trace

obj-y += head_$(BITS).o
--
2.41.0

2023-10-26 16:02:40

by Brian Gerst

[permalink] [raw]
Subject: [PATCH v2 11/11] kallsyms: Remove KALLSYMS_ABSOLUTE_PERCPU

x86-64 was the only user.

Signed-off-by: Brian Gerst <[email protected]>
---
init/Kconfig | 11 +-----
kernel/kallsyms.c | 12 ++-----
scripts/kallsyms.c | 80 ++++++++---------------------------------
scripts/link-vmlinux.sh | 4 ---
4 files changed, 18 insertions(+), 89 deletions(-)

diff --git a/init/Kconfig b/init/Kconfig
index 1af31b23e376..4d91c5632aaf 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1715,11 +1715,6 @@ config KALLSYMS_ALL

Say N unless you really need all symbols, or kernel live patching.

-config KALLSYMS_ABSOLUTE_PERCPU
- bool
- depends on KALLSYMS
- default n
-
config KALLSYMS_BASE_RELATIVE
bool
depends on KALLSYMS
@@ -1727,11 +1722,7 @@ config KALLSYMS_BASE_RELATIVE
help
Instead of emitting them as absolute values in the native word size,
emit the symbol references in the kallsyms table as 32-bit entries,
- each containing a relative value in the range [base, base + U32_MAX]
- or, when KALLSYMS_ABSOLUTE_PERCPU is in effect, each containing either
- an absolute value in the range [0, S32_MAX] or a relative value in the
- range [base, base + S32_MAX], where base is the lowest relative symbol
- address encountered in the image.
+ each containing a relative value in the range [base, base + U32_MAX].

On 64-bit builds, this reduces the size of the address table by 50%,
but more importantly, it results in entries whose values are build
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index 18edd57b5fe8..f4e8e531052a 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -151,16 +151,8 @@ unsigned long kallsyms_sym_address(int idx)
if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))
return kallsyms_addresses[idx];

- /* values are unsigned offsets if --absolute-percpu is not in effect */
- if (!IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU))
- return kallsyms_relative_base + (u32)kallsyms_offsets[idx];
-
- /* ...otherwise, positive offsets are absolute values */
- if (kallsyms_offsets[idx] >= 0)
- return kallsyms_offsets[idx];
-
- /* ...and negative offsets are relative to kallsyms_relative_base - 1 */
- return kallsyms_relative_base - 1 - kallsyms_offsets[idx];
+ /* values are unsigned offsets */
+ return kallsyms_relative_base + (u32)kallsyms_offsets[idx];
}

static void cleanup_symbol_name(char *s)
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 653b92f6d4c8..501f978abf4b 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -5,8 +5,8 @@
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
- * Usage: kallsyms [--all-symbols] [--absolute-percpu]
- * [--base-relative] [--lto-clang] in.map > out.S
+ * Usage: kallsyms [--all-symbols] [--base-relative] [--lto-clang]
+ * in.map > out.S
*
* Table compression uses all the unused char codes on the symbols and
* maps these to the most used substrings (tokens). For instance, it might
@@ -37,7 +37,6 @@ struct sym_entry {
unsigned int len;
unsigned int seq;
unsigned int start_pos;
- unsigned int percpu_absolute;
unsigned char sym[];
};

@@ -55,14 +54,9 @@ static struct addr_range text_ranges[] = {
#define text_range_text (&text_ranges[0])
#define text_range_inittext (&text_ranges[1])

-static struct addr_range percpu_range = {
- "__per_cpu_start", "__per_cpu_end", -1ULL, 0
-};
-
static struct sym_entry **table;
static unsigned int table_size, table_cnt;
static int all_symbols;
-static int absolute_percpu;
static int base_relative;
static int lto_clang;

@@ -75,7 +69,7 @@ static unsigned char best_table_len[256];

static void usage(void)
{
- fprintf(stderr, "Usage: kallsyms [--all-symbols] [--absolute-percpu] "
+ fprintf(stderr, "Usage: kallsyms [--all-symbols] "
"[--base-relative] [--lto-clang] in.map > out.S\n");
exit(1);
}
@@ -167,7 +161,6 @@ static struct sym_entry *read_symbol(FILE *in, char **buf, size_t *buf_len)
return NULL;

check_symbol_range(name, addr, text_ranges, ARRAY_SIZE(text_ranges));
- check_symbol_range(name, addr, &percpu_range, 1);

/* include the type field in the symbol name, so that it gets
* compressed together */
@@ -183,7 +176,6 @@ static struct sym_entry *read_symbol(FILE *in, char **buf, size_t *buf_len)
sym->len = len;
sym->sym[0] = type;
strcpy(sym_name(sym), name);
- sym->percpu_absolute = 0;

return sym;
}
@@ -334,11 +326,6 @@ static int expand_symbol(const unsigned char *data, int len, char *result)
return total;
}

-static int symbol_absolute(const struct sym_entry *s)
-{
- return s->percpu_absolute;
-}
-
static void cleanup_symbol_name(char *s)
{
char *p;
@@ -499,30 +486,17 @@ static void write_src(void)
*/

long long offset;
- int overflow;
-
- if (!absolute_percpu) {
- offset = table[i]->addr - relative_base;
- overflow = (offset < 0 || offset > UINT_MAX);
- } else if (symbol_absolute(table[i])) {
- offset = table[i]->addr;
- overflow = (offset < 0 || offset > INT_MAX);
- } else {
- offset = relative_base - table[i]->addr - 1;
- overflow = (offset < INT_MIN || offset >= 0);
- }
- if (overflow) {
+
+ offset = table[i]->addr - relative_base;
+ if (offset < 0 || offset > UINT_MAX) {
fprintf(stderr, "kallsyms failure: "
- "%s symbol value %#llx out of range in relative mode\n",
- symbol_absolute(table[i]) ? "absolute" : "relative",
+ "symbol value %#llx out of range in relative mode\n",
table[i]->addr);
exit(EXIT_FAILURE);
}
printf("\t.long\t%#x /* %s */\n", (int)offset, table[i]->sym);
- } else if (!symbol_absolute(table[i])) {
- output_address(table[i]->addr);
} else {
- printf("\tPTR\t%#llx\n", table[i]->addr);
+ output_address(table[i]->addr);
}
}
printf("\n");
@@ -775,36 +749,15 @@ static void sort_symbols(void)
qsort(table, table_cnt, sizeof(table[0]), compare_symbols);
}

-static void make_percpus_absolute(void)
-{
- unsigned int i;
-
- for (i = 0; i < table_cnt; i++)
- if (symbol_in_range(table[i], &percpu_range, 1)) {
- /*
- * Keep the 'A' override for percpu symbols to
- * ensure consistent behavior compared to older
- * versions of this tool.
- */
- table[i]->sym[0] = 'A';
- table[i]->percpu_absolute = 1;
- }
-}
-
-/* find the minimum non-absolute symbol address */
+/* find the minimum symbol address */
static void record_relative_base(void)
{
- unsigned int i;
-
- for (i = 0; i < table_cnt; i++)
- if (!symbol_absolute(table[i])) {
- /*
- * The table is sorted by address.
- * Take the first non-absolute symbol value.
- */
- relative_base = table[i]->addr;
- return;
- }
+ /*
+ * The table is sorted by address.
+ * Take the first symbol value.
+ */
+ if (table_cnt)
+ relative_base = table[0]->addr;
}

int main(int argc, char **argv)
@@ -812,7 +765,6 @@ int main(int argc, char **argv)
while (1) {
static const struct option long_options[] = {
{"all-symbols", no_argument, &all_symbols, 1},
- {"absolute-percpu", no_argument, &absolute_percpu, 1},
{"base-relative", no_argument, &base_relative, 1},
{"lto-clang", no_argument, &lto_clang, 1},
{},
@@ -831,8 +783,6 @@ int main(int argc, char **argv)

read_map(argv[optind]);
shrink_table();
- if (absolute_percpu)
- make_percpus_absolute();
sort_symbols();
if (base_relative)
record_relative_base();
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index a432b171be82..d25b6d5de45e 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -148,10 +148,6 @@ kallsyms()
kallsymopt="${kallsymopt} --all-symbols"
fi

- if is_enabled CONFIG_KALLSYMS_ABSOLUTE_PERCPU; then
- kallsymopt="${kallsymopt} --absolute-percpu"
- fi
-
if is_enabled CONFIG_KALLSYMS_BASE_RELATIVE; then
kallsymopt="${kallsymopt} --base-relative"
fi
--
2.41.0

2023-10-26 16:02:45

by Brian Gerst

[permalink] [raw]
Subject: [PATCH v2 07/11] x86/percpu/64: Use relative percpu offsets

The percpu section is currently linked at virtual address 0, because
older compilers hardcoded the stack protector canary value at a fixed
offset from the start of the GS segment. Now that the canary is a
normal percpu variable, the percpu section can be linked normally.
This means that x86-64 will calculate percpu offsets like most other
architectures, as the delta between the initial percpu address and the
dynamically allocated memory.

Signed-off-by: Brian Gerst <[email protected]>
---
arch/x86/kernel/head_64.S | 6 ------
arch/x86/kernel/setup_percpu.c | 12 ++----------
arch/x86/kernel/vmlinux.lds.S | 24 +-----------------------
arch/x86/platform/pvh/head.S | 6 ------
arch/x86/tools/relocs.c | 10 +++-------
arch/x86/xen/xen-head.S | 6 ------
init/Kconfig | 2 +-
7 files changed, 7 insertions(+), 59 deletions(-)

diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index f2453eb38417..b35f74e58dd7 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -72,14 +72,8 @@ SYM_CODE_START_NOALIGN(startup_64)

/* Setup GSBASE to allow stack canary access for C code */
movl $MSR_GS_BASE, %ecx
-#ifdef CONFIG_SMP
- leaq __per_cpu_load(%rip), %rdx
- movl %edx, %eax
- shrq $32, %rdx
-#else
xorl %eax, %eax
xorl %edx, %edx
-#endif
wrmsr

call startup_64_setup_env
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c
index 2c97bf7b56ae..8707dd07b9ce 100644
--- a/arch/x86/kernel/setup_percpu.c
+++ b/arch/x86/kernel/setup_percpu.c
@@ -23,18 +23,10 @@
#include <asm/cpumask.h>
#include <asm/cpu.h>

-#ifdef CONFIG_X86_64
-#define BOOT_PERCPU_OFFSET ((unsigned long)__per_cpu_load)
-#else
-#define BOOT_PERCPU_OFFSET 0
-#endif
-
-DEFINE_PER_CPU_READ_MOSTLY(unsigned long, this_cpu_off) = BOOT_PERCPU_OFFSET;
+DEFINE_PER_CPU_READ_MOSTLY(unsigned long, this_cpu_off);
EXPORT_PER_CPU_SYMBOL(this_cpu_off);

-unsigned long __per_cpu_offset[NR_CPUS] __ro_after_init = {
- [0 ... NR_CPUS-1] = BOOT_PERCPU_OFFSET,
-};
+unsigned long __per_cpu_offset[NR_CPUS] __ro_after_init;
EXPORT_SYMBOL(__per_cpu_offset);

/*
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index e6126cd21615..efa4885060b5 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -103,12 +103,6 @@ const_pcpu_hot = pcpu_hot;
PHDRS {
text PT_LOAD FLAGS(5); /* R_E */
data PT_LOAD FLAGS(6); /* RW_ */
-#ifdef CONFIG_X86_64
-#ifdef CONFIG_SMP
- percpu PT_LOAD FLAGS(6); /* RW_ */
-#endif
- init PT_LOAD FLAGS(7); /* RWE */
-#endif
note PT_NOTE FLAGS(0); /* ___ */
}

@@ -224,21 +218,7 @@ SECTIONS
__init_begin = .; /* paired with __init_end */
}

-#if defined(CONFIG_X86_64) && defined(CONFIG_SMP)
- /*
- * percpu offsets are zero-based on SMP. PERCPU_VADDR() changes the
- * output PHDR, so the next output section - .init.text - should
- * start another segment - init.
- */
- PERCPU_VADDR(INTERNODE_CACHE_BYTES, 0, :percpu)
- ASSERT(SIZEOF(.data..percpu) < CONFIG_PHYSICAL_START,
- "per-CPU data too large - increase CONFIG_PHYSICAL_START")
-#endif
-
INIT_TEXT_SECTION(PAGE_SIZE)
-#ifdef CONFIG_X86_64
- :init
-#endif

/*
* Section for code used exclusively before alternatives are run. All
@@ -368,9 +348,7 @@ SECTIONS
EXIT_DATA
}

-#if !defined(CONFIG_X86_64) || !defined(CONFIG_SMP)
PERCPU_SECTION(INTERNODE_CACHE_BYTES)
-#endif

. = ALIGN(PAGE_SIZE);

@@ -508,7 +486,7 @@ SECTIONS
* Per-cpu symbols which need to be offset from __per_cpu_load
* for the boot processor.
*/
-#define INIT_PER_CPU(x) init_per_cpu__##x = ABSOLUTE(x) + __per_cpu_load
+#define INIT_PER_CPU(x) init_per_cpu__##x = ABSOLUTE(x)
INIT_PER_CPU(gdt_page);
INIT_PER_CPU(irq_stack_backing_store);

diff --git a/arch/x86/platform/pvh/head.S b/arch/x86/platform/pvh/head.S
index d215b16bf89f..4bd925b23436 100644
--- a/arch/x86/platform/pvh/head.S
+++ b/arch/x86/platform/pvh/head.S
@@ -96,14 +96,8 @@ SYM_CODE_START_LOCAL(pvh_start_xen)
1:
/* Set base address in stack canary descriptor. */
mov $MSR_GS_BASE,%ecx
-#ifdef CONFIG_SMP
- lea __per_cpu_load(%rip), %rdx
- mov %edx, %eax
- shr $32, %rdx
-#else
xor %eax, %eax
xor %edx, %edx
-#endif
wrmsr

call xen_prepare_pvh
diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index 3ccd9d4fcf9c..01efbfdd3eb3 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -815,12 +815,7 @@ static void percpu_init(void)
*/
static int is_percpu_sym(ElfW(Sym) *sym, const char *symname)
{
- int shndx = sym_index(sym);
-
- return (shndx == per_cpu_shndx) &&
- strcmp(symname, "__init_begin") &&
- strcmp(symname, "__per_cpu_load") &&
- strncmp(symname, "init_per_cpu_", 13);
+ return 0;
}


@@ -1043,7 +1038,8 @@ static int cmp_relocs(const void *va, const void *vb)

static void sort_relocs(struct relocs *r)
{
- qsort(r->offset, r->count, sizeof(r->offset[0]), cmp_relocs);
+ if (r->count)
+ qsort(r->offset, r->count, sizeof(r->offset[0]), cmp_relocs);
}

static int write32(uint32_t v, FILE *f)
diff --git a/arch/x86/xen/xen-head.S b/arch/x86/xen/xen-head.S
index 9ce0d9d268bb..c1d9c92b417a 100644
--- a/arch/x86/xen/xen-head.S
+++ b/arch/x86/xen/xen-head.S
@@ -57,14 +57,8 @@ SYM_CODE_START(startup_xen)
* the per cpu areas are set up.
*/
movl $MSR_GS_BASE,%ecx
-#ifdef CONFIG_SMP
- leaq __per_cpu_load(%rip), %rdx
- movl %edx, %eax
- shrq $32, %rdx
-#else
xorl %eax, %eax
xorl %edx, %edx
-#endif
wrmsr

mov %rsi, %rdi
diff --git a/init/Kconfig b/init/Kconfig
index 6d35728b94b2..1af31b23e376 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1718,7 +1718,7 @@ config KALLSYMS_ALL
config KALLSYMS_ABSOLUTE_PERCPU
bool
depends on KALLSYMS
- default X86_64 && SMP
+ default n

config KALLSYMS_BASE_RELATIVE
bool
--
2.41.0

2023-10-26 16:03:22

by Brian Gerst

[permalink] [raw]
Subject: [PATCH v2 01/11] x86/stackprotector/32: Remove stack protector test script

Test for compiler support directly in Kconfig.

Signed-off-by: Brian Gerst <[email protected]>
---
arch/x86/Kconfig | 2 +-
scripts/gcc-x86_32-has-stack-protector.sh | 8 --------
2 files changed, 1 insertion(+), 9 deletions(-)
delete mode 100755 scripts/gcc-x86_32-has-stack-protector.sh

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 5ef081aa12ac..039872be1630 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -411,7 +411,7 @@ config PGTABLE_LEVELS
config CC_HAS_SANE_STACKPROTECTOR
bool
default $(success,$(srctree)/scripts/gcc-x86_64-has-stack-protector.sh $(CC) $(CLANG_FLAGS)) if 64BIT
- default $(success,$(srctree)/scripts/gcc-x86_32-has-stack-protector.sh $(CC) $(CLANG_FLAGS))
+ default $(cc-option,-mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard)
help
We have to make sure stack protector is unconditionally disabled if
the compiler produces broken code or if it does not let us control
diff --git a/scripts/gcc-x86_32-has-stack-protector.sh b/scripts/gcc-x86_32-has-stack-protector.sh
deleted file mode 100755
index 825c75c5b715..000000000000
--- a/scripts/gcc-x86_32-has-stack-protector.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-
-# This requires GCC 8.1 or better. Specifically, we require
-# -mstack-protector-guard-reg, added by
-# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81708
-
-echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -m32 -O0 -fstack-protector -mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard - -o - 2> /dev/null | grep -q "%fs"
--
2.41.0

2023-10-26 16:03:28

by Brian Gerst

[permalink] [raw]
Subject: [PATCH v2 10/11] percpu: Remove PER_CPU_FIRST_SECTION

x86-64 was the only user.

Signed-off-by: Brian Gerst <[email protected]>
---
include/asm-generic/vmlinux.lds.h | 1 -
include/linux/percpu-defs.h | 12 ------------
2 files changed, 13 deletions(-)

diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 67d8dd2f1bde..23d8acc72760 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -1032,7 +1032,6 @@
*/
#define PERCPU_INPUT(cacheline) \
__per_cpu_start = .; \
- *(.data..percpu..first) \
. = ALIGN(PAGE_SIZE); \
*(.data..percpu..page_aligned) \
. = ALIGN(cacheline); \
diff --git a/include/linux/percpu-defs.h b/include/linux/percpu-defs.h
index ec3573119923..b9ddee91e6c7 100644
--- a/include/linux/percpu-defs.h
+++ b/include/linux/percpu-defs.h
@@ -26,13 +26,11 @@
#define PER_CPU_SHARED_ALIGNED_SECTION "..shared_aligned"
#define PER_CPU_ALIGNED_SECTION "..shared_aligned"
#endif
-#define PER_CPU_FIRST_SECTION "..first"

#else

#define PER_CPU_SHARED_ALIGNED_SECTION ""
#define PER_CPU_ALIGNED_SECTION "..shared_aligned"
-#define PER_CPU_FIRST_SECTION ""

#endif

@@ -114,16 +112,6 @@
#define DEFINE_PER_CPU(type, name) \
DEFINE_PER_CPU_SECTION(type, name, "")

-/*
- * Declaration/definition used for per-CPU variables that must come first in
- * the set of variables.
- */
-#define DECLARE_PER_CPU_FIRST(type, name) \
- DECLARE_PER_CPU_SECTION(type, name, PER_CPU_FIRST_SECTION)
-
-#define DEFINE_PER_CPU_FIRST(type, name) \
- DEFINE_PER_CPU_SECTION(type, name, PER_CPU_FIRST_SECTION)
-
/*
* Declaration/definition used for per-CPU variables that must be cacheline
* aligned under SMP conditions so that, whilst a particular instance of the
--
2.41.0

2023-10-26 16:03:27

by Brian Gerst

[permalink] [raw]
Subject: [PATCH v2 04/11] x86/pvh: Use fixed_percpu_data for early boot GSBASE

Instead of having a private area for the stack canary, use
fixed_percpu_data for GSBASE like the native kernel.

Signed-off-by: Brian Gerst <[email protected]>
---
arch/x86/platform/pvh/head.S | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/arch/x86/platform/pvh/head.S b/arch/x86/platform/pvh/head.S
index c4365a05ab83..be8d973c0528 100644
--- a/arch/x86/platform/pvh/head.S
+++ b/arch/x86/platform/pvh/head.S
@@ -96,8 +96,9 @@ SYM_CODE_START_LOCAL(pvh_start_xen)
1:
/* Set base address in stack canary descriptor. */
mov $MSR_GS_BASE,%ecx
- mov $_pa(canary), %eax
- xor %edx, %edx
+ lea INIT_PER_CPU_VAR(fixed_percpu_data)(%rip), %rdx
+ mov %edx, %eax
+ shr $32, %rdx
wrmsr

call xen_prepare_pvh
@@ -156,8 +157,6 @@ SYM_DATA_START_LOCAL(gdt_start)
SYM_DATA_END_LABEL(gdt_start, SYM_L_LOCAL, gdt_end)

.balign 16
-SYM_DATA_LOCAL(canary, .fill 48, 1, 0)
-
SYM_DATA_START_LOCAL(early_stack)
.fill BOOT_STACK_SIZE, 1, 0
SYM_DATA_END_LABEL(early_stack, SYM_L_LOCAL, early_stack_end)
--
2.41.0

2023-10-26 16:03:48

by Brian Gerst

[permalink] [raw]
Subject: [PATCH v2 08/11] x86/boot/64: Remove inverse relocations

Now that the percpu section is not at a fixed virtual address, inverse
relocations, which were needed to offset the effects of relocation on
RIP-relative percpu references, are no longer needed.

Signed-off-by: Brian Gerst <[email protected]>
---
arch/x86/boot/compressed/misc.c | 14 +---
arch/x86/tools/relocs.c | 126 +-------------------------------
2 files changed, 2 insertions(+), 138 deletions(-)

diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index b99e08e6815b..2de345a236c0 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -221,7 +221,7 @@ static void handle_relocations(void *output, unsigned long output_len,

/*
* Process relocations: 32 bit relocations first then 64 bit after.
- * Three sets of binary relocations are added to the end of the kernel
+ * Two sets of binary relocations are added to the end of the kernel
* before compression. Each relocation table entry is the kernel
* address of the location which needs to be updated stored as a
* 32-bit value which is sign extended to 64 bits.
@@ -231,8 +231,6 @@ static void handle_relocations(void *output, unsigned long output_len,
* kernel bits...
* 0 - zero terminator for 64 bit relocations
* 64 bit relocation repeated
- * 0 - zero terminator for inverse 32 bit relocations
- * 32 bit inverse relocation repeated
* 0 - zero terminator for 32 bit relocations
* 32 bit relocation repeated
*
@@ -249,16 +247,6 @@ static void handle_relocations(void *output, unsigned long output_len,
*(uint32_t *)ptr += delta;
}
#ifdef CONFIG_X86_64
- while (*--reloc) {
- long extended = *reloc;
- extended += map;
-
- ptr = (unsigned long)extended;
- if (ptr < min_addr || ptr > max_addr)
- error("inverse 32-bit relocation outside of kernel!\n");
-
- *(int32_t *)ptr -= delta;
- }
for (reloc--; *reloc; reloc--) {
long extended = *reloc;
extended += map;
diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index 01efbfdd3eb3..7feb63179b62 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -28,7 +28,6 @@ struct relocs {
static struct relocs relocs16;
static struct relocs relocs32;
#if ELF_BITS == 64
-static struct relocs relocs32neg;
static struct relocs relocs64;
#define FMT PRIu64
#else
@@ -84,7 +83,6 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
"__initramfs_start|"
"(jiffies|jiffies_64)|"
#if ELF_BITS == 64
- "__per_cpu_load|"
"init_per_cpu__.*|"
"__end_rodata_hpage_align|"
#endif
@@ -281,33 +279,6 @@ static const char *sym_name(const char *sym_strtab, Elf_Sym *sym)
return name;
}

-static Elf_Sym *sym_lookup(const char *symname)
-{
- int i;
- for (i = 0; i < shnum; i++) {
- struct section *sec = &secs[i];
- long nsyms;
- char *strtab;
- Elf_Sym *symtab;
- Elf_Sym *sym;
-
- if (sec->shdr.sh_type != SHT_SYMTAB)
- continue;
-
- nsyms = sec->shdr.sh_size/sizeof(Elf_Sym);
- symtab = sec->symtab;
- strtab = sec->link->strtab;
-
- for (sym = symtab; --nsyms >= 0; sym++) {
- if (!sym->st_name)
- continue;
- if (strcmp(symname, strtab + sym->st_name) == 0)
- return sym;
- }
- }
- return 0;
-}
-
#if BYTE_ORDER == LITTLE_ENDIAN
#define le16_to_cpu(val) (val)
#define le32_to_cpu(val) (val)
@@ -750,75 +721,8 @@ static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel,
}
}

-/*
- * The .data..percpu section is a special case for x86_64 SMP kernels.
- * It is used to initialize the actual per_cpu areas and to provide
- * definitions for the per_cpu variables that correspond to their offsets
- * within the percpu area. Since the values of all of the symbols need
- * to be offsets from the start of the per_cpu area the virtual address
- * (sh_addr) of .data..percpu is 0 in SMP kernels.
- *
- * This means that:
- *
- * Relocations that reference symbols in the per_cpu area do not
- * need further relocation (since the value is an offset relative
- * to the start of the per_cpu area that does not change).
- *
- * Relocations that apply to the per_cpu area need to have their
- * offset adjusted by by the value of __per_cpu_load to make them
- * point to the correct place in the loaded image (because the
- * virtual address of .data..percpu is 0).
- *
- * For non SMP kernels .data..percpu is linked as part of the normal
- * kernel data and does not require special treatment.
- *
- */
-static int per_cpu_shndx = -1;
-static Elf_Addr per_cpu_load_addr;
-
-static void percpu_init(void)
-{
- int i;
- for (i = 0; i < shnum; i++) {
- ElfW(Sym) *sym;
- if (strcmp(sec_name(i), ".data..percpu"))
- continue;
-
- if (secs[i].shdr.sh_addr != 0) /* non SMP kernel */
- return;
-
- sym = sym_lookup("__per_cpu_load");
- if (!sym)
- die("can't find __per_cpu_load\n");
-
- per_cpu_shndx = i;
- per_cpu_load_addr = sym->st_value;
- return;
- }
-}
-
#if ELF_BITS == 64

-/*
- * Check to see if a symbol lies in the .data..percpu section.
- *
- * The linker incorrectly associates some symbols with the
- * .data..percpu section so we also need to check the symbol
- * name to make sure that we classify the symbol correctly.
- *
- * The GNU linker incorrectly associates:
- * __init_begin
- * __per_cpu_load
- *
- * The "gold" linker incorrectly associates:
- * init_per_cpu__gdt_page
- */
-static int is_percpu_sym(ElfW(Sym) *sym, const char *symname)
-{
- return 0;
-}
-
-
static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
const char *symname)
{
@@ -829,12 +733,6 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
if (sym->st_shndx == SHN_UNDEF)
return 0;

- /*
- * Adjust the offset if this reloc applies to the percpu section.
- */
- if (sec->shdr.sh_info == per_cpu_shndx)
- offset += per_cpu_load_addr;
-
switch (r_type) {
case R_X86_64_NONE:
/* NONE can be ignored. */
@@ -843,33 +741,21 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
case R_X86_64_PC32:
case R_X86_64_PLT32:
/*
- * PC relative relocations don't need to be adjusted unless
- * referencing a percpu symbol.
+ * PC relative relocations don't need to be adjusted.
*
* NB: R_X86_64_PLT32 can be treated as R_X86_64_PC32.
*/
- if (is_percpu_sym(sym, symname))
- add_reloc(&relocs32neg, offset);
break;

case R_X86_64_PC64:
/*
* Only used by jump labels
*/
- if (is_percpu_sym(sym, symname))
- die("Invalid R_X86_64_PC64 relocation against per-CPU symbol %s\n",
- symname);
break;

case R_X86_64_32:
case R_X86_64_32S:
case R_X86_64_64:
- /*
- * References to the percpu area don't need to be adjusted.
- */
- if (is_percpu_sym(sym, symname))
- break;
-
if (shn_abs) {
/*
* Whitelisted absolute symbols do not require
@@ -1083,7 +969,6 @@ static void emit_relocs(int as_text, int use_real_mode)
/* Order the relocations for more efficient processing */
sort_relocs(&relocs32);
#if ELF_BITS == 64
- sort_relocs(&relocs32neg);
sort_relocs(&relocs64);
#else
sort_relocs(&relocs16);
@@ -1115,13 +1000,6 @@ static void emit_relocs(int as_text, int use_real_mode)
/* Now print each relocation */
for (i = 0; i < relocs64.count; i++)
write_reloc(relocs64.offset[i], stdout);
-
- /* Print a stop */
- write_reloc(0, stdout);
-
- /* Now print each inverse 32-bit relocation */
- for (i = 0; i < relocs32neg.count; i++)
- write_reloc(relocs32neg.offset[i], stdout);
#endif

/* Print a stop */
@@ -1172,8 +1050,6 @@ void process(FILE *fp, int use_real_mode, int as_text,
read_strtabs(fp);
read_symtabs(fp);
read_relocs(fp);
- if (ELF_BITS == 64)
- percpu_init();
if (show_absolute_syms) {
print_absolute_symbols();
return;
--
2.41.0

2023-10-26 17:59:35

by Uros Bizjak

[permalink] [raw]
Subject: Re: [PATCH v2 01/11] x86/stackprotector/32: Remove stack protector test script

On Thu, Oct 26, 2023 at 6:01 PM Brian Gerst <[email protected]> wrote:
>
> Test for compiler support directly in Kconfig.
>
> Signed-off-by: Brian Gerst <[email protected]>

Reviewed-by: Uros Bizjak <[email protected]>

> ---
> arch/x86/Kconfig | 2 +-
> scripts/gcc-x86_32-has-stack-protector.sh | 8 --------
> 2 files changed, 1 insertion(+), 9 deletions(-)
> delete mode 100755 scripts/gcc-x86_32-has-stack-protector.sh
>
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 5ef081aa12ac..039872be1630 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -411,7 +411,7 @@ config PGTABLE_LEVELS
> config CC_HAS_SANE_STACKPROTECTOR
> bool
> default $(success,$(srctree)/scripts/gcc-x86_64-has-stack-protector.sh $(CC) $(CLANG_FLAGS)) if 64BIT
> - default $(success,$(srctree)/scripts/gcc-x86_32-has-stack-protector.sh $(CC) $(CLANG_FLAGS))
> + default $(cc-option,-mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard)
> help
> We have to make sure stack protector is unconditionally disabled if
> the compiler produces broken code or if it does not let us control
> diff --git a/scripts/gcc-x86_32-has-stack-protector.sh b/scripts/gcc-x86_32-has-stack-protector.sh
> deleted file mode 100755
> index 825c75c5b715..000000000000
> --- a/scripts/gcc-x86_32-has-stack-protector.sh
> +++ /dev/null
> @@ -1,8 +0,0 @@
> -#!/bin/sh
> -# SPDX-License-Identifier: GPL-2.0
> -
> -# This requires GCC 8.1 or better. Specifically, we require
> -# -mstack-protector-guard-reg, added by
> -# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81708
> -
> -echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -m32 -O0 -fstack-protector -mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard - -o - 2> /dev/null | grep -q "%fs"
> --
> 2.41.0
>

2023-10-26 18:07:09

by Uros Bizjak

[permalink] [raw]
Subject: Re: [PATCH v2 02/11] x86/stackprotector/64: Remove stack protector test script

On Thu, Oct 26, 2023 at 6:01 PM Brian Gerst <[email protected]> wrote:
>
> This test for the stack protector was added in 2006 to make sure the
> compiler had the PR28281 patch applied. With GCC 5.1 being the minimum
> supported compiler now, it is no longer necessary.
>
> Signed-off-by: Brian Gerst <[email protected]>

Reviewed-by: Uros Bizjak <[email protected]>

> ---
> arch/x86/Kconfig | 2 +-
> scripts/gcc-x86_64-has-stack-protector.sh | 4 ----
> 2 files changed, 1 insertion(+), 5 deletions(-)
> delete mode 100755 scripts/gcc-x86_64-has-stack-protector.sh
>
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 039872be1630..92144c6f26d2 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -410,7 +410,7 @@ config PGTABLE_LEVELS
>
> config CC_HAS_SANE_STACKPROTECTOR
> bool
> - default $(success,$(srctree)/scripts/gcc-x86_64-has-stack-protector.sh $(CC) $(CLANG_FLAGS)) if 64BIT
> + default y if 64BIT
> default $(cc-option,-mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard)
> help
> We have to make sure stack protector is unconditionally disabled if
> diff --git a/scripts/gcc-x86_64-has-stack-protector.sh b/scripts/gcc-x86_64-has-stack-protector.sh
> deleted file mode 100755
> index 75e4e22b986a..000000000000
> --- a/scripts/gcc-x86_64-has-stack-protector.sh
> +++ /dev/null
> @@ -1,4 +0,0 @@
> -#!/bin/sh
> -# SPDX-License-Identifier: GPL-2.0
> -
> -echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -m64 -O0 -mcmodel=kernel -fno-PIE -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
> --
> 2.41.0
>

2023-10-26 18:17:06

by Uros Bizjak

[permalink] [raw]
Subject: Re: [PATCH v2 05/11] x86/stackprotector/64: Convert stack protector to normal percpu variable

On Thu, Oct 26, 2023 at 6:01 PM Brian Gerst <[email protected]> wrote:
>
> Older versions of GCC fixed the location of the stack protector canary
> at %gs:40. This constraint forced the percpu section to be linked at
> virtual address 0 so that the canary could be the first data object in
> the percpu section. Supporting the zero-based percpu section requires
> additional code to handle relocations for RIP-relative references to
> percpu data, extra complexity to kallsyms, and workarounds for linker
> bugs due to the use of absolute symbols.
>
> Since version 8.1, GCC has options to configure the location of the
> canary value. This allows the canary to be turned into a normal
> percpu variable and removes the constraint that the percpu section
> be zero-based.
>
> Signed-off-by: Brian Gerst <[email protected]>

Reviewed-by: Uros Bizjak <[email protected]>

> ---
> arch/x86/Kconfig | 5 ++--
> arch/x86/Makefile | 19 +++++++++-----
> arch/x86/entry/entry_64.S | 2 +-
> arch/x86/include/asm/processor.h | 15 +----------
> arch/x86/include/asm/stackprotector.h | 37 +++++----------------------
> arch/x86/kernel/asm-offsets_64.c | 6 -----
> arch/x86/kernel/cpu/common.c | 4 +--
> arch/x86/kernel/head_64.S | 3 +--
> arch/x86/xen/xen-head.S | 3 +--
> 9 files changed, 26 insertions(+), 68 deletions(-)
>
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 92144c6f26d2..c95e0ce557da 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -410,12 +410,11 @@ config PGTABLE_LEVELS
>
> config CC_HAS_SANE_STACKPROTECTOR
> bool
> - default y if 64BIT
> + default $(cc-option,-mstack-protector-guard-reg=gs -mstack-protector-guard-symbol=__stack_chk_guard) if 64BIT
> default $(cc-option,-mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard)
> help
> We have to make sure stack protector is unconditionally disabled if
> - the compiler produces broken code or if it does not let us control
> - the segment on 32-bit kernels.
> + the compiler does not allow control of the segment and symbol.
>
> menu "Processor type and features"
>
> diff --git a/arch/x86/Makefile b/arch/x86/Makefile
> index 22e41d9dbc23..6ab8b4419f41 100644
> --- a/arch/x86/Makefile
> +++ b/arch/x86/Makefile
> @@ -111,13 +111,7 @@ ifeq ($(CONFIG_X86_32),y)
> # temporary until string.h is fixed
> KBUILD_CFLAGS += -ffreestanding
>
> - ifeq ($(CONFIG_STACKPROTECTOR),y)
> - ifeq ($(CONFIG_SMP),y)
> - KBUILD_CFLAGS += -mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard
> - else
> - KBUILD_CFLAGS += -mstack-protector-guard=global
> - endif
> - endif
> + percpu_seg := fs
> else
> BITS := 64
> UTS_MACHINE := x86_64
> @@ -167,6 +161,17 @@ else
> KBUILD_CFLAGS += -mcmodel=kernel
> KBUILD_RUSTFLAGS += -Cno-redzone=y
> KBUILD_RUSTFLAGS += -Ccode-model=kernel
> +
> + percpu_seg := gs
> +endif
> +
> +ifeq ($(CONFIG_STACKPROTECTOR),y)
> + ifeq ($(CONFIG_SMP),y)
> + KBUILD_CFLAGS += -mstack-protector-guard-reg=$(percpu_seg)
> + KBUILD_CFLAGS += -mstack-protector-guard-symbol=__stack_chk_guard
> + else
> + KBUILD_CFLAGS += -mstack-protector-guard=global
> + endif
> endif
>
> #
> diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
> index 1a88ad8a7b48..cddcc236aaae 100644
> --- a/arch/x86/entry/entry_64.S
> +++ b/arch/x86/entry/entry_64.S
> @@ -190,7 +190,7 @@ SYM_FUNC_START(__switch_to_asm)
>
> #ifdef CONFIG_STACKPROTECTOR
> movq TASK_stack_canary(%rsi), %rbx
> - movq %rbx, PER_CPU_VAR(fixed_percpu_data + FIXED_stack_canary)
> + movq %rbx, PER_CPU_VAR(__stack_chk_guard)
> #endif
>
> /*
> diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
> index 4b130d894cb6..2b6531d90273 100644
> --- a/arch/x86/include/asm/processor.h
> +++ b/arch/x86/include/asm/processor.h
> @@ -394,16 +394,7 @@ struct irq_stack {
>
> #ifdef CONFIG_X86_64
> struct fixed_percpu_data {
> - /*
> - * GCC hardcodes the stack canary as %gs:40. Since the
> - * irq_stack is the object at %gs:0, we reserve the bottom
> - * 48 bytes of the irq stack for the canary.
> - *
> - * Once we are willing to require -mstack-protector-guard-symbol=
> - * support for x86_64 stackprotector, we can get rid of this.
> - */
> char gs_base[40];
> - unsigned long stack_canary;
> };
>
> DECLARE_PER_CPU_FIRST(struct fixed_percpu_data, fixed_percpu_data) __visible;
> @@ -418,11 +409,7 @@ extern asmlinkage void entry_SYSCALL32_ignore(void);
>
> /* Save actual FS/GS selectors and bases to current->thread */
> void current_save_fsgs(void);
> -#else /* X86_64 */
> -#ifdef CONFIG_STACKPROTECTOR
> -DECLARE_PER_CPU(unsigned long, __stack_chk_guard);
> -#endif
> -#endif /* !X86_64 */
> +#endif /* X86_64 */
>
> struct perf_event;
>
> diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h
> index 00473a650f51..33abbd29ea26 100644
> --- a/arch/x86/include/asm/stackprotector.h
> +++ b/arch/x86/include/asm/stackprotector.h
> @@ -2,26 +2,13 @@
> /*
> * GCC stack protector support.
> *
> - * Stack protector works by putting predefined pattern at the start of
> + * Stack protector works by putting a predefined pattern at the start of
> * the stack frame and verifying that it hasn't been overwritten when
> - * returning from the function. The pattern is called stack canary
> - * and unfortunately gcc historically required it to be at a fixed offset
> - * from the percpu segment base. On x86_64, the offset is 40 bytes.
> + * returning from the function. The pattern is called the stack canary
> + * and is a unique value for each task.
> *
> - * The same segment is shared by percpu area and stack canary. On
> - * x86_64, percpu symbols are zero based and %gs (64-bit) points to the
> - * base of percpu area. The first occupant of the percpu area is always
> - * fixed_percpu_data which contains stack_canary at the appropriate
> - * offset. On x86_32, the stack canary is just a regular percpu
> - * variable.
> - *
> - * Putting percpu data in %fs on 32-bit is a minor optimization compared to
> - * using %gs. Since 32-bit userspace normally has %fs == 0, we are likely
> - * to load 0 into %fs on exit to usermode, whereas with percpu data in
> - * %gs, we are likely to load a non-null %gs on return to user mode.
> - *
> - * Once we are willing to require GCC 8.1 or better for 64-bit stackprotector
> - * support, we can remove some of this complexity.
> + * GCC is configured to read the stack canary value from the __stack_chk_guard
> + * per-cpu variable, which is changed on task switch.
> */
>
> #ifndef _ASM_STACKPROTECTOR_H
> @@ -36,6 +23,8 @@
>
> #include <linux/sched.h>
>
> +DECLARE_PER_CPU(unsigned long, __stack_chk_guard);
> +
> /*
> * Initialize the stackprotector canary value.
> *
> @@ -51,25 +40,13 @@ static __always_inline void boot_init_stack_canary(void)
> {
> unsigned long canary = get_random_canary();
>
> -#ifdef CONFIG_X86_64
> - BUILD_BUG_ON(offsetof(struct fixed_percpu_data, stack_canary) != 40);
> -#endif
> -
> current->stack_canary = canary;
> -#ifdef CONFIG_X86_64
> - this_cpu_write(fixed_percpu_data.stack_canary, canary);
> -#else
> this_cpu_write(__stack_chk_guard, canary);
> -#endif
> }
>
> static inline void cpu_init_stack_canary(int cpu, struct task_struct *idle)
> {
> -#ifdef CONFIG_X86_64
> - per_cpu(fixed_percpu_data.stack_canary, cpu) = idle->stack_canary;
> -#else
> per_cpu(__stack_chk_guard, cpu) = idle->stack_canary;
> -#endif
> }
>
> #else /* STACKPROTECTOR */
> diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c
> index bb65371ea9df..590b6cd0eac0 100644
> --- a/arch/x86/kernel/asm-offsets_64.c
> +++ b/arch/x86/kernel/asm-offsets_64.c
> @@ -54,11 +54,5 @@ int main(void)
> BLANK();
> #undef ENTRY
>
> - BLANK();
> -
> -#ifdef CONFIG_STACKPROTECTOR
> - OFFSET(FIXED_stack_canary, fixed_percpu_data, stack_canary);
> - BLANK();
> -#endif
> return 0;
> }
> diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
> index 9058da9ae011..fb8f0371ffc3 100644
> --- a/arch/x86/kernel/cpu/common.c
> +++ b/arch/x86/kernel/cpu/common.c
> @@ -2104,15 +2104,13 @@ void syscall_init(void)
> X86_EFLAGS_AC|X86_EFLAGS_ID);
> }
>
> -#else /* CONFIG_X86_64 */
> +#endif /* CONFIG_X86_64 */
>
> #ifdef CONFIG_STACKPROTECTOR
> DEFINE_PER_CPU(unsigned long, __stack_chk_guard);
> EXPORT_PER_CPU_SYMBOL(__stack_chk_guard);
> #endif
>
> -#endif /* CONFIG_X86_64 */
> -
> /*
> * Clear all 6 debug registers:
> */
> diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
> index 3dcabbc49149..0d94d2a091fe 100644
> --- a/arch/x86/kernel/head_64.S
> +++ b/arch/x86/kernel/head_64.S
> @@ -345,8 +345,7 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL)
>
> /* Set up %gs.
> *
> - * The base of %gs always points to fixed_percpu_data. If the
> - * stack protector canary is enabled, it is located at %gs:40.
> + * The base of %gs always points to fixed_percpu_data.
> * Note that, on SMP, the boot cpu uses init data section until
> * the per cpu areas are set up.
> */
> diff --git a/arch/x86/xen/xen-head.S b/arch/x86/xen/xen-head.S
> index a0ea285878db..30f27e757354 100644
> --- a/arch/x86/xen/xen-head.S
> +++ b/arch/x86/xen/xen-head.S
> @@ -53,8 +53,7 @@ SYM_CODE_START(startup_xen)
>
> /* Set up %gs.
> *
> - * The base of %gs always points to fixed_percpu_data. If the
> - * stack protector canary is enabled, it is located at %gs:40.
> + * The base of %gs always points to fixed_percpu_data.
> * Note that, on SMP, the boot cpu uses init data section until
> * the per cpu areas are set up.
> */
> --
> 2.41.0
>

2023-10-26 18:28:21

by Uros Bizjak

[permalink] [raw]
Subject: Re: [PATCH v2 06/11] x86/percpu/64: Remove fixed_percpu_data

On Thu, Oct 26, 2023 at 6:01 PM Brian Gerst <[email protected]> wrote:
>
> Now that the stack protector canary value is a normal percpu variable,
> fixed_percpu_data is unused and can be removed.
>
> Signed-off-by: Brian Gerst <[email protected]>

Reviewed-by: Uros Bizjak <[email protected]>

> ---
> arch/x86/include/asm/processor.h | 13 +++++--------
> arch/x86/kernel/cpu/common.c | 4 ----
> arch/x86/kernel/head_64.S | 11 ++++++-----
> arch/x86/kernel/vmlinux.lds.S | 6 ------
> arch/x86/platform/pvh/head.S | 7 ++++++-
> arch/x86/tools/relocs.c | 1 -
> arch/x86/xen/xen-head.S | 11 ++++++++---
> 7 files changed, 25 insertions(+), 28 deletions(-)
>
> diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
> index 2b6531d90273..d5a4044dba8f 100644
> --- a/arch/x86/include/asm/processor.h
> +++ b/arch/x86/include/asm/processor.h
> @@ -393,16 +393,13 @@ struct irq_stack {
> } __aligned(IRQ_STACK_SIZE);
>
> #ifdef CONFIG_X86_64
> -struct fixed_percpu_data {
> - char gs_base[40];
> -};
> -
> -DECLARE_PER_CPU_FIRST(struct fixed_percpu_data, fixed_percpu_data) __visible;
> -DECLARE_INIT_PER_CPU(fixed_percpu_data);
> -
> static inline unsigned long cpu_kernelmode_gs_base(int cpu)
> {
> - return (unsigned long)per_cpu(fixed_percpu_data.gs_base, cpu);
> +#ifdef CONFIG_SMP
> + return per_cpu_offset(cpu);
> +#else
> + return 0;
> +#endif
> }
>
> extern asmlinkage void entry_SYSCALL32_ignore(void);
> diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
> index fb8f0371ffc3..32ae76cf4508 100644
> --- a/arch/x86/kernel/cpu/common.c
> +++ b/arch/x86/kernel/cpu/common.c
> @@ -2052,10 +2052,6 @@ EXPORT_PER_CPU_SYMBOL(pcpu_hot);
> EXPORT_PER_CPU_SYMBOL(const_pcpu_hot);
>
> #ifdef CONFIG_X86_64
> -DEFINE_PER_CPU_FIRST(struct fixed_percpu_data,
> - fixed_percpu_data) __aligned(PAGE_SIZE) __visible;
> -EXPORT_PER_CPU_SYMBOL_GPL(fixed_percpu_data);
> -
> static void wrmsrl_cstar(unsigned long val)
> {
> /*
> diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
> index 0d94d2a091fe..f2453eb38417 100644
> --- a/arch/x86/kernel/head_64.S
> +++ b/arch/x86/kernel/head_64.S
> @@ -72,9 +72,14 @@ SYM_CODE_START_NOALIGN(startup_64)
>
> /* Setup GSBASE to allow stack canary access for C code */
> movl $MSR_GS_BASE, %ecx
> - leaq INIT_PER_CPU_VAR(fixed_percpu_data)(%rip), %rdx
> +#ifdef CONFIG_SMP
> + leaq __per_cpu_load(%rip), %rdx
> movl %edx, %eax
> shrq $32, %rdx
> +#else
> + xorl %eax, %eax
> + xorl %edx, %edx
> +#endif
> wrmsr
>
> call startup_64_setup_env
> @@ -345,14 +350,10 @@ SYM_INNER_LABEL(secondary_startup_64_no_verify, SYM_L_GLOBAL)
>
> /* Set up %gs.
> *
> - * The base of %gs always points to fixed_percpu_data.
> * Note that, on SMP, the boot cpu uses init data section until
> * the per cpu areas are set up.
> */
> movl $MSR_GS_BASE,%ecx
> -#ifndef CONFIG_SMP
> - leaq INIT_PER_CPU_VAR(fixed_percpu_data)(%rip), %rdx
> -#endif
> movl %edx, %eax
> shrq $32, %rdx
> wrmsr
> diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
> index 1239be7cc8d8..e6126cd21615 100644
> --- a/arch/x86/kernel/vmlinux.lds.S
> +++ b/arch/x86/kernel/vmlinux.lds.S
> @@ -510,14 +510,8 @@ SECTIONS
> */
> #define INIT_PER_CPU(x) init_per_cpu__##x = ABSOLUTE(x) + __per_cpu_load
> INIT_PER_CPU(gdt_page);
> -INIT_PER_CPU(fixed_percpu_data);
> INIT_PER_CPU(irq_stack_backing_store);
>
> -#ifdef CONFIG_SMP
> -. = ASSERT((fixed_percpu_data == 0),
> - "fixed_percpu_data is not at start of per-cpu area");
> -#endif
> -
> #ifdef CONFIG_CPU_UNRET_ENTRY
> . = ASSERT((retbleed_return_thunk & 0x3f) == 0, "retbleed_return_thunk not cacheline-aligned");
> #endif
> diff --git a/arch/x86/platform/pvh/head.S b/arch/x86/platform/pvh/head.S
> index be8d973c0528..d215b16bf89f 100644
> --- a/arch/x86/platform/pvh/head.S
> +++ b/arch/x86/platform/pvh/head.S
> @@ -96,9 +96,14 @@ SYM_CODE_START_LOCAL(pvh_start_xen)
> 1:
> /* Set base address in stack canary descriptor. */
> mov $MSR_GS_BASE,%ecx
> - lea INIT_PER_CPU_VAR(fixed_percpu_data)(%rip), %rdx
> +#ifdef CONFIG_SMP
> + lea __per_cpu_load(%rip), %rdx
> mov %edx, %eax
> shr $32, %rdx
> +#else
> + xor %eax, %eax
> + xor %edx, %edx
> +#endif
> wrmsr
>
> call xen_prepare_pvh
> diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
> index d30949e25ebd..3ccd9d4fcf9c 100644
> --- a/arch/x86/tools/relocs.c
> +++ b/arch/x86/tools/relocs.c
> @@ -811,7 +811,6 @@ static void percpu_init(void)
> * __per_cpu_load
> *
> * The "gold" linker incorrectly associates:
> - * init_per_cpu__fixed_percpu_data
> * init_per_cpu__gdt_page
> */
> static int is_percpu_sym(ElfW(Sym) *sym, const char *symname)
> diff --git a/arch/x86/xen/xen-head.S b/arch/x86/xen/xen-head.S
> index 30f27e757354..9ce0d9d268bb 100644
> --- a/arch/x86/xen/xen-head.S
> +++ b/arch/x86/xen/xen-head.S
> @@ -53,13 +53,18 @@ SYM_CODE_START(startup_xen)
>
> /* Set up %gs.
> *
> - * The base of %gs always points to fixed_percpu_data.
> * Note that, on SMP, the boot cpu uses init data section until
> * the per cpu areas are set up.
> */
> movl $MSR_GS_BASE,%ecx
> - movq $INIT_PER_CPU_VAR(fixed_percpu_data),%rax
> - cdq
> +#ifdef CONFIG_SMP
> + leaq __per_cpu_load(%rip), %rdx
> + movl %edx, %eax
> + shrq $32, %rdx
> +#else
> + xorl %eax, %eax
> + xorl %edx, %edx
> +#endif
> wrmsr
>
> mov %rsi, %rdi
> --
> 2.41.0
>

2023-10-26 18:48:13

by Uros Bizjak

[permalink] [raw]
Subject: Re: [PATCH v2 07/11] x86/percpu/64: Use relative percpu offsets

On Thu, Oct 26, 2023 at 6:01 PM Brian Gerst <[email protected]> wrote:
>
> The percpu section is currently linked at virtual address 0, because
> older compilers hardcoded the stack protector canary value at a fixed
> offset from the start of the GS segment. Now that the canary is a
> normal percpu variable, the percpu section can be linked normally.
> This means that x86-64 will calculate percpu offsets like most other
> architectures, as the delta between the initial percpu address and the
> dynamically allocated memory.

The comments above MSR_GS_BASE setup should be reviewed or removed. I
don't think they need to be set up to access stack canary, they are
just clearing MSR now.

>
> Signed-off-by: Brian Gerst <[email protected]>

With fixed comments:

Reviewed-by: Uros Bizjak <[email protected]>

> ---
> arch/x86/kernel/head_64.S | 6 ------
> arch/x86/kernel/setup_percpu.c | 12 ++----------
> arch/x86/kernel/vmlinux.lds.S | 24 +-----------------------
> arch/x86/platform/pvh/head.S | 6 ------
> arch/x86/tools/relocs.c | 10 +++-------
> arch/x86/xen/xen-head.S | 6 ------
> init/Kconfig | 2 +-
> 7 files changed, 7 insertions(+), 59 deletions(-)
>
> diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
> index f2453eb38417..b35f74e58dd7 100644
> --- a/arch/x86/kernel/head_64.S
> +++ b/arch/x86/kernel/head_64.S
> @@ -72,14 +72,8 @@ SYM_CODE_START_NOALIGN(startup_64)
>
> /* Setup GSBASE to allow stack canary access for C code */
> movl $MSR_GS_BASE, %ecx
> -#ifdef CONFIG_SMP
> - leaq __per_cpu_load(%rip), %rdx
> - movl %edx, %eax
> - shrq $32, %rdx
> -#else
> xorl %eax, %eax
> xorl %edx, %edx
> -#endif
> wrmsr
>
> call startup_64_setup_env
> diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c
> index 2c97bf7b56ae..8707dd07b9ce 100644
> --- a/arch/x86/kernel/setup_percpu.c
> +++ b/arch/x86/kernel/setup_percpu.c
> @@ -23,18 +23,10 @@
> #include <asm/cpumask.h>
> #include <asm/cpu.h>
>
> -#ifdef CONFIG_X86_64
> -#define BOOT_PERCPU_OFFSET ((unsigned long)__per_cpu_load)
> -#else
> -#define BOOT_PERCPU_OFFSET 0
> -#endif
> -
> -DEFINE_PER_CPU_READ_MOSTLY(unsigned long, this_cpu_off) = BOOT_PERCPU_OFFSET;
> +DEFINE_PER_CPU_READ_MOSTLY(unsigned long, this_cpu_off);
> EXPORT_PER_CPU_SYMBOL(this_cpu_off);
>
> -unsigned long __per_cpu_offset[NR_CPUS] __ro_after_init = {
> - [0 ... NR_CPUS-1] = BOOT_PERCPU_OFFSET,
> -};
> +unsigned long __per_cpu_offset[NR_CPUS] __ro_after_init;
> EXPORT_SYMBOL(__per_cpu_offset);
>
> /*
> diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
> index e6126cd21615..efa4885060b5 100644
> --- a/arch/x86/kernel/vmlinux.lds.S
> +++ b/arch/x86/kernel/vmlinux.lds.S
> @@ -103,12 +103,6 @@ const_pcpu_hot = pcpu_hot;
> PHDRS {
> text PT_LOAD FLAGS(5); /* R_E */
> data PT_LOAD FLAGS(6); /* RW_ */
> -#ifdef CONFIG_X86_64
> -#ifdef CONFIG_SMP
> - percpu PT_LOAD FLAGS(6); /* RW_ */
> -#endif
> - init PT_LOAD FLAGS(7); /* RWE */
> -#endif
> note PT_NOTE FLAGS(0); /* ___ */
> }
>
> @@ -224,21 +218,7 @@ SECTIONS
> __init_begin = .; /* paired with __init_end */
> }
>
> -#if defined(CONFIG_X86_64) && defined(CONFIG_SMP)
> - /*
> - * percpu offsets are zero-based on SMP. PERCPU_VADDR() changes the
> - * output PHDR, so the next output section - .init.text - should
> - * start another segment - init.
> - */
> - PERCPU_VADDR(INTERNODE_CACHE_BYTES, 0, :percpu)
> - ASSERT(SIZEOF(.data..percpu) < CONFIG_PHYSICAL_START,
> - "per-CPU data too large - increase CONFIG_PHYSICAL_START")
> -#endif
> -
> INIT_TEXT_SECTION(PAGE_SIZE)
> -#ifdef CONFIG_X86_64
> - :init
> -#endif
>
> /*
> * Section for code used exclusively before alternatives are run. All
> @@ -368,9 +348,7 @@ SECTIONS
> EXIT_DATA
> }
>
> -#if !defined(CONFIG_X86_64) || !defined(CONFIG_SMP)
> PERCPU_SECTION(INTERNODE_CACHE_BYTES)
> -#endif
>
> . = ALIGN(PAGE_SIZE);
>
> @@ -508,7 +486,7 @@ SECTIONS
> * Per-cpu symbols which need to be offset from __per_cpu_load
> * for the boot processor.
> */
> -#define INIT_PER_CPU(x) init_per_cpu__##x = ABSOLUTE(x) + __per_cpu_load
> +#define INIT_PER_CPU(x) init_per_cpu__##x = ABSOLUTE(x)
> INIT_PER_CPU(gdt_page);
> INIT_PER_CPU(irq_stack_backing_store);
>
> diff --git a/arch/x86/platform/pvh/head.S b/arch/x86/platform/pvh/head.S
> index d215b16bf89f..4bd925b23436 100644
> --- a/arch/x86/platform/pvh/head.S
> +++ b/arch/x86/platform/pvh/head.S
> @@ -96,14 +96,8 @@ SYM_CODE_START_LOCAL(pvh_start_xen)
> 1:
> /* Set base address in stack canary descriptor. */
> mov $MSR_GS_BASE,%ecx
> -#ifdef CONFIG_SMP
> - lea __per_cpu_load(%rip), %rdx
> - mov %edx, %eax
> - shr $32, %rdx
> -#else
> xor %eax, %eax
> xor %edx, %edx
> -#endif
> wrmsr
>
> call xen_prepare_pvh
> diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
> index 3ccd9d4fcf9c..01efbfdd3eb3 100644
> --- a/arch/x86/tools/relocs.c
> +++ b/arch/x86/tools/relocs.c
> @@ -815,12 +815,7 @@ static void percpu_init(void)
> */
> static int is_percpu_sym(ElfW(Sym) *sym, const char *symname)
> {
> - int shndx = sym_index(sym);
> -
> - return (shndx == per_cpu_shndx) &&
> - strcmp(symname, "__init_begin") &&
> - strcmp(symname, "__per_cpu_load") &&
> - strncmp(symname, "init_per_cpu_", 13);
> + return 0;
> }
>
>
> @@ -1043,7 +1038,8 @@ static int cmp_relocs(const void *va, const void *vb)
>
> static void sort_relocs(struct relocs *r)
> {
> - qsort(r->offset, r->count, sizeof(r->offset[0]), cmp_relocs);
> + if (r->count)
> + qsort(r->offset, r->count, sizeof(r->offset[0]), cmp_relocs);
> }
>
> static int write32(uint32_t v, FILE *f)
> diff --git a/arch/x86/xen/xen-head.S b/arch/x86/xen/xen-head.S
> index 9ce0d9d268bb..c1d9c92b417a 100644
> --- a/arch/x86/xen/xen-head.S
> +++ b/arch/x86/xen/xen-head.S
> @@ -57,14 +57,8 @@ SYM_CODE_START(startup_xen)
> * the per cpu areas are set up.
> */
> movl $MSR_GS_BASE,%ecx
> -#ifdef CONFIG_SMP
> - leaq __per_cpu_load(%rip), %rdx
> - movl %edx, %eax
> - shrq $32, %rdx
> -#else
> xorl %eax, %eax
> xorl %edx, %edx
> -#endif
> wrmsr
>
> mov %rsi, %rdi
> diff --git a/init/Kconfig b/init/Kconfig
> index 6d35728b94b2..1af31b23e376 100644
> --- a/init/Kconfig
> +++ b/init/Kconfig
> @@ -1718,7 +1718,7 @@ config KALLSYMS_ALL
> config KALLSYMS_ABSOLUTE_PERCPU
> bool
> depends on KALLSYMS
> - default X86_64 && SMP
> + default n
>
> config KALLSYMS_BASE_RELATIVE
> bool
> --
> 2.41.0
>

2023-10-26 18:49:18

by Uros Bizjak

[permalink] [raw]
Subject: Re: [PATCH v2 09/11] x86/percpu/64: Remove INIT_PER_CPU macros

On Thu, Oct 26, 2023 at 6:01 PM Brian Gerst <[email protected]> wrote:
>
> The load and link addresses of percpu variables are now the same, so
> these macros are no longer necessary.
>
> Signed-off-by: Brian Gerst <[email protected]>

Reviewed-by: Uros Bizjak <[email protected]>

> ---
> arch/x86/include/asm/percpu.h | 22 ----------------------
> arch/x86/kernel/irq_64.c | 1 -
> arch/x86/kernel/vmlinux.lds.S | 7 -------
> arch/x86/tools/relocs.c | 1 -
> 4 files changed, 31 deletions(-)
>
> diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h
> index b86b27d15e52..7a176381ee01 100644
> --- a/arch/x86/include/asm/percpu.h
> +++ b/arch/x86/include/asm/percpu.h
> @@ -20,12 +20,6 @@
>
> #define PER_CPU_VAR(var) __percpu(var)__percpu_rel
>
> -#ifdef CONFIG_X86_64_SMP
> -#define INIT_PER_CPU_VAR(var) init_per_cpu__##var
> -#else
> -#define INIT_PER_CPU_VAR(var) var
> -#endif
> -
> #else /* ...!ASSEMBLY */
>
> #include <linux/kernel.h>
> @@ -96,22 +90,6 @@
> #define __percpu_arg(x) __percpu_prefix "%" #x
> #define __force_percpu_arg(x) __force_percpu_prefix "%" #x
>
> -/*
> - * Initialized pointers to per-cpu variables needed for the boot
> - * processor need to use these macros to get the proper address
> - * offset from __per_cpu_load on SMP.
> - *
> - * There also must be an entry in vmlinux_64.lds.S
> - */
> -#define DECLARE_INIT_PER_CPU(var) \
> - extern typeof(var) init_per_cpu_var(var)
> -
> -#ifdef CONFIG_X86_64_SMP
> -#define init_per_cpu_var(var) init_per_cpu__##var
> -#else
> -#define init_per_cpu_var(var) var
> -#endif
> -
> /* For arch-specific code, we can use direct single-insn ops (they
> * don't give an lvalue though). */
>
> diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c
> index fe0c859873d1..30424f9876bc 100644
> --- a/arch/x86/kernel/irq_64.c
> +++ b/arch/x86/kernel/irq_64.c
> @@ -26,7 +26,6 @@
> #include <asm/apic.h>
>
> DEFINE_PER_CPU_PAGE_ALIGNED(struct irq_stack, irq_stack_backing_store) __visible;
> -DECLARE_INIT_PER_CPU(irq_stack_backing_store);
>
> #ifdef CONFIG_VMAP_STACK
> /*
> diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
> index efa4885060b5..9aea7b6b02c7 100644
> --- a/arch/x86/kernel/vmlinux.lds.S
> +++ b/arch/x86/kernel/vmlinux.lds.S
> @@ -482,13 +482,6 @@ SECTIONS
> "kernel image bigger than KERNEL_IMAGE_SIZE");
>
> #ifdef CONFIG_X86_64
> -/*
> - * Per-cpu symbols which need to be offset from __per_cpu_load
> - * for the boot processor.
> - */
> -#define INIT_PER_CPU(x) init_per_cpu__##x = ABSOLUTE(x)
> -INIT_PER_CPU(gdt_page);
> -INIT_PER_CPU(irq_stack_backing_store);
>
> #ifdef CONFIG_CPU_UNRET_ENTRY
> . = ASSERT((retbleed_return_thunk & 0x3f) == 0, "retbleed_return_thunk not cacheline-aligned");
> diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
> index 7feb63179b62..931d90aa814c 100644
> --- a/arch/x86/tools/relocs.c
> +++ b/arch/x86/tools/relocs.c
> @@ -83,7 +83,6 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
> "__initramfs_start|"
> "(jiffies|jiffies_64)|"
> #if ELF_BITS == 64
> - "init_per_cpu__.*|"
> "__end_rodata_hpage_align|"
> #endif
> "__vvar_page|"
> --
> 2.41.0
>

2023-10-26 18:51:28

by Uros Bizjak

[permalink] [raw]
Subject: Re: [PATCH v2 10/11] percpu: Remove PER_CPU_FIRST_SECTION

On Thu, Oct 26, 2023 at 6:01 PM Brian Gerst <[email protected]> wrote:
>
> x86-64 was the only user.
>
> Signed-off-by: Brian Gerst <[email protected]>

Reviewed-by: Uros Bizjak <[email protected]>

> ---
> include/asm-generic/vmlinux.lds.h | 1 -
> include/linux/percpu-defs.h | 12 ------------
> 2 files changed, 13 deletions(-)
>
> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
> index 67d8dd2f1bde..23d8acc72760 100644
> --- a/include/asm-generic/vmlinux.lds.h
> +++ b/include/asm-generic/vmlinux.lds.h
> @@ -1032,7 +1032,6 @@
> */
> #define PERCPU_INPUT(cacheline) \
> __per_cpu_start = .; \
> - *(.data..percpu..first) \
> . = ALIGN(PAGE_SIZE); \
> *(.data..percpu..page_aligned) \
> . = ALIGN(cacheline); \
> diff --git a/include/linux/percpu-defs.h b/include/linux/percpu-defs.h
> index ec3573119923..b9ddee91e6c7 100644
> --- a/include/linux/percpu-defs.h
> +++ b/include/linux/percpu-defs.h
> @@ -26,13 +26,11 @@
> #define PER_CPU_SHARED_ALIGNED_SECTION "..shared_aligned"
> #define PER_CPU_ALIGNED_SECTION "..shared_aligned"
> #endif
> -#define PER_CPU_FIRST_SECTION "..first"
>
> #else
>
> #define PER_CPU_SHARED_ALIGNED_SECTION ""
> #define PER_CPU_ALIGNED_SECTION "..shared_aligned"
> -#define PER_CPU_FIRST_SECTION ""
>
> #endif
>
> @@ -114,16 +112,6 @@
> #define DEFINE_PER_CPU(type, name) \
> DEFINE_PER_CPU_SECTION(type, name, "")
>
> -/*
> - * Declaration/definition used for per-CPU variables that must come first in
> - * the set of variables.
> - */
> -#define DECLARE_PER_CPU_FIRST(type, name) \
> - DECLARE_PER_CPU_SECTION(type, name, PER_CPU_FIRST_SECTION)
> -
> -#define DEFINE_PER_CPU_FIRST(type, name) \
> - DEFINE_PER_CPU_SECTION(type, name, PER_CPU_FIRST_SECTION)
> -
> /*
> * Declaration/definition used for per-CPU variables that must be cacheline
> * aligned under SMP conditions so that, whilst a particular instance of the
> --
> 2.41.0
>

2023-10-27 02:09:49

by Brian Gerst

[permalink] [raw]
Subject: Re: [PATCH v2 07/11] x86/percpu/64: Use relative percpu offsets

On Thu, Oct 26, 2023 at 2:47 PM Uros Bizjak <[email protected]> wrote:
>
> On Thu, Oct 26, 2023 at 6:01 PM Brian Gerst <[email protected]> wrote:
> >
> > The percpu section is currently linked at virtual address 0, because
> > older compilers hardcoded the stack protector canary value at a fixed
> > offset from the start of the GS segment. Now that the canary is a
> > normal percpu variable, the percpu section can be linked normally.
> > This means that x86-64 will calculate percpu offsets like most other
> > architectures, as the delta between the initial percpu address and the
> > dynamically allocated memory.
>
> The comments above MSR_GS_BASE setup should be reviewed or removed. I
> don't think they need to be set up to access stack canary, they are
> just clearing MSR now.

GSBASE is deliberately set to zero offset on SMP for boot because we
want any percpu accesses (including stack protector) to use the
initial percpu area until the full percpu memory is allocated. It's
possible that more stack protector checks could sneak back into the
early boot code, and after the conversion to relative percpu offsets
they would work properly again. I just didn't reenable them because
they are unnecessary that early.

Brian Gerst

2023-10-27 06:09:49

by Uros Bizjak

[permalink] [raw]
Subject: Re: [PATCH v2 07/11] x86/percpu/64: Use relative percpu offsets

On Fri, Oct 27, 2023 at 4:09 AM Brian Gerst <[email protected]> wrote:
>
> On Thu, Oct 26, 2023 at 2:47 PM Uros Bizjak <[email protected]> wrote:
> >
> > On Thu, Oct 26, 2023 at 6:01 PM Brian Gerst <[email protected]> wrote:
> > >
> > > The percpu section is currently linked at virtual address 0, because
> > > older compilers hardcoded the stack protector canary value at a fixed
> > > offset from the start of the GS segment. Now that the canary is a
> > > normal percpu variable, the percpu section can be linked normally.
> > > This means that x86-64 will calculate percpu offsets like most other
> > > architectures, as the delta between the initial percpu address and the
> > > dynamically allocated memory.
> >
> > The comments above MSR_GS_BASE setup should be reviewed or removed. I
> > don't think they need to be set up to access stack canary, they are
> > just clearing MSR now.
>
> GSBASE is deliberately set to zero offset on SMP for boot because we
> want any percpu accesses (including stack protector) to use the
> initial percpu area until the full percpu memory is allocated. It's
> possible that more stack protector checks could sneak back into the
> early boot code, and after the conversion to relative percpu offsets
> they would work properly again. I just didn't reenable them because
> they are unnecessary that early.

Thanks for the explanation, perhaps this non-obvious fact should be
mentioned in the comment .

Thanks,
Uros.

> Brian Gerst

2023-10-27 16:56:00

by Brian Gerst

[permalink] [raw]
Subject: Re: [PATCH v2 07/11] x86/percpu/64: Use relative percpu offsets

On Fri, Oct 27, 2023 at 2:09 AM Uros Bizjak <[email protected]> wrote:
>
> On Fri, Oct 27, 2023 at 4:09 AM Brian Gerst <[email protected]> wrote:
> >
> > On Thu, Oct 26, 2023 at 2:47 PM Uros Bizjak <[email protected]> wrote:
> > >
> > > On Thu, Oct 26, 2023 at 6:01 PM Brian Gerst <[email protected]> wrote:
> > > >
> > > > The percpu section is currently linked at virtual address 0, because
> > > > older compilers hardcoded the stack protector canary value at a fixed
> > > > offset from the start of the GS segment. Now that the canary is a
> > > > normal percpu variable, the percpu section can be linked normally.
> > > > This means that x86-64 will calculate percpu offsets like most other
> > > > architectures, as the delta between the initial percpu address and the
> > > > dynamically allocated memory.
> > >
> > > The comments above MSR_GS_BASE setup should be reviewed or removed. I
> > > don't think they need to be set up to access stack canary, they are
> > > just clearing MSR now.
> >
> > GSBASE is deliberately set to zero offset on SMP for boot because we
> > want any percpu accesses (including stack protector) to use the4
> > initial percpu area until the full percpu memory is allocated. It's
> > possible that more stack protector checks could sneak back into the
> > early boot code, and after the conversion to relative percpu offsets
> > they would work properly again. I just didn't reenable them because
> > they are unnecessary that early.
>
> Thanks for the explanation, perhaps this non-obvious fact should be
> mentioned in the comment .

I will update the comments if I need to send a v3 for some other
reason, otherwise I'll do a followup patch.

Brian Gerst

2023-10-29 01:27:45

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v2 05/11] x86/stackprotector/64: Convert stack protector to normal percpu variable

Hi Brian,

kernel test robot noticed the following build errors:

[auto build test ERROR on tip/master]
[also build test ERROR on next-20231027]
[cannot apply to tip/x86/core dennis-percpu/for-next linus/master tip/auto-latest v6.6-rc7]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Brian-Gerst/x86-stackprotector-32-Remove-stack-protector-test-script/20231027-000533
base: tip/master
patch link: https://lore.kernel.org/r/20231026160100.195099-6-brgerst%40gmail.com
patch subject: [PATCH v2 05/11] x86/stackprotector/64: Convert stack protector to normal percpu variable
config: x86_64-rhel-8.3-rust (https://download.01.org/0day-ci/archive/20231029/[email protected]/config)
compiler: clang version 16.0.4 (https://github.com/llvm/llvm-project.git ae42196bc493ffe877a7e3dff8be32035dea4d07)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231029/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

>> Unsupported relocation type: unknown type rel type name (42)

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

2023-10-29 07:16:00

by Brian Gerst

[permalink] [raw]
Subject: Re: [PATCH v2 05/11] x86/stackprotector/64: Convert stack protector to normal percpu variable

On Sat, Oct 28, 2023 at 9:26 PM kernel test robot <[email protected]> wrote:
>
> Hi Brian,
>
> kernel test robot noticed the following build errors:
>
> [auto build test ERROR on tip/master]
> [also build test ERROR on next-20231027]
> [cannot apply to tip/x86/core dennis-percpu/for-next linus/master tip/auto-latest v6.6-rc7]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url: https://github.com/intel-lab-lkp/linux/commits/Brian-Gerst/x86-stackprotector-32-Remove-stack-protector-test-script/20231027-000533
> base: tip/master
> patch link: https://lore.kernel.org/r/20231026160100.195099-6-brgerst%40gmail.com
> patch subject: [PATCH v2 05/11] x86/stackprotector/64: Convert stack protector to normal percpu variable
> config: x86_64-rhel-8.3-rust (https://download.01.org/0day-ci/archive/20231029/[email protected]/config)
> compiler: clang version 16.0.4 (https://github.com/llvm/llvm-project.git ae42196bc493ffe877a7e3dff8be32035dea4d07)
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231029/[email protected]/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <[email protected]>
> | Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
>
> All errors (new ones prefixed by >>):
>
> >> Unsupported relocation type: unknown type rel type name (42)

Clang is generating a new relocation type (R_X86_64_REX_GOTPCRELX)
that the relocs tool doesn't know about. This is supposed to allow
movq __stack_chk_guard@GOTPCREL(%rip), %rax
movq %gs:(%rax), %rax
to be relaxed to
leaq __stack_chk_guard(%rip), %rax
movq %gs:(%rax), %rax

But why is clang doing this instead of what GCC does?
movq %gs:__stack_chk_guard(%rip), %rax

Brian Gerst

2023-10-29 17:01:51

by Brian Gerst

[permalink] [raw]
Subject: Re: [PATCH v2 05/11] x86/stackprotector/64: Convert stack protector to normal percpu variable

On Sun, Oct 29, 2023 at 2:56 AM Brian Gerst <[email protected]> wrote:
>
> On Sat, Oct 28, 2023 at 9:26 PM kernel test robot <[email protected]> wrote:
> >
> > Hi Brian,
> >
> > kernel test robot noticed the following build errors:
> >
> > [auto build test ERROR on tip/master]
> > [also build test ERROR on next-20231027]
> > [cannot apply to tip/x86/core dennis-percpu/for-next linus/master tip/auto-latest v6.6-rc7]
> > [If your patch is applied to the wrong git tree, kindly drop us a note.
> > And when submitting patch, we suggest to use '--base' as documented in
> > https://git-scm.com/docs/git-format-patch#_base_tree_information]
> >
> > url: https://github.com/intel-lab-lkp/linux/commits/Brian-Gerst/x86-stackprotector-32-Remove-stack-protector-test-script/20231027-000533
> > base: tip/master
> > patch link: https://lore.kernel.org/r/20231026160100.195099-6-brgerst%40gmail.com
> > patch subject: [PATCH v2 05/11] x86/stackprotector/64: Convert stack protector to normal percpu variable
> > config: x86_64-rhel-8.3-rust (https://download.01.org/0day-ci/archive/20231029/[email protected]/config)
> > compiler: clang version 16.0.4 (https://github.com/llvm/llvm-project.git ae42196bc493ffe877a7e3dff8be32035dea4d07)
> > reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231029/[email protected]/reproduce)
> >
> > If you fix the issue in a separate patch/commit (i.e. not just a new version of
> > the same patch/commit), kindly add following tags
> > | Reported-by: kernel test robot <[email protected]>
> > | Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
> >
> > All errors (new ones prefixed by >>):
> >
> > >> Unsupported relocation type: unknown type rel type name (42)
>
> Clang is generating a new relocation type (R_X86_64_REX_GOTPCRELX)
> that the relocs tool doesn't know about. This is supposed to allow
> movq __stack_chk_guard@GOTPCREL(%rip), %rax
> movq %gs:(%rax), %rax
> to be relaxed to
> leaq __stack_chk_guard(%rip), %rax
> movq %gs:(%rax), %rax
>
> But why is clang doing this instead of what GCC does?
> movq %gs:__stack_chk_guard(%rip), %rax

Digging a bit deeper, there also appears to be differences in how the
linkers behave with this new relocation:

make CC=clang LD=ld:
ffffffff81002838: 48 c7 c0 c0 5c 42 83 mov $0xffffffff83425cc0,%rax
ffffffff8100283b: R_X86_64_32S __stack_chk_guard
ffffffff8100283f: 65 48 8b 00 mov %gs:(%rax),%rax

make CC=clang LD=ld.lld:
ffffffff81002838: 48 8d 05 81 34 42 02 lea
0x2423481(%rip),%rax # ffffffff83425cc0 <__stack_chk_guard>
ffffffff8100283b: R_X86_64_REX_GOTPCRELX
__stack_chk_guard-0x4
ffffffff8100283f: 65 48 8b 00 mov %gs:(%rax),%rax

The LLVM linker keeps the R_X86_64_REX_GOTPCRELX even after performing
the relaxation. It should be R_X86_64_32S based on it changing to an
LEA instruction. The GNU linker changes it to R_X86_64_32S and a MOV
immediate.

So I think there are two issues here. 1) clang is producing code
referencing the GOT for stack protector accesses, despite -fno-PIE on
the command line and no other GOT references, and 2) ld.lld is using
the wrong relocation type after the relaxation step is performed.

I think the quick fix here is to teach the relocs tool about this new
relocation. It should be able to be safely ignored since it's
PC-relative. The code clang produces is functionally correct,
although not optimal.

Brian Gerst

2023-10-29 21:42:44

by David Laight

[permalink] [raw]
Subject: RE: [PATCH v2 00/11] x86-64: Stack protector and percpu improvements

From: Brian Gerst
> Sent: 26 October 2023 17:01
>
> Currently, x86-64 uses an unusual percpu layout, where the percpu section
> is linked at absolute address 0. The reason behind this is that older GCC
> versions placed the stack protector (if enabled) at a fixed offset from the
> GS segment base. Since the GS segement is also used for percpu variables,
> this forced the current layout.
>
> GCC since version 8.1 supports a configurable location for the stack
> protector value, which allows removal of the restriction on how the percpu
> section is linked. This allows the percpu section to be linked
> normally, like most other architectures. In turn, this allows removal
> of code that was needed to support the zero-based percpu section.

I didn't think the minimum gcc version was anything like 8.1.
I'm using 7.5.0 and I don't think that is the oldest version.

David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)

2023-10-30 00:03:13

by Brian Gerst

[permalink] [raw]
Subject: Re: [PATCH v2 00/11] x86-64: Stack protector and percpu improvements

On Sun, Oct 29, 2023 at 5:42 PM David Laight <[email protected]> wrote:
>
> From: Brian Gerst
> > Sent: 26 October 2023 17:01
> >
> > Currently, x86-64 uses an unusual percpu layout, where the percpu section
> > is linked at absolute address 0. The reason behind this is that older GCC
> > versions placed the stack protector (if enabled) at a fixed offset from the
> > GS segment base. Since the GS segement is also used for percpu variables,
> > this forced the current layout.
> >
> > GCC since version 8.1 supports a configurable location for the stack
> > protector value, which allows removal of the restriction on how the percpu
> > section is linked. This allows the percpu section to be linked
> > normally, like most other architectures. In turn, this allows removal
> > of code that was needed to support the zero-based percpu section.
>
> I didn't think the minimum gcc version was anything like 8.1.
> I'm using 7.5.0 and I don't think that is the oldest version.

What distribution are you using that still relies on that old of a compiler?

Brian Gerst

2023-10-30 08:07:07

by Uros Bizjak

[permalink] [raw]
Subject: Re: [PATCH v2 00/11] x86-64: Stack protector and percpu improvements

On Sun, Oct 29, 2023 at 10:42 PM David Laight <[email protected]> wrote:
>
> From: Brian Gerst
> > Sent: 26 October 2023 17:01
> >
> > Currently, x86-64 uses an unusual percpu layout, where the percpu section
> > is linked at absolute address 0. The reason behind this is that older GCC
> > versions placed the stack protector (if enabled) at a fixed offset from the
> > GS segment base. Since the GS segement is also used for percpu variables,
> > this forced the current layout.
> >
> > GCC since version 8.1 supports a configurable location for the stack
> > protector value, which allows removal of the restriction on how the percpu
> > section is linked. This allows the percpu section to be linked
> > normally, like most other architectures. In turn, this allows removal
> > of code that was needed to support the zero-based percpu section.
>
> I didn't think the minimum gcc version was anything like 8.1.
> I'm using 7.5.0 and I don't think that is the oldest version.

Please see previous discussion regarding modernizing stack protector
on x86_64 [1]

[1] https://lore.kernel.org/lkml/[email protected]/

and x86_32 [2]

[2] https://lore.kernel.org/lkml/[email protected]/

The conclusion in [2] is:

"I'm all in favour of simply requiring GCC-8.1 to build a more secure
x86_64 kernel. Gives people an incentive to not use ancient compilers.

And if you do want to use your ancient compiler, we'll still build, you
just don't get to have stackprotector."

and in [1]:

"Ack. We did this for 32-bit and got few complaints. Let’s finish the job."

Uros.

2023-10-30 09:06:10

by David Laight

[permalink] [raw]
Subject: RE: [PATCH v2 00/11] x86-64: Stack protector and percpu improvements

From: Uros Bizjak
> Sent: 30 October 2023 08:07
>
> On Sun, Oct 29, 2023 at 10:42 PM David Laight <[email protected]> wrote:
> >
> > From: Brian Gerst
> > > Sent: 26 October 2023 17:01
> > >
> > > Currently, x86-64 uses an unusual percpu layout, where the percpu section
> > > is linked at absolute address 0. The reason behind this is that older GCC
> > > versions placed the stack protector (if enabled) at a fixed offset from the
> > > GS segment base. Since the GS segement is also used for percpu variables,
> > > this forced the current layout.
> > >
> > > GCC since version 8.1 supports a configurable location for the stack
> > > protector value, which allows removal of the restriction on how the percpu
> > > section is linked. This allows the percpu section to be linked
> > > normally, like most other architectures. In turn, this allows removal
> > > of code that was needed to support the zero-based percpu section.
> >
> > I didn't think the minimum gcc version was anything like 8.1.
> > I'm using 7.5.0 and I don't think that is the oldest version.
>
> Please see previous discussion regarding modernizing stack protector
> on x86_64 [1]
>
> [1] https://lore.kernel.org/lkml/[email protected]/
>
> and x86_32 [2]
>
> [2] https://lore.kernel.org/lkml/[email protected]/
>
> The conclusion in [2] is:
>
> "I'm all in favour of simply requiring GCC-8.1 to build a more secure
> x86_64 kernel. Gives people an incentive to not use ancient compilers.
>
> And if you do want to use your ancient compiler, we'll still build, you
> just don't get to have stackprotector."

I didn't see a patch that limited 'stackprotector' to gcc >= 8.1
Without that anyone who already has it enabled and is using an
older compiler will get very broken kernels.

David

>
> and in [1]:
>
> "Ack. We did this for 32-bit and got few complaints. Let’s finish the job."
>
> Uros.

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)

2023-10-30 09:10:51

by Uros Bizjak

[permalink] [raw]
Subject: Re: [PATCH v2 00/11] x86-64: Stack protector and percpu improvements

On Mon, Oct 30, 2023 at 10:05 AM David Laight <[email protected]> wrote:
>
> From: Uros Bizjak
> > Sent: 30 October 2023 08:07
> >
> > On Sun, Oct 29, 2023 at 10:42 PM David Laight <[email protected]> wrote:
> > >
> > > From: Brian Gerst
> > > > Sent: 26 October 2023 17:01
> > > >
> > > > Currently, x86-64 uses an unusual percpu layout, where the percpu section
> > > > is linked at absolute address 0. The reason behind this is that older GCC
> > > > versions placed the stack protector (if enabled) at a fixed offset from the
> > > > GS segment base. Since the GS segement is also used for percpu variables,
> > > > this forced the current layout.
> > > >
> > > > GCC since version 8.1 supports a configurable location for the stack
> > > > protector value, which allows removal of the restriction on how the percpu
> > > > section is linked. This allows the percpu section to be linked
> > > > normally, like most other architectures. In turn, this allows removal
> > > > of code that was needed to support the zero-based percpu section.
> > >
> > > I didn't think the minimum gcc version was anything like 8.1.
> > > I'm using 7.5.0 and I don't think that is the oldest version.
> >
> > Please see previous discussion regarding modernizing stack protector
> > on x86_64 [1]
> >
> > [1] https://lore.kernel.org/lkml/[email protected]/
> >
> > and x86_32 [2]
> >
> > [2] https://lore.kernel.org/lkml/[email protected]/
> >
> > The conclusion in [2] is:
> >
> > "I'm all in favour of simply requiring GCC-8.1 to build a more secure
> > x86_64 kernel. Gives people an incentive to not use ancient compilers.
> >
> > And if you do want to use your ancient compiler, we'll still build, you
> > just don't get to have stackprotector."
>
> I didn't see a patch that limited 'stackprotector' to gcc >= 8.1
> Without that anyone who already has it enabled and is using an
> older compiler will get very broken kernels.

It's this part:

--cut here--
diff --git a/scripts/gcc-x86_32-has-stack-protector.sh
b/scripts/gcc-x86_32-has-stack-protector.sh
index f5c119495254..51f864d76bd6 100755
--- a/scripts/gcc-x86_32-has-stack-protector.sh
+++ b/scripts/gcc-x86_32-has-stack-protector.sh
@@ -1,4 +1,8 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0

-echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -m32
-O0 -fstack-protector - -o - 2> /dev/null | grep -q "%gs"
+# This requires GCC 8.1 or better. Specifically, we require
+# -mstack-protector-guard-reg, added by
+# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81708
+
+echo "int foo(void) { char X[200]; return 3; }" | $* -S -x c -c -m32
-O0 -fstack-protector -mstack-protector-guard-reg=fs
-mstack-protector-guard-symbol=stack_canary - -o - 2> /dev/null | grep
-q "%fs"
--cut here--

Uros.

2023-10-30 15:24:46

by Nick Desaulniers

[permalink] [raw]
Subject: Re: [PATCH v2 05/11] x86/stackprotector/64: Convert stack protector to normal percpu variable

On Sun, Oct 29, 2023 at 10:01 AM Brian Gerst <[email protected]> wrote:
>
> On Sun, Oct 29, 2023 at 2:56 AM Brian Gerst <[email protected]> wrote:
> >
> > On Sat, Oct 28, 2023 at 9:26 PM kernel test robot <[email protected]> wrote:
> > >
> > > Hi Brian,
> > >
> > > kernel test robot noticed the following build errors:
> > >
> > > [auto build test ERROR on tip/master]
> > > [also build test ERROR on next-20231027]
> > > [cannot apply to tip/x86/core dennis-percpu/for-next linus/master tip/auto-latest v6.6-rc7]
> > > [If your patch is applied to the wrong git tree, kindly drop us a note.
> > > And when submitting patch, we suggest to use '--base' as documented in
> > > https://git-scm.com/docs/git-format-patch#_base_tree_information]
> > >
> > > url: https://github.com/intel-lab-lkp/linux/commits/Brian-Gerst/x86-stackprotector-32-Remove-stack-protector-test-script/20231027-000533
> > > base: tip/master
> > > patch link: https://lore.kernel.org/r/20231026160100.195099-6-brgerst%40gmail.com
> > > patch subject: [PATCH v2 05/11] x86/stackprotector/64: Convert stack protector to normal percpu variable
> > > config: x86_64-rhel-8.3-rust (https://download.01.org/0day-ci/archive/20231029/[email protected]/config)
> > > compiler: clang version 16.0.4 (https://github.com/llvm/llvm-project.git ae42196bc493ffe877a7e3dff8be32035dea4d07)
> > > reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231029/[email protected]/reproduce)
> > >
> > > If you fix the issue in a separate patch/commit (i.e. not just a new version of
> > > the same patch/commit), kindly add following tags
> > > | Reported-by: kernel test robot <[email protected]>
> > > | Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
> > >
> > > All errors (new ones prefixed by >>):
> > >
> > > >> Unsupported relocation type: unknown type rel type name (42)
> >
> > Clang is generating a new relocation type (R_X86_64_REX_GOTPCRELX)
> > that the relocs tool doesn't know about. This is supposed to allow
> > movq __stack_chk_guard@GOTPCREL(%rip), %rax
> > movq %gs:(%rax), %rax
> > to be relaxed to
> > leaq __stack_chk_guard(%rip), %rax
> > movq %gs:(%rax), %rax
> >
> > But why is clang doing this instead of what GCC does?
> > movq %gs:__stack_chk_guard(%rip), %rax
>
> Digging a bit deeper, there also appears to be differences in how the
> linkers behave with this new relocation:
>
> make CC=clang LD=ld:
> ffffffff81002838: 48 c7 c0 c0 5c 42 83 mov $0xffffffff83425cc0,%rax
> ffffffff8100283b: R_X86_64_32S __stack_chk_guard
> ffffffff8100283f: 65 48 8b 00 mov %gs:(%rax),%rax
>
> make CC=clang LD=ld.lld:
> ffffffff81002838: 48 8d 05 81 34 42 02 lea
> 0x2423481(%rip),%rax # ffffffff83425cc0 <__stack_chk_guard>
> ffffffff8100283b: R_X86_64_REX_GOTPCRELX
> __stack_chk_guard-0x4
> ffffffff8100283f: 65 48 8b 00 mov %gs:(%rax),%rax
>
> The LLVM linker keeps the R_X86_64_REX_GOTPCRELX even after performing
> the relaxation. It should be R_X86_64_32S based on it changing to an
> LEA instruction. The GNU linker changes it to R_X86_64_32S and a MOV
> immediate.
>
> So I think there are two issues here. 1) clang is producing code
> referencing the GOT for stack protector accesses, despite -fno-PIE on
> the command line and no other GOT references, and 2) ld.lld is using
> the wrong relocation type after the relaxation step is performed.
>
> I think the quick fix here is to teach the relocs tool about this new
> relocation. It should be able to be safely ignored since it's
> PC-relative. The code clang produces is functionally correct,
> although not optimal.

Thanks for the report. + Fangrui for thoughts on relocations against
__stack_chk_guard; clang has similar issues for 32b x86 as well.

>
> Brian Gerst
>


--
Thanks,
~Nick Desaulniers

2023-10-30 17:19:43

by Brian Gerst

[permalink] [raw]
Subject: Re: [PATCH v2 05/11] x86/stackprotector/64: Convert stack protector to normal percpu variable

On Mon, Oct 30, 2023 at 11:24 AM Nick Desaulniers
<[email protected]> wrote:
>
> On Sun, Oct 29, 2023 at 10:01 AM Brian Gerst <[email protected]> wrote:
> >
> > On Sun, Oct 29, 2023 at 2:56 AM Brian Gerst <[email protected]> wrote:
> > >
> > > On Sat, Oct 28, 2023 at 9:26 PM kernel test robot <[email protected]> wrote:
> > > >
> > > > Hi Brian,
> > > >
> > > > kernel test robot noticed the following build errors:
> > > >
> > > > [auto build test ERROR on tip/master]
> > > > [also build test ERROR on next-20231027]
> > > > [cannot apply to tip/x86/core dennis-percpu/for-next linus/master tip/auto-latest v6.6-rc7]
> > > > [If your patch is applied to the wrong git tree, kindly drop us a note.
> > > > And when submitting patch, we suggest to use '--base' as documented in
> > > > https://git-scm.com/docs/git-format-patch#_base_tree_information]
> > > >
> > > > url: https://github.com/intel-lab-lkp/linux/commits/Brian-Gerst/x86-stackprotector-32-Remove-stack-protector-test-script/20231027-000533
> > > > base: tip/master
> > > > patch link: https://lore.kernel.org/r/20231026160100.195099-6-brgerst%40gmail.com
> > > > patch subject: [PATCH v2 05/11] x86/stackprotector/64: Convert stack protector to normal percpu variable
> > > > config: x86_64-rhel-8.3-rust (https://download.01.org/0day-ci/archive/20231029/[email protected]/config)
> > > > compiler: clang version 16.0.4 (https://github.com/llvm/llvm-project.git ae42196bc493ffe877a7e3dff8be32035dea4d07)
> > > > reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231029/[email protected]/reproduce)
> > > >
> > > > If you fix the issue in a separate patch/commit (i.e. not just a new version of
> > > > the same patch/commit), kindly add following tags
> > > > | Reported-by: kernel test robot <[email protected]>
> > > > | Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
> > > >
> > > > All errors (new ones prefixed by >>):
> > > >
> > > > >> Unsupported relocation type: unknown type rel type name (42)
> > >
> > > Clang is generating a new relocation type (R_X86_64_REX_GOTPCRELX)
> > > that the relocs tool doesn't know about. This is supposed to allow
> > > movq __stack_chk_guard@GOTPCREL(%rip), %rax
> > > movq %gs:(%rax), %rax
> > > to be relaxed to
> > > leaq __stack_chk_guard(%rip), %rax
> > > movq %gs:(%rax), %rax
> > >
> > > But why is clang doing this instead of what GCC does?
> > > movq %gs:__stack_chk_guard(%rip), %rax
> >
> > Digging a bit deeper, there also appears to be differences in how the
> > linkers behave with this new relocation:
> >
> > make CC=clang LD=ld:
> > ffffffff81002838: 48 c7 c0 c0 5c 42 83 mov $0xffffffff83425cc0,%rax
> > ffffffff8100283b: R_X86_64_32S __stack_chk_guard
> > ffffffff8100283f: 65 48 8b 00 mov %gs:(%rax),%rax
> >
> > make CC=clang LD=ld.lld:
> > ffffffff81002838: 48 8d 05 81 34 42 02 lea
> > 0x2423481(%rip),%rax # ffffffff83425cc0 <__stack_chk_guard>
> > ffffffff8100283b: R_X86_64_REX_GOTPCRELX
> > __stack_chk_guard-0x4
> > ffffffff8100283f: 65 48 8b 00 mov %gs:(%rax),%rax
> >
> > The LLVM linker keeps the R_X86_64_REX_GOTPCRELX even after performing
> > the relaxation. It should be R_X86_64_32S based on it changing to an
> > LEA instruction. The GNU linker changes it to R_X86_64_32S and a MOV
> > immediate.

Correction: It should be R_X86_64_PC32 for the LEA instruction.

Brian Gerst

2023-11-01 21:21:27

by Fangrui Song

[permalink] [raw]
Subject: Re: [PATCH v2 05/11] x86/stackprotector/64: Convert stack protector to normal percpu variable

On Mon, Oct 30, 2023 at 10:19 AM Brian Gerst <[email protected]> wrote:
>
> On Mon, Oct 30, 2023 at 11:24 AM Nick Desaulniers
> <[email protected]> wrote:
> >
> > On Sun, Oct 29, 2023 at 10:01 AM Brian Gerst <[email protected]> wrote:
> > >
> > > On Sun, Oct 29, 2023 at 2:56 AM Brian Gerst <[email protected]> wrote:
> > > >
> > > > On Sat, Oct 28, 2023 at 9:26 PM kernel test robot <[email protected]> wrote:
> > > > >
> > > > > Hi Brian,
> > > > >
> > > > > kernel test robot noticed the following build errors:
> > > > >
> > > > > [auto build test ERROR on tip/master]
> > > > > [also build test ERROR on next-20231027]
> > > > > [cannot apply to tip/x86/core dennis-percpu/for-next linus/master tip/auto-latest v6.6-rc7]
> > > > > [If your patch is applied to the wrong git tree, kindly drop us a note.
> > > > > And when submitting patch, we suggest to use '--base' as documented in
> > > > > https://git-scm.com/docs/git-format-patch#_base_tree_information]
> > > > >
> > > > > url: https://github.com/intel-lab-lkp/linux/commits/Brian-Gerst/x86-stackprotector-32-Remove-stack-protector-test-script/20231027-000533
> > > > > base: tip/master
> > > > > patch link: https://lore.kernel.org/r/20231026160100.195099-6-brgerst%40gmail.com
> > > > > patch subject: [PATCH v2 05/11] x86/stackprotector/64: Convert stack protector to normal percpu variable
> > > > > config: x86_64-rhel-8.3-rust (https://download.01.org/0day-ci/archive/20231029/[email protected]/config)
> > > > > compiler: clang version 16.0.4 (https://github.com/llvm/llvm-project.git ae42196bc493ffe877a7e3dff8be32035dea4d07)
> > > > > reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231029/[email protected]/reproduce)
> > > > >
> > > > > If you fix the issue in a separate patch/commit (i.e. not just a new version of
> > > > > the same patch/commit), kindly add following tags
> > > > > | Reported-by: kernel test robot <[email protected]>
> > > > > | Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
> > > > >
> > > > > All errors (new ones prefixed by >>):
> > > > >
> > > > > >> Unsupported relocation type: unknown type rel type name (42)
> > > >
> > > > Clang is generating a new relocation type (R_X86_64_REX_GOTPCRELX)
> > > > that the relocs tool doesn't know about. This is supposed to allow
> > > > movq __stack_chk_guard@GOTPCREL(%rip), %rax
> > > > movq %gs:(%rax), %rax
> > > > to be relaxed to
> > > > leaq __stack_chk_guard(%rip), %rax
> > > > movq %gs:(%rax), %rax
> > > >
> > > > But why is clang doing this instead of what GCC does?
> > > > movq %gs:__stack_chk_guard(%rip), %rax

https://github.com/llvm/llvm-project/issues/60116 has some discussions
on this topic.

clang-16 -fno-pic -fstack-protector -mstack-protector-guard-reg=gs
-mstack-protector-guard-symbol=__stack_chk_guard
uses a GOT-generating relocation for __stack_chk_guard. This avoids a
copy relocation for userspace but the kernel seems to really want an
absolute relocation,
so https://reviews.llvm.org/D150841 (milestone: clang 17) has implemented it.

> If an `R_X86_64_32` relocation is used and `__stack_chk_guard` is defined by a shared object, copy relocation. We will need an ELF hack called [copy relocation](https://maskray.me/blog/2021-01-09-copy-relocations-canonical-plt-entries-and-protected).

> > > Digging a bit deeper, there also appears to be differences in how the
> > > linkers behave with this new relocation:
> > >
> > > make CC=clang LD=ld:
> > > ffffffff81002838: 48 c7 c0 c0 5c 42 83 mov $0xffffffff83425cc0,%rax
> > > ffffffff8100283b: R_X86_64_32S __stack_chk_guard
> > > ffffffff8100283f: 65 48 8b 00 mov %gs:(%rax),%rax
> > >
> > > make CC=clang LD=ld.lld:
> > > ffffffff81002838: 48 8d 05 81 34 42 02 lea
> > > 0x2423481(%rip),%rax # ffffffff83425cc0 <__stack_chk_guard>
> > > ffffffff8100283b: R_X86_64_REX_GOTPCRELX
> > > __stack_chk_guard-0x4
> > > ffffffff8100283f: 65 48 8b 00 mov %gs:(%rax),%rax
> > >
> > > The LLVM linker keeps the R_X86_64_REX_GOTPCRELX even after performing
> > > the relaxation. It should be R_X86_64_32S based on it changing to an
> > > LEA instruction. The GNU linker changes it to R_X86_64_32S and a MOV
> > > immediate.
>
> Correction: It should be R_X86_64_PC32 for the LEA instruction.
>
> Brian Gerst

Whether --emit-relocs converts the original relocation type is debatable.
I have some comments on a similar topic on RISC-V:
https://sourceware.org/bugzilla/show_bug.cgi?id=30844#c6

> So it seems that ppc performed conversion can all be described by existing relocation types, which is nice.
>
> However, I do not know whether the property will hold for all current and future RISC-V relaxation schemes.
>
> When investigating relocation overflow pressure for x86-64 small code model, I have found that preserving the original relocation type gives me more information: I can tell how
many R_X86_64_PC32/R_X86_64_GOTPCRELX/R_X86_64_REX_GOTPCRELX are
problematic. If they are converted to R_X86_64_PC32/R_X86_64_32, I'd
lose some information.
>
> Perhaps whether the --emit-relocs uses the original relocation type or the transformed relocation type , does not matter for the majority of use cases. E.g. Linux kernel's objtool, seems to perform a sanity check on relocations. It just needs to know the categories of relocations, e.g. absolute/PC-relative, not the exact type.



--
宋方睿