forked from luck/tmp_suning_uos_patched
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
|
help
|
||||||
Say Y if you want to run Linux in a Virtual Machine on Xen on ARM.
|
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
|
endmenu
|
||||||
|
|
||||||
menu "Boot options"
|
menu "Boot options"
|
||||||
|
|
|
@ -303,6 +303,18 @@ else
|
||||||
KBUILD_IMAGE := $(boot)/zImage
|
KBUILD_IMAGE := $(boot)/zImage
|
||||||
endif
|
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))
|
all: $(notdir $(KBUILD_IMAGE))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,7 @@ clean-files += piggy_data lib1funcs.S ashldi3.S bswapsdi2.S \
|
||||||
$(libfdt) $(libfdt_hdrs) hyp-stub.S
|
$(libfdt) $(libfdt_hdrs) hyp-stub.S
|
||||||
|
|
||||||
KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
|
KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
|
||||||
|
KBUILD_CFLAGS += $(DISABLE_ARM_SSP_PER_TASK_PLUGIN)
|
||||||
|
|
||||||
ifeq ($(CONFIG_FUNCTION_TRACER),y)
|
ifeq ($(CONFIG_FUNCTION_TRACER),y)
|
||||||
ORIG_CFLAGS := $(KBUILD_CFLAGS)
|
ORIG_CFLAGS := $(KBUILD_CFLAGS)
|
||||||
|
|
|
@ -6,8 +6,10 @@
|
||||||
* the stack frame and verifying that it hasn't been overwritten when
|
* the stack frame and verifying that it hasn't been overwritten when
|
||||||
* returning from the function. The pattern is called stack canary
|
* returning from the function. The pattern is called stack canary
|
||||||
* and gcc expects it to be defined by a global variable called
|
* and gcc expects it to be defined by a global variable called
|
||||||
* "__stack_chk_guard" on ARM. This unfortunately means that on SMP
|
* "__stack_chk_guard" on ARM. This prevents SMP systems from using a
|
||||||
* we cannot have a different canary value per task.
|
* 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
|
#ifndef _ASM_STACKPROTECTOR_H
|
||||||
|
@ -16,6 +18,8 @@
|
||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include <linux/version.h>
|
#include <linux/version.h>
|
||||||
|
|
||||||
|
#include <asm/thread_info.h>
|
||||||
|
|
||||||
extern unsigned long __stack_chk_guard;
|
extern unsigned long __stack_chk_guard;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -33,7 +37,11 @@ static __always_inline void boot_init_stack_canary(void)
|
||||||
canary ^= LINUX_VERSION_CODE;
|
canary ^= LINUX_VERSION_CODE;
|
||||||
|
|
||||||
current->stack_canary = canary;
|
current->stack_canary = canary;
|
||||||
|
#ifndef CONFIG_STACKPROTECTOR_PER_TASK
|
||||||
__stack_chk_guard = current->stack_canary;
|
__stack_chk_guard = current->stack_canary;
|
||||||
|
#else
|
||||||
|
current_thread_info()->stack_canary = current->stack_canary;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _ASM_STACKPROTECTOR_H */
|
#endif /* _ASM_STACKPROTECTOR_H */
|
||||||
|
|
|
@ -53,6 +53,9 @@ struct thread_info {
|
||||||
struct task_struct *task; /* main task structure */
|
struct task_struct *task; /* main task structure */
|
||||||
__u32 cpu; /* cpu */
|
__u32 cpu; /* cpu */
|
||||||
__u32 cpu_domain; /* cpu domain */
|
__u32 cpu_domain; /* cpu domain */
|
||||||
|
#ifdef CONFIG_STACKPROTECTOR_PER_TASK
|
||||||
|
unsigned long stack_canary;
|
||||||
|
#endif
|
||||||
struct cpu_context_save cpu_context; /* cpu context */
|
struct cpu_context_save cpu_context; /* cpu context */
|
||||||
__u32 syscall; /* syscall number */
|
__u32 syscall; /* syscall number */
|
||||||
__u8 used_cp[16]; /* thread used copro */
|
__u8 used_cp[16]; /* thread used copro */
|
||||||
|
|
|
@ -79,6 +79,10 @@ int main(void)
|
||||||
#ifdef CONFIG_CRUNCH
|
#ifdef CONFIG_CRUNCH
|
||||||
DEFINE(TI_CRUNCH_STATE, offsetof(struct thread_info, crunchstate));
|
DEFINE(TI_CRUNCH_STATE, offsetof(struct thread_info, crunchstate));
|
||||||
#endif
|
#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();
|
BLANK();
|
||||||
DEFINE(S_R0, offsetof(struct pt_regs, ARM_r0));
|
DEFINE(S_R0, offsetof(struct pt_regs, ARM_r0));
|
||||||
DEFINE(S_R1, offsetof(struct pt_regs, ARM_r1));
|
DEFINE(S_R1, offsetof(struct pt_regs, ARM_r1));
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
#include <asm/tls.h>
|
#include <asm/tls.h>
|
||||||
#include <asm/vdso.h>
|
#include <asm/vdso.h>
|
||||||
|
|
||||||
#ifdef CONFIG_STACKPROTECTOR
|
#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_STACKPROTECTOR_PER_TASK)
|
||||||
#include <linux/stackprotector.h>
|
#include <linux/stackprotector.h>
|
||||||
unsigned long __stack_chk_guard __read_mostly;
|
unsigned long __stack_chk_guard __read_mostly;
|
||||||
EXPORT_SYMBOL(__stack_chk_guard);
|
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);
|
thread_notify(THREAD_NOTIFY_COPY, thread);
|
||||||
|
|
||||||
|
#ifdef CONFIG_STACKPROTECTOR_PER_TASK
|
||||||
|
thread->stack_canary = p->stack_canary;
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,12 @@ ifdef CONFIG_GCC_PLUGIN_STACKLEAK
|
||||||
endif
|
endif
|
||||||
export DISABLE_STACKLEAK_PLUGIN
|
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
|
# All the plugin CFLAGS are collected here in case a build target needs to
|
||||||
# filter them out of the KBUILD_CFLAGS.
|
# filter them out of the KBUILD_CFLAGS.
|
||||||
GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y))
|
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
|
runtime to control kernel stack erasing for kernels built with
|
||||||
CONFIG_GCC_PLUGIN_STACKLEAK.
|
CONFIG_GCC_PLUGIN_STACKLEAK.
|
||||||
|
|
||||||
|
config GCC_PLUGIN_ARM_SSP_PER_TASK
|
||||||
|
bool
|
||||||
|
depends on GCC_PLUGINS && ARM
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
103
scripts/gcc-plugins/arm_ssp_per_task_plugin.c
Normal file
103
scripts/gcc-plugins/arm_ssp_per_task_plugin.c
Normal file
|
@ -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
Block a user