867 lines · 21.7 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0+//// Security related flags and so on.//// Copyright 2018, Michael Ellerman, IBM Corporation. #include <linux/cpu.h>#include <linux/kernel.h>#include <linux/device.h>#include <linux/memblock.h>#include <linux/nospec.h>#include <linux/prctl.h>#include <linux/seq_buf.h>#include <linux/sysfs.h>#include <linux/debugfs.h> #include <asm/asm-prototypes.h>#include <asm/text-patching.h>#include <asm/security_features.h>#include <asm/sections.h>#include <asm/setup.h>#include <asm/inst.h> #include "setup.h" u64 powerpc_security_features __read_mostly = SEC_FTR_DEFAULT; enum branch_cache_flush_type {	BRANCH_CACHE_FLUSH_NONE	= 0x1,	BRANCH_CACHE_FLUSH_SW	= 0x2,	BRANCH_CACHE_FLUSH_HW	= 0x4,};static enum branch_cache_flush_type count_cache_flush_type = BRANCH_CACHE_FLUSH_NONE;static enum branch_cache_flush_type link_stack_flush_type = BRANCH_CACHE_FLUSH_NONE; bool barrier_nospec_enabled;static bool no_nospec;static bool btb_flush_enabled;#if defined(CONFIG_PPC_E500) || defined(CONFIG_PPC_BOOK3S_64)static bool no_spectrev2;#endif static void enable_barrier_nospec(bool enable){	barrier_nospec_enabled = enable;	do_barrier_nospec_fixups(enable);} void __init setup_barrier_nospec(void){	bool enable; 	/*	 * It would make sense to check SEC_FTR_SPEC_BAR_ORI31 below as well.	 * But there's a good reason not to. The two flags we check below are	 * both are enabled by default in the kernel, so if the hcall is not	 * functional they will be enabled.	 * On a system where the host firmware has been updated (so the ori	 * functions as a barrier), but on which the hypervisor (KVM/Qemu) has	 * not been updated, we would like to enable the barrier. Dropping the	 * check for SEC_FTR_SPEC_BAR_ORI31 achieves that. The only downside is	 * we potentially enable the barrier on systems where the host firmware	 * is not updated, but that's harmless as it's a no-op.	 */	enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) &&		 security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR); 	if (!no_nospec && !cpu_mitigations_off())		enable_barrier_nospec(enable);} static int __init handle_nospectre_v1(char *p){	no_nospec = true; 	return 0;}early_param("nospectre_v1", handle_nospectre_v1); #ifdef CONFIG_DEBUG_FSstatic int barrier_nospec_set(void *data, u64 val){	switch (val) {	case 0:	case 1:		break;	default:		return -EINVAL;	} 	if (!!val == !!barrier_nospec_enabled)		return 0; 	enable_barrier_nospec(!!val); 	return 0;} static int barrier_nospec_get(void *data, u64 *val){	*val = barrier_nospec_enabled ? 1 : 0;	return 0;} DEFINE_DEBUGFS_ATTRIBUTE(fops_barrier_nospec, barrier_nospec_get,			 barrier_nospec_set, "%llu\n"); static __init int barrier_nospec_debugfs_init(void){	debugfs_create_file_unsafe("barrier_nospec", 0600,				   arch_debugfs_dir, NULL,				   &fops_barrier_nospec);	return 0;}device_initcall(barrier_nospec_debugfs_init); static __init int security_feature_debugfs_init(void){	debugfs_create_x64("security_features", 0400, arch_debugfs_dir,			   &powerpc_security_features);	return 0;}device_initcall(security_feature_debugfs_init);#endif /* CONFIG_DEBUG_FS */ #if defined(CONFIG_PPC_E500) || defined(CONFIG_PPC_BOOK3S_64)static int __init handle_nospectre_v2(char *p){	no_spectrev2 = true; 	return 0;}early_param("nospectre_v2", handle_nospectre_v2);#endif /* CONFIG_PPC_E500 || CONFIG_PPC_BOOK3S_64 */ #ifdef CONFIG_PPC_E500void __init setup_spectre_v2(void){	if (no_spectrev2 || cpu_mitigations_off())		do_btb_flush_fixups();	else		btb_flush_enabled = true;}#endif /* CONFIG_PPC_E500 */ #ifdef CONFIG_PPC_BOOK3S_64ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf){	bool thread_priv; 	thread_priv = security_ftr_enabled(SEC_FTR_L1D_THREAD_PRIV); 	if (rfi_flush) {		struct seq_buf s;		seq_buf_init(&s, buf, PAGE_SIZE - 1); 		seq_buf_printf(&s, "Mitigation: RFI Flush");		if (thread_priv)			seq_buf_printf(&s, ", L1D private per thread"); 		seq_buf_printf(&s, "\n"); 		return s.len;	} 	if (thread_priv)		return sysfs_emit(buf, "Vulnerable: L1D private per thread\n"); 	if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) &&	    !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR))		return sysfs_emit(buf, "Not affected\n"); 	return sysfs_emit(buf, "Vulnerable\n");} ssize_t cpu_show_l1tf(struct device *dev, struct device_attribute *attr, char *buf){	return cpu_show_meltdown(dev, attr, buf);}#endif ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf){	struct seq_buf s; 	seq_buf_init(&s, buf, PAGE_SIZE - 1); 	if (security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR)) {		if (barrier_nospec_enabled)			seq_buf_printf(&s, "Mitigation: __user pointer sanitization");		else			seq_buf_printf(&s, "Vulnerable"); 		if (security_ftr_enabled(SEC_FTR_SPEC_BAR_ORI31))			seq_buf_printf(&s, ", ori31 speculation barrier enabled"); 		seq_buf_printf(&s, "\n");	} else		seq_buf_printf(&s, "Not affected\n"); 	return s.len;} ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf){	struct seq_buf s;	bool bcs, ccd; 	seq_buf_init(&s, buf, PAGE_SIZE - 1); 	bcs = security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED);	ccd = security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED); 	if (bcs || ccd) {		seq_buf_printf(&s, "Mitigation: "); 		if (bcs)			seq_buf_printf(&s, "Indirect branch serialisation (kernel only)"); 		if (bcs && ccd)			seq_buf_printf(&s, ", "); 		if (ccd)			seq_buf_printf(&s, "Indirect branch cache disabled"); 	} else if (count_cache_flush_type != BRANCH_CACHE_FLUSH_NONE) {		seq_buf_printf(&s, "Mitigation: Software count cache flush"); 		if (count_cache_flush_type == BRANCH_CACHE_FLUSH_HW)			seq_buf_printf(&s, " (hardware accelerated)"); 	} else if (btb_flush_enabled) {		seq_buf_printf(&s, "Mitigation: Branch predictor state flush");	} else {		seq_buf_printf(&s, "Vulnerable");	} 	if (bcs || ccd || count_cache_flush_type != BRANCH_CACHE_FLUSH_NONE) {		if (link_stack_flush_type != BRANCH_CACHE_FLUSH_NONE)			seq_buf_printf(&s, ", Software link stack flush");		if (link_stack_flush_type == BRANCH_CACHE_FLUSH_HW)			seq_buf_printf(&s, " (hardware accelerated)");	} 	seq_buf_printf(&s, "\n"); 	return s.len;} #ifdef CONFIG_PPC_BOOK3S_64/* * Store-forwarding barrier support. */ static enum stf_barrier_type stf_enabled_flush_types;static bool no_stf_barrier;static bool stf_barrier; static int __init handle_no_stf_barrier(char *p){	pr_info("stf-barrier: disabled on command line.");	no_stf_barrier = true;	return 0;} early_param("no_stf_barrier", handle_no_stf_barrier); enum stf_barrier_type stf_barrier_type_get(void){	return stf_enabled_flush_types;} /* This is the generic flag used by other architectures */static int __init handle_ssbd(char *p){	if (!p || strncmp(p, "auto", 5) == 0 || strncmp(p, "on", 2) == 0 ) {		/* Until firmware tells us, we have the barrier with auto */		return 0;	} else if (strncmp(p, "off", 3) == 0) {		handle_no_stf_barrier(NULL);		return 0;	} else		return 1; 	return 0;}early_param("spec_store_bypass_disable", handle_ssbd); /* This is the generic flag used by other architectures */static int __init handle_no_ssbd(char *p){	handle_no_stf_barrier(NULL);	return 0;}early_param("nospec_store_bypass_disable", handle_no_ssbd); static void stf_barrier_enable(bool enable){	if (enable)		do_stf_barrier_fixups(stf_enabled_flush_types);	else		do_stf_barrier_fixups(STF_BARRIER_NONE); 	stf_barrier = enable;} void setup_stf_barrier(void){	enum stf_barrier_type type;	bool enable; 	/* Default to fallback in case fw-features are not available */	if (cpu_has_feature(CPU_FTR_ARCH_300))		type = STF_BARRIER_EIEIO;	else if (cpu_has_feature(CPU_FTR_ARCH_207S))		type = STF_BARRIER_SYNC_ORI;	else if (cpu_has_feature(CPU_FTR_ARCH_206))		type = STF_BARRIER_FALLBACK;	else		type = STF_BARRIER_NONE; 	enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) &&		 security_ftr_enabled(SEC_FTR_STF_BARRIER); 	if (type == STF_BARRIER_FALLBACK) {		pr_info("stf-barrier: fallback barrier available\n");	} else if (type == STF_BARRIER_SYNC_ORI) {		pr_info("stf-barrier: hwsync barrier available\n");	} else if (type == STF_BARRIER_EIEIO) {		pr_info("stf-barrier: eieio barrier available\n");	} 	stf_enabled_flush_types = type; 	if (!no_stf_barrier && !cpu_mitigations_off())		stf_barrier_enable(enable);} ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *attr, char *buf){	if (stf_barrier && stf_enabled_flush_types != STF_BARRIER_NONE) {		const char *type;		switch (stf_enabled_flush_types) {		case STF_BARRIER_EIEIO:			type = "eieio";			break;		case STF_BARRIER_SYNC_ORI:			type = "hwsync";			break;		case STF_BARRIER_FALLBACK:			type = "fallback";			break;		default:			type = "unknown";		}		return sysfs_emit(buf, "Mitigation: Kernel entry/exit barrier (%s)\n", type);	} 	if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) &&	    !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR))		return sysfs_emit(buf, "Not affected\n"); 	return sysfs_emit(buf, "Vulnerable\n");} static int ssb_prctl_get(struct task_struct *task){	/*	 * The STF_BARRIER feature is on by default, so if it's off that means	 * firmware has explicitly said the CPU is not vulnerable via either	 * the hypercall or device tree.	 */	if (!security_ftr_enabled(SEC_FTR_STF_BARRIER))		return PR_SPEC_NOT_AFFECTED; 	/*	 * If the system's CPU has no known barrier (see setup_stf_barrier())	 * then assume that the CPU is not vulnerable.	 */	if (stf_enabled_flush_types == STF_BARRIER_NONE)		return PR_SPEC_NOT_AFFECTED; 	/*	 * Otherwise the CPU is vulnerable. The barrier is not a global or	 * per-process mitigation, so the only value that can be reported here	 * is PR_SPEC_ENABLE, which appears as "vulnerable" in /proc.	 */	return PR_SPEC_ENABLE;} int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which){	switch (which) {	case PR_SPEC_STORE_BYPASS:		return ssb_prctl_get(task);	default:		return -ENODEV;	}} #ifdef CONFIG_DEBUG_FSstatic int stf_barrier_set(void *data, u64 val){	bool enable; 	if (val == 1)		enable = true;	else if (val == 0)		enable = false;	else		return -EINVAL; 	/* Only do anything if we're changing state */	if (enable != stf_barrier)		stf_barrier_enable(enable); 	return 0;} static int stf_barrier_get(void *data, u64 *val){	*val = stf_barrier ? 1 : 0;	return 0;} DEFINE_DEBUGFS_ATTRIBUTE(fops_stf_barrier, stf_barrier_get, stf_barrier_set,			 "%llu\n"); static __init int stf_barrier_debugfs_init(void){	debugfs_create_file_unsafe("stf_barrier", 0600, arch_debugfs_dir,				   NULL, &fops_stf_barrier);	return 0;}device_initcall(stf_barrier_debugfs_init);#endif /* CONFIG_DEBUG_FS */ static void update_branch_cache_flush(void){	u32 *site, __maybe_unused *site2; #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE	site = &patch__call_kvm_flush_link_stack;	site2 = &patch__call_kvm_flush_link_stack_p9;	// This controls the branch from guest_exit_cont to kvm_flush_link_stack	if (link_stack_flush_type == BRANCH_CACHE_FLUSH_NONE) {		patch_instruction_site(site, ppc_inst(PPC_RAW_NOP()));		patch_instruction_site(site2, ppc_inst(PPC_RAW_NOP()));	} else {		// Could use HW flush, but that could also flush count cache		patch_branch_site(site, (u64)&kvm_flush_link_stack, BRANCH_SET_LINK);		patch_branch_site(site2, (u64)&kvm_flush_link_stack, BRANCH_SET_LINK);	}#endif 	// Patch out the bcctr first, then nop the rest	site = &patch__call_flush_branch_caches3;	patch_instruction_site(site, ppc_inst(PPC_RAW_NOP()));	site = &patch__call_flush_branch_caches2;	patch_instruction_site(site, ppc_inst(PPC_RAW_NOP()));	site = &patch__call_flush_branch_caches1;	patch_instruction_site(site, ppc_inst(PPC_RAW_NOP())); 	// This controls the branch from _switch to flush_branch_caches	if (count_cache_flush_type == BRANCH_CACHE_FLUSH_NONE &&	    link_stack_flush_type == BRANCH_CACHE_FLUSH_NONE) {		// Nothing to be done 	} else if (count_cache_flush_type == BRANCH_CACHE_FLUSH_HW &&		   link_stack_flush_type == BRANCH_CACHE_FLUSH_HW) {		// Patch in the bcctr last		site = &patch__call_flush_branch_caches1;		patch_instruction_site(site, ppc_inst(0x39207fff)); // li r9,0x7fff		site = &patch__call_flush_branch_caches2;		patch_instruction_site(site, ppc_inst(0x7d2903a6)); // mtctr r9		site = &patch__call_flush_branch_caches3;		patch_instruction_site(site, ppc_inst(PPC_INST_BCCTR_FLUSH)); 	} else {		patch_branch_site(site, (u64)&flush_branch_caches, BRANCH_SET_LINK); 		// If we just need to flush the link stack, early return		if (count_cache_flush_type == BRANCH_CACHE_FLUSH_NONE) {			patch_instruction_site(&patch__flush_link_stack_return,					       ppc_inst(PPC_RAW_BLR())); 		// If we have flush instruction, early return		} else if (count_cache_flush_type == BRANCH_CACHE_FLUSH_HW) {			patch_instruction_site(&patch__flush_count_cache_return,					       ppc_inst(PPC_RAW_BLR()));		}	}} static void toggle_branch_cache_flush(bool enable){	if (!enable || !security_ftr_enabled(SEC_FTR_FLUSH_COUNT_CACHE)) {		if (count_cache_flush_type != BRANCH_CACHE_FLUSH_NONE)			count_cache_flush_type = BRANCH_CACHE_FLUSH_NONE; 

Lines 1–500 of 867.