mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-13 14:24:11 +08:00
arm64 fixes for -rc6
- Fix handling of POR_EL0 during signal delivery so that pushing the signal context doesn't fail based on the pkey configuration of the interrupted context and align our user-visible behaviour with that of x86. - Fix a bogus pointer being passed to the CPU hotplug code from the Arm SDEI driver. - Re-enable software tag-based KASAN with GCC by using an alternative implementation of '__no_sanitize_address'. -----BEGIN PGP SIGNATURE----- iQFEBAABCgAuFiEEPxTL6PPUbjXGY88ct6xw3ITBYzQFAmcjr8wQHHdpbGxAa2Vy bmVsLm9yZwAKCRC3rHDchMFjNL2DB/4tNl7feCA2V4fW/Eu3RzXrHTdJbZvTjLDl JjeXPZr4WdGQQMgQ0DPZtpnmeBzd5nswx9WHG9VSsUxc5g+rzWxwvMnUeplDvEXo Y/QMUq4JZN3eqDZWPs0mEN4fMI+QOihInErVHvFXaJLcbxYrU5BvfwExgfY53AjT ZJEPmF291OL6V4UCWVWggk44BQaTBeWmc4itJcYm6z6mIgAgh84MZGK5M0e582ip CRAImDiAPqLxRO9kzKcYthI3FDyyVi1HtiSL1CiNktOXMNz19qPelq1XAnDEyvBt TEUitTLTwbUJ0nqi4u7ve09aebneAq8nsGucteYTrBU4U/PRjvQO =LTB9 -----END PGP SIGNATURE----- Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux Pull arm64 fixes from Will Deacon: "The important one is a change to the way in which we handle protection keys around signal delivery so that we're more closely aligned with the x86 behaviour, however there is also a revert of the previous fix to disable software tag-based KASAN with GCC, since a workaround materialised shortly afterwards. I'd love to say we're done with 6.12, but we're aware of some longstanding fpsimd register corruption issues that we're almost at the bottom of resolving. Summary: - Fix handling of POR_EL0 during signal delivery so that pushing the signal context doesn't fail based on the pkey configuration of the interrupted context and align our user-visible behaviour with that of x86. - Fix a bogus pointer being passed to the CPU hotplug code from the Arm SDEI driver. - Re-enable software tag-based KASAN with GCC by using an alternative implementation of '__no_sanitize_address'" * tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: arm64: signal: Improve POR_EL0 handling to avoid uaccess failures firmware: arm_sdei: Fix the input parameter of cpuhp_remove_state() Revert "kasan: Disable Software Tag-Based KASAN with GCC" kasan: Fix Software Tag-Based KASAN with GCC
This commit is contained in:
commit
3dfffd506e
@ -19,6 +19,7 @@
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/rseq.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/pkeys.h>
|
||||
|
||||
#include <asm/daifflags.h>
|
||||
#include <asm/debug-monitors.h>
|
||||
@ -66,10 +67,63 @@ struct rt_sigframe_user_layout {
|
||||
unsigned long end_offset;
|
||||
};
|
||||
|
||||
/*
|
||||
* Holds any EL0-controlled state that influences unprivileged memory accesses.
|
||||
* This includes both accesses done in userspace and uaccess done in the kernel.
|
||||
*
|
||||
* This state needs to be carefully managed to ensure that it doesn't cause
|
||||
* uaccess to fail when setting up the signal frame, and the signal handler
|
||||
* itself also expects a well-defined state when entered.
|
||||
*/
|
||||
struct user_access_state {
|
||||
u64 por_el0;
|
||||
};
|
||||
|
||||
#define BASE_SIGFRAME_SIZE round_up(sizeof(struct rt_sigframe), 16)
|
||||
#define TERMINATOR_SIZE round_up(sizeof(struct _aarch64_ctx), 16)
|
||||
#define EXTRA_CONTEXT_SIZE round_up(sizeof(struct extra_context), 16)
|
||||
|
||||
/*
|
||||
* Save the user access state into ua_state and reset it to disable any
|
||||
* restrictions.
|
||||
*/
|
||||
static void save_reset_user_access_state(struct user_access_state *ua_state)
|
||||
{
|
||||
if (system_supports_poe()) {
|
||||
u64 por_enable_all = 0;
|
||||
|
||||
for (int pkey = 0; pkey < arch_max_pkey(); pkey++)
|
||||
por_enable_all |= POE_RXW << (pkey * POR_BITS_PER_PKEY);
|
||||
|
||||
ua_state->por_el0 = read_sysreg_s(SYS_POR_EL0);
|
||||
write_sysreg_s(por_enable_all, SYS_POR_EL0);
|
||||
/* Ensure that any subsequent uaccess observes the updated value */
|
||||
isb();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the user access state for invoking the signal handler.
|
||||
*
|
||||
* No uaccess should be done after that function is called.
|
||||
*/
|
||||
static void set_handler_user_access_state(void)
|
||||
{
|
||||
if (system_supports_poe())
|
||||
write_sysreg_s(POR_EL0_INIT, SYS_POR_EL0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore the user access state to the values saved in ua_state.
|
||||
*
|
||||
* No uaccess should be done after that function is called.
|
||||
*/
|
||||
static void restore_user_access_state(const struct user_access_state *ua_state)
|
||||
{
|
||||
if (system_supports_poe())
|
||||
write_sysreg_s(ua_state->por_el0, SYS_POR_EL0);
|
||||
}
|
||||
|
||||
static void init_user_layout(struct rt_sigframe_user_layout *user)
|
||||
{
|
||||
const size_t reserved_size =
|
||||
@ -261,18 +315,20 @@ static int restore_fpmr_context(struct user_ctxs *user)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int preserve_poe_context(struct poe_context __user *ctx)
|
||||
static int preserve_poe_context(struct poe_context __user *ctx,
|
||||
const struct user_access_state *ua_state)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
__put_user_error(POE_MAGIC, &ctx->head.magic, err);
|
||||
__put_user_error(sizeof(*ctx), &ctx->head.size, err);
|
||||
__put_user_error(read_sysreg_s(SYS_POR_EL0), &ctx->por_el0, err);
|
||||
__put_user_error(ua_state->por_el0, &ctx->por_el0, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int restore_poe_context(struct user_ctxs *user)
|
||||
static int restore_poe_context(struct user_ctxs *user,
|
||||
struct user_access_state *ua_state)
|
||||
{
|
||||
u64 por_el0;
|
||||
int err = 0;
|
||||
@ -282,7 +338,7 @@ static int restore_poe_context(struct user_ctxs *user)
|
||||
|
||||
__get_user_error(por_el0, &(user->poe->por_el0), err);
|
||||
if (!err)
|
||||
write_sysreg_s(por_el0, SYS_POR_EL0);
|
||||
ua_state->por_el0 = por_el0;
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -850,7 +906,8 @@ invalid:
|
||||
}
|
||||
|
||||
static int restore_sigframe(struct pt_regs *regs,
|
||||
struct rt_sigframe __user *sf)
|
||||
struct rt_sigframe __user *sf,
|
||||
struct user_access_state *ua_state)
|
||||
{
|
||||
sigset_t set;
|
||||
int i, err;
|
||||
@ -899,7 +956,7 @@ static int restore_sigframe(struct pt_regs *regs,
|
||||
err = restore_zt_context(&user);
|
||||
|
||||
if (err == 0 && system_supports_poe() && user.poe)
|
||||
err = restore_poe_context(&user);
|
||||
err = restore_poe_context(&user, ua_state);
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -908,6 +965,7 @@ SYSCALL_DEFINE0(rt_sigreturn)
|
||||
{
|
||||
struct pt_regs *regs = current_pt_regs();
|
||||
struct rt_sigframe __user *frame;
|
||||
struct user_access_state ua_state;
|
||||
|
||||
/* Always make any pending restarted system calls return -EINTR */
|
||||
current->restart_block.fn = do_no_restart_syscall;
|
||||
@ -924,12 +982,14 @@ SYSCALL_DEFINE0(rt_sigreturn)
|
||||
if (!access_ok(frame, sizeof (*frame)))
|
||||
goto badframe;
|
||||
|
||||
if (restore_sigframe(regs, frame))
|
||||
if (restore_sigframe(regs, frame, &ua_state))
|
||||
goto badframe;
|
||||
|
||||
if (restore_altstack(&frame->uc.uc_stack))
|
||||
goto badframe;
|
||||
|
||||
restore_user_access_state(&ua_state);
|
||||
|
||||
return regs->regs[0];
|
||||
|
||||
badframe:
|
||||
@ -1035,7 +1095,8 @@ static int setup_sigframe_layout(struct rt_sigframe_user_layout *user,
|
||||
}
|
||||
|
||||
static int setup_sigframe(struct rt_sigframe_user_layout *user,
|
||||
struct pt_regs *regs, sigset_t *set)
|
||||
struct pt_regs *regs, sigset_t *set,
|
||||
const struct user_access_state *ua_state)
|
||||
{
|
||||
int i, err = 0;
|
||||
struct rt_sigframe __user *sf = user->sigframe;
|
||||
@ -1097,10 +1158,9 @@ static int setup_sigframe(struct rt_sigframe_user_layout *user,
|
||||
struct poe_context __user *poe_ctx =
|
||||
apply_user_offset(user, user->poe_offset);
|
||||
|
||||
err |= preserve_poe_context(poe_ctx);
|
||||
err |= preserve_poe_context(poe_ctx, ua_state);
|
||||
}
|
||||
|
||||
|
||||
/* ZA state if present */
|
||||
if (system_supports_sme() && err == 0 && user->za_offset) {
|
||||
struct za_context __user *za_ctx =
|
||||
@ -1237,9 +1297,6 @@ static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
|
||||
sme_smstop();
|
||||
}
|
||||
|
||||
if (system_supports_poe())
|
||||
write_sysreg_s(POR_EL0_INIT, SYS_POR_EL0);
|
||||
|
||||
if (ka->sa.sa_flags & SA_RESTORER)
|
||||
sigtramp = ka->sa.sa_restorer;
|
||||
else
|
||||
@ -1253,6 +1310,7 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
|
||||
{
|
||||
struct rt_sigframe_user_layout user;
|
||||
struct rt_sigframe __user *frame;
|
||||
struct user_access_state ua_state;
|
||||
int err = 0;
|
||||
|
||||
fpsimd_signal_preserve_current_state();
|
||||
@ -1260,13 +1318,14 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
|
||||
if (get_sigframe(&user, ksig, regs))
|
||||
return 1;
|
||||
|
||||
save_reset_user_access_state(&ua_state);
|
||||
frame = user.sigframe;
|
||||
|
||||
__put_user_error(0, &frame->uc.uc_flags, err);
|
||||
__put_user_error(NULL, &frame->uc.uc_link, err);
|
||||
|
||||
err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
|
||||
err |= setup_sigframe(&user, regs, set);
|
||||
err |= setup_sigframe(&user, regs, set, &ua_state);
|
||||
if (err == 0) {
|
||||
setup_return(regs, &ksig->ka, &user, usig);
|
||||
if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
|
||||
@ -1276,6 +1335,11 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
|
||||
}
|
||||
}
|
||||
|
||||
if (err == 0)
|
||||
set_handler_user_access_state();
|
||||
else
|
||||
restore_user_access_state(&ua_state);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -763,7 +763,7 @@ static int sdei_device_freeze(struct device *dev)
|
||||
int err;
|
||||
|
||||
/* unregister private events */
|
||||
cpuhp_remove_state(sdei_entry_point);
|
||||
cpuhp_remove_state(sdei_hp_state);
|
||||
|
||||
err = sdei_unregister_shared();
|
||||
if (err)
|
||||
|
@ -80,7 +80,11 @@
|
||||
#define __noscs __attribute__((__no_sanitize__("shadow-call-stack")))
|
||||
#endif
|
||||
|
||||
#ifdef __SANITIZE_HWADDRESS__
|
||||
#define __no_sanitize_address __attribute__((__no_sanitize__("hwaddress")))
|
||||
#else
|
||||
#define __no_sanitize_address __attribute__((__no_sanitize_address__))
|
||||
#endif
|
||||
|
||||
#if defined(__SANITIZE_THREAD__)
|
||||
#define __no_sanitize_thread __attribute__((__no_sanitize_thread__))
|
||||
|
@ -22,11 +22,8 @@ config ARCH_DISABLE_KASAN_INLINE
|
||||
config CC_HAS_KASAN_GENERIC
|
||||
def_bool $(cc-option, -fsanitize=kernel-address)
|
||||
|
||||
# GCC appears to ignore no_sanitize_address when -fsanitize=kernel-hwaddress
|
||||
# is passed. See https://bugzilla.kernel.org/show_bug.cgi?id=218854 (and
|
||||
# the linked LKML thread) for more details.
|
||||
config CC_HAS_KASAN_SW_TAGS
|
||||
def_bool !CC_IS_GCC && $(cc-option, -fsanitize=kernel-hwaddress)
|
||||
def_bool $(cc-option, -fsanitize=kernel-hwaddress)
|
||||
|
||||
# This option is only required for software KASAN modes.
|
||||
# Old GCC versions do not have proper support for no_sanitize_address.
|
||||
@ -101,7 +98,7 @@ config KASAN_SW_TAGS
|
||||
help
|
||||
Enables Software Tag-Based KASAN.
|
||||
|
||||
Requires Clang.
|
||||
Requires GCC 11+ or Clang.
|
||||
|
||||
Supported only on arm64 CPUs and relies on Top Byte Ignore.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user