New gcc-plugin:
- Enable per-task stack protector for ARM (Ard Biesheuvel) -----BEGIN PGP SIGNATURE----- Comment: Kees Cook <kees@outflux.net> iQJKBAABCgA0FiEEpcP2jyKd1g9yPm4TiXL039xtwCYFAlwYN04WHGtlZXNjb29r QGNocm9taXVtLm9yZwAKCRCJcvTf3G3AJhUkD/4i0FW2fW1tY63lnbKhp6LFSGvF N7OdwPXwS5dlmVY8KFFrJp0GlT8qvJ3Kqwit5QTu9U9Mo32UbAVwB6gEW/kT3oB3 Pk9pR/DMhTTxD6mUjIHq2c/IJgzw42slTbf1ezb5RtmFYaxqbX1A/wKes7ZTtp23 JtNw2EkqDGMeMNDCbIZAaPHC7fwk6t40qgyrLOAHz+jnrL9tEd9/UIdqaRTn6HKE nslegmaDAUmPmmG8UK3RITQBD+FZsizcz/n2xKkCB79fld0qGwlUriacSmwVScBS LzGvVSrjUbfo/oo850RgrE48GxxlQntOF0z1foRQ7EFygk4gPPsqYRE9OvjE2Iid 9BNtImt6mvOw7faD7sS6R9U5n/66Q3qlHi5FcU8ID6wVjwPM0RX0G4SDO/aTL//w FedMx4PPQtzQIH+X0WxI3mXreuEmN36rnQBR6XovBg2IBlmT6zMRXKhC+50U8+89 WCUeWCuUz4p4daPgV4xKJu8H7EJxQN3YQ2IMStJCAgmrMAUX710pkJ5bt7meGg6Y LUPxRVBeQIC9UuJBDWzMbCYpHx/09o8FsFSEd/M6hW9NhGKo6PIGUu+1oy12LuqM eqb+m4wnylUXeaZnDTIYaVzwfCDCcMPTnt2X3Czc1huq8A5pGmfbUGBLMKHVoguA 8J3bD55suTMTZut3vA== =AkLm -----END PGP SIGNATURE----- Merge tag 'gcc-plugins-v4.21-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux Pull gcc-plugins update from Kees Cook: "Both arm and arm64 are gaining per-task stack canaries (to match x86), but arm is being done with a gcc plugin, hence it going through the gcc-plugins tree. New gcc-plugin: - Enable per-task stack protector for ARM (Ard Biesheuvel)" * tag 'gcc-plugins-v4.21-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: ARM: smp: add support for per-task stack canaries
This commit is contained in:
commit
c6f1b355d4
|
@ -1810,6 +1810,21 @@ config XEN
|
|||
help
|
||||
Say Y if you want to run Linux in a Virtual Machine on Xen on ARM.
|
||||
|
||||
config STACKPROTECTOR_PER_TASK
|
||||
bool "Use a unique stack canary value for each task"
|
||||
depends on GCC_PLUGINS && STACKPROTECTOR && SMP && !XIP_DEFLATED_DATA
|
||||
select GCC_PLUGIN_ARM_SSP_PER_TASK
|
||||
default y
|
||||
help
|
||||
Due to the fact that GCC uses an ordinary symbol reference from
|
||||
which to load the value of the stack canary, this value can only
|
||||
change at reboot time on SMP systems, and all tasks running in the
|
||||
kernel's address space are forced to use the same canary value for
|
||||
the entire duration that the system is up.
|
||||
|
||||
Enable this option to switch to a different method that uses a
|
||||
different canary value for each task.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Boot options"
|
||||
|
|
|
@ -303,6 +303,18 @@ else
|
|||
KBUILD_IMAGE := $(boot)/zImage
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_STACKPROTECTOR_PER_TASK),y)
|
||||
prepare: stack_protector_prepare
|
||||
stack_protector_prepare: prepare0
|
||||
$(eval KBUILD_CFLAGS += \
|
||||
-fplugin-arg-arm_ssp_per_task_plugin-tso=$(shell \
|
||||
awk '{if ($$2 == "THREAD_SZ_ORDER") print $$3;}'\
|
||||
include/generated/asm-offsets.h) \
|
||||
-fplugin-arg-arm_ssp_per_task_plugin-offset=$(shell \
|
||||
awk '{if ($$2 == "TI_STACK_CANARY") print $$3;}'\
|
||||
include/generated/asm-offsets.h))
|
||||
endif
|
||||
|
||||
all: $(notdir $(KBUILD_IMAGE))
|
||||
|
||||
|
||||
|
|
|
@ -101,6 +101,7 @@ clean-files += piggy_data lib1funcs.S ashldi3.S bswapsdi2.S \
|
|||
$(libfdt) $(libfdt_hdrs) hyp-stub.S
|
||||
|
||||
KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
|
||||
KBUILD_CFLAGS += $(DISABLE_ARM_SSP_PER_TASK_PLUGIN)
|
||||
|
||||
ifeq ($(CONFIG_FUNCTION_TRACER),y)
|
||||
ORIG_CFLAGS := $(KBUILD_CFLAGS)
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
* the stack frame and verifying that it hasn't been overwritten when
|
||||
* returning from the function. The pattern is called stack canary
|
||||
* and gcc expects it to be defined by a global variable called
|
||||
* "__stack_chk_guard" on ARM. This unfortunately means that on SMP
|
||||
* we cannot have a different canary value per task.
|
||||
* "__stack_chk_guard" on ARM. This prevents SMP systems from using a
|
||||
* different value for each task unless we enable a GCC plugin that
|
||||
* replaces these symbol references with references to each task's own
|
||||
* value.
|
||||
*/
|
||||
|
||||
#ifndef _ASM_STACKPROTECTOR_H
|
||||
|
@ -16,6 +18,8 @@
|
|||
#include <linux/random.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include <asm/thread_info.h>
|
||||
|
||||
extern unsigned long __stack_chk_guard;
|
||||
|
||||
/*
|
||||
|
@ -33,7 +37,11 @@ static __always_inline void boot_init_stack_canary(void)
|
|||
canary ^= LINUX_VERSION_CODE;
|
||||
|
||||
current->stack_canary = canary;
|
||||
#ifndef CONFIG_STACKPROTECTOR_PER_TASK
|
||||
__stack_chk_guard = current->stack_canary;
|
||||
#else
|
||||
current_thread_info()->stack_canary = current->stack_canary;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* _ASM_STACKPROTECTOR_H */
|
||||
|
|
|
@ -53,6 +53,9 @@ struct thread_info {
|
|||
struct task_struct *task; /* main task structure */
|
||||
__u32 cpu; /* cpu */
|
||||
__u32 cpu_domain; /* cpu domain */
|
||||
#ifdef CONFIG_STACKPROTECTOR_PER_TASK
|
||||
unsigned long stack_canary;
|
||||
#endif
|
||||
struct cpu_context_save cpu_context; /* cpu context */
|
||||
__u32 syscall; /* syscall number */
|
||||
__u8 used_cp[16]; /* thread used copro */
|
||||
|
|
|
@ -79,6 +79,10 @@ int main(void)
|
|||
#ifdef CONFIG_CRUNCH
|
||||
DEFINE(TI_CRUNCH_STATE, offsetof(struct thread_info, crunchstate));
|
||||
#endif
|
||||
#ifdef CONFIG_STACKPROTECTOR_PER_TASK
|
||||
DEFINE(TI_STACK_CANARY, offsetof(struct thread_info, stack_canary));
|
||||
#endif
|
||||
DEFINE(THREAD_SZ_ORDER, THREAD_SIZE_ORDER);
|
||||
BLANK();
|
||||
DEFINE(S_R0, offsetof(struct pt_regs, ARM_r0));
|
||||
DEFINE(S_R1, offsetof(struct pt_regs, ARM_r1));
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
#include <asm/tls.h>
|
||||
#include <asm/vdso.h>
|
||||
|
||||
#ifdef CONFIG_STACKPROTECTOR
|
||||
#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_STACKPROTECTOR_PER_TASK)
|
||||
#include <linux/stackprotector.h>
|
||||
unsigned long __stack_chk_guard __read_mostly;
|
||||
EXPORT_SYMBOL(__stack_chk_guard);
|
||||
|
@ -267,6 +267,10 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,
|
|||
|
||||
thread_notify(THREAD_NOTIFY_COPY, thread);
|
||||
|
||||
#ifdef CONFIG_STACKPROTECTOR_PER_TASK
|
||||
thread->stack_canary = p->stack_canary;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,12 @@ ifdef CONFIG_GCC_PLUGIN_STACKLEAK
|
|||
endif
|
||||
export DISABLE_STACKLEAK_PLUGIN
|
||||
|
||||
gcc-plugin-$(CONFIG_GCC_PLUGIN_ARM_SSP_PER_TASK) += arm_ssp_per_task_plugin.so
|
||||
ifdef CONFIG_GCC_PLUGIN_ARM_SSP_PER_TASK
|
||||
DISABLE_ARM_SSP_PER_TASK_PLUGIN += -fplugin-arg-arm_ssp_per_task_plugin-disable
|
||||
endif
|
||||
export DISABLE_ARM_SSP_PER_TASK_PLUGIN
|
||||
|
||||
# All the plugin CFLAGS are collected here in case a build target needs to
|
||||
# filter them out of the KBUILD_CFLAGS.
|
||||
GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y))
|
||||
|
|
|
@ -190,4 +190,8 @@ config STACKLEAK_RUNTIME_DISABLE
|
|||
runtime to control kernel stack erasing for kernels built with
|
||||
CONFIG_GCC_PLUGIN_STACKLEAK.
|
||||
|
||||
config GCC_PLUGIN_ARM_SSP_PER_TASK
|
||||
bool
|
||||
depends on GCC_PLUGINS && ARM
|
||||
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#include "gcc-common.h"
|
||||
|
||||
__visible int plugin_is_GPL_compatible;
|
||||
|
||||
static unsigned int sp_mask, canary_offset;
|
||||
|
||||
static unsigned int arm_pertask_ssp_rtl_execute(void)
|
||||
{
|
||||
rtx_insn *insn;
|
||||
|
||||
for (insn = get_insns(); insn; insn = NEXT_INSN(insn)) {
|
||||
const char *sym;
|
||||
rtx body;
|
||||
rtx masked_sp;
|
||||
|
||||
/*
|
||||
* Find a SET insn involving a SYMBOL_REF to __stack_chk_guard
|
||||
*/
|
||||
if (!INSN_P(insn))
|
||||
continue;
|
||||
body = PATTERN(insn);
|
||||
if (GET_CODE(body) != SET ||
|
||||
GET_CODE(SET_SRC(body)) != SYMBOL_REF)
|
||||
continue;
|
||||
sym = XSTR(SET_SRC(body), 0);
|
||||
if (strcmp(sym, "__stack_chk_guard"))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Replace the source of the SET insn with an expression that
|
||||
* produces the address of the copy of the stack canary value
|
||||
* stored in struct thread_info
|
||||
*/
|
||||
masked_sp = gen_reg_rtx(Pmode);
|
||||
|
||||
emit_insn_before(gen_rtx_SET(masked_sp,
|
||||
gen_rtx_AND(Pmode,
|
||||
stack_pointer_rtx,
|
||||
GEN_INT(sp_mask))),
|
||||
insn);
|
||||
|
||||
SET_SRC(body) = gen_rtx_PLUS(Pmode, masked_sp,
|
||||
GEN_INT(canary_offset));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define PASS_NAME arm_pertask_ssp_rtl
|
||||
|
||||
#define NO_GATE
|
||||
#include "gcc-generate-rtl-pass.h"
|
||||
|
||||
__visible int plugin_init(struct plugin_name_args *plugin_info,
|
||||
struct plugin_gcc_version *version)
|
||||
{
|
||||
const char * const plugin_name = plugin_info->base_name;
|
||||
const int argc = plugin_info->argc;
|
||||
const struct plugin_argument *argv = plugin_info->argv;
|
||||
int tso = 0;
|
||||
int i;
|
||||
|
||||
if (!plugin_default_version_check(version, &gcc_version)) {
|
||||
error(G_("incompatible gcc/plugin versions"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < argc; ++i) {
|
||||
if (!strcmp(argv[i].key, "disable"))
|
||||
return 0;
|
||||
|
||||
/* all remaining options require a value */
|
||||
if (!argv[i].value) {
|
||||
error(G_("no value supplied for option '-fplugin-arg-%s-%s'"),
|
||||
plugin_name, argv[i].key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i].key, "tso")) {
|
||||
tso = atoi(argv[i].value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i].key, "offset")) {
|
||||
canary_offset = atoi(argv[i].value);
|
||||
continue;
|
||||
}
|
||||
error(G_("unknown option '-fplugin-arg-%s-%s'"),
|
||||
plugin_name, argv[i].key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* create the mask that produces the base of the stack */
|
||||
sp_mask = ~((1U << (12 + tso)) - 1);
|
||||
|
||||
PASS_INFO(arm_pertask_ssp_rtl, "expand", 1, PASS_POS_INSERT_AFTER);
|
||||
|
||||
register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP,
|
||||
NULL, &arm_pertask_ssp_rtl_pass_info);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue