diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst index e338306f4587341ef4b5f5377ebd44f321e4b01e..254517e538aebba31469d5e193ab4549afc99456 100644 --- a/Documentation/admin-guide/sysctl/kernel.rst +++ b/Documentation/admin-guide/sysctl/kernel.rst @@ -478,6 +478,27 @@ if leaking kernel pointer values to unprivileged users is a concern. When ``kptr_restrict`` is set to 2, kernel pointers printed using %pK will be replaced with 0s regardless of privileges. +machine_check_safe (arm64 only) +================================ + +Controls the kernel's behaviour when an hardware memory error is +encountered in the following scenarios: + += =================== +1 cow +2 copy_mc_to_kernel +3 copy_from_user +4 copy_to_user +5 get_user +6 put_user += =================== + +Correspondence between sysctl value and behavior: + += ======================= +0 Kernel panic +1 Kill related processes += ======================= modprobe ======== diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index a29559483f26ea1c4f849ce64e222ae677c0c76d..a48ec28b5beede82bec9df705edaee96e2a48e94 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -88,6 +88,8 @@ #define STACK_TOP STACK_TOP_MAX #endif /* CONFIG_COMPAT */ +extern int sysctl_machine_check_safe; + #ifndef CONFIG_ARM64_FORCE_52BIT #define arch_get_mmap_end(addr) ((addr > DEFAULT_MAP_WINDOW) ? TASK_SIZE :\ DEFAULT_MAP_WINDOW) diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 4ab0ba6616574a389e5f40c988bef87d54dab589..53cdcbda7cb63f43d664d1b569968b17616807e4 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -40,6 +40,8 @@ #include #include +int sysctl_machine_check_safe = 1; + struct fault_info { int (*fn)(unsigned long addr, unsigned int esr, struct pt_regs *regs); @@ -640,6 +642,9 @@ static bool arm64_do_kernel_sea(void __user *addr, unsigned int esr, if (!IS_ENABLED(CONFIG_ARCH_HAS_COPY_MC)) return false; + if (!sysctl_machine_check_safe) + return false; + if (user_mode(regs)) return false; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index c1eebbcd0a1cb6d75746a5431800a3ea5613a3af..38866c11f8b696aa0feccac2167e69a92ee274de 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -2726,6 +2726,17 @@ static struct ctl_table kern_table[] = { .extra1 = SYSCTL_ZERO, .extra2 = SYSCTL_ONE, }, +#endif +#if defined(CONFIG_ARM64) && defined(CONFIG_ARCH_HAS_COPY_MC) + { + .procname = "machine_check_safe", + .data = &sysctl_machine_check_safe, + .maxlen = sizeof(sysctl_machine_check_safe), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, #endif { } };