Fix a sparse warning in the arm64 signal code dealing with the user

shadow stack register, GCSPR_EL0.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE5RElWfyWxS+3PLO2a9axLQDIXvEFAmdlufgACgkQa9axLQDI
 XvHS9Q//WmBcPgp99ZgmHwV4x9VZz4lBiZphBp2+WYNmYFjkEcNDggs8nWs+JwgR
 Y1isI5fLEuNYCqjoejtT5iPY3i9YAtiOtq8J7xnlZ35r3Ycur28f4C28ZxQnpHGH
 xaFO7deNTGhUkLvHaxIDxAyu8iHcJL+Q4XwuuTozedHPGwCHb5uyYHZB1fvYTrB0
 x4yxJDBehsN9x/xQPNYlaaXpYG3i0as/1DQod7kKIDckxnGOOk1s1sTPPMTsOMAv
 W9xvUPUmzoRvn7nH1ErT7X3O8LzbACy6RDg1iGzdMINTuLDDM9n55i2tl0TToqqq
 9h5IQ7ZSsPPixrPGarSZMhKnRKLHd0psFwfzhaWdPSGn4MHQInhkIP4vK05ycpxc
 E3AzbQMTb8ABVwW57XeJYnJJ28wY2QvQp0mm96xjSHfhYwafx4heTAM/4jzw5ZwC
 JsIbQsy603Ir7JhSV3rNozAUPI8GdQzXBYZ5PtW0AIbyJHAWP2R+/Q5kGK2IJd7a
 T5fzCLNSd0u7soY/4J856HYsDYw0SC0f6ua9BbaIC99vOlG9PhO/MJIkr+FsPeQq
 O3zH/xg/LGWQYudAoXYJhY6YuQ18mpdMw++/cNci2wWdhApf2sQLrhkO1Kz1numd
 WDDO13hyQZQMeulTeTrkS0teQmhuVeGvgb3vxLJzYi4OIEr8Iv4=
 =sJbw
 -----END PGP SIGNATURE-----

Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux

Pull arm64 fix from Catalin Marinas:
 "Fix a sparse warning in the arm64 signal code dealing with the user
  shadow stack register, GCSPR_EL0"

* tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux:
  arm64/signal: Silence sparse warning storing GCSPR_EL0
This commit is contained in:
Linus Torvalds 2024-12-20 14:10:01 -08:00
commit 499551201b
1 changed files with 15 additions and 20 deletions

View File

@ -36,15 +36,8 @@
#include <asm/traps.h> #include <asm/traps.h>
#include <asm/vdso.h> #include <asm/vdso.h>
#ifdef CONFIG_ARM64_GCS
#define GCS_SIGNAL_CAP(addr) (((unsigned long)addr) & GCS_CAP_ADDR_MASK) #define GCS_SIGNAL_CAP(addr) (((unsigned long)addr) & GCS_CAP_ADDR_MASK)
static bool gcs_signal_cap_valid(u64 addr, u64 val)
{
return val == GCS_SIGNAL_CAP(addr);
}
#endif
/* /*
* Do a signal return; undo the signal stack. These are aligned to 128-bit. * Do a signal return; undo the signal stack. These are aligned to 128-bit.
*/ */
@ -1062,8 +1055,7 @@ static int restore_sigframe(struct pt_regs *regs,
#ifdef CONFIG_ARM64_GCS #ifdef CONFIG_ARM64_GCS
static int gcs_restore_signal(void) static int gcs_restore_signal(void)
{ {
unsigned long __user *gcspr_el0; u64 gcspr_el0, cap;
u64 cap;
int ret; int ret;
if (!system_supports_gcs()) if (!system_supports_gcs())
@ -1072,7 +1064,7 @@ static int gcs_restore_signal(void)
if (!(current->thread.gcs_el0_mode & PR_SHADOW_STACK_ENABLE)) if (!(current->thread.gcs_el0_mode & PR_SHADOW_STACK_ENABLE))
return 0; return 0;
gcspr_el0 = (unsigned long __user *)read_sysreg_s(SYS_GCSPR_EL0); gcspr_el0 = read_sysreg_s(SYS_GCSPR_EL0);
/* /*
* Ensure that any changes to the GCS done via GCS operations * Ensure that any changes to the GCS done via GCS operations
@ -1087,22 +1079,23 @@ static int gcs_restore_signal(void)
* then faults will be generated on GCS operations - the main * then faults will be generated on GCS operations - the main
* concern is to protect GCS pages. * concern is to protect GCS pages.
*/ */
ret = copy_from_user(&cap, gcspr_el0, sizeof(cap)); ret = copy_from_user(&cap, (unsigned long __user *)gcspr_el0,
sizeof(cap));
if (ret) if (ret)
return -EFAULT; return -EFAULT;
/* /*
* Check that the cap is the actual GCS before replacing it. * Check that the cap is the actual GCS before replacing it.
*/ */
if (!gcs_signal_cap_valid((u64)gcspr_el0, cap)) if (cap != GCS_SIGNAL_CAP(gcspr_el0))
return -EINVAL; return -EINVAL;
/* Invalidate the token to prevent reuse */ /* Invalidate the token to prevent reuse */
put_user_gcs(0, (__user void*)gcspr_el0, &ret); put_user_gcs(0, (unsigned long __user *)gcspr_el0, &ret);
if (ret != 0) if (ret != 0)
return -EFAULT; return -EFAULT;
write_sysreg_s(gcspr_el0 + 1, SYS_GCSPR_EL0); write_sysreg_s(gcspr_el0 + 8, SYS_GCSPR_EL0);
return 0; return 0;
} }
@ -1421,7 +1414,7 @@ static int get_sigframe(struct rt_sigframe_user_layout *user,
static int gcs_signal_entry(__sigrestore_t sigtramp, struct ksignal *ksig) static int gcs_signal_entry(__sigrestore_t sigtramp, struct ksignal *ksig)
{ {
unsigned long __user *gcspr_el0; u64 gcspr_el0;
int ret = 0; int ret = 0;
if (!system_supports_gcs()) if (!system_supports_gcs())
@ -1434,18 +1427,20 @@ static int gcs_signal_entry(__sigrestore_t sigtramp, struct ksignal *ksig)
* We are entering a signal handler, current register state is * We are entering a signal handler, current register state is
* active. * active.
*/ */
gcspr_el0 = (unsigned long __user *)read_sysreg_s(SYS_GCSPR_EL0); gcspr_el0 = read_sysreg_s(SYS_GCSPR_EL0);
/* /*
* Push a cap and the GCS entry for the trampoline onto the GCS. * Push a cap and the GCS entry for the trampoline onto the GCS.
*/ */
put_user_gcs((unsigned long)sigtramp, gcspr_el0 - 2, &ret); put_user_gcs((unsigned long)sigtramp,
put_user_gcs(GCS_SIGNAL_CAP(gcspr_el0 - 1), gcspr_el0 - 1, &ret); (unsigned long __user *)(gcspr_el0 - 16), &ret);
put_user_gcs(GCS_SIGNAL_CAP(gcspr_el0 - 8),
(unsigned long __user *)(gcspr_el0 - 8), &ret);
if (ret != 0) if (ret != 0)
return ret; return ret;
gcspr_el0 -= 2; gcspr_el0 -= 16;
write_sysreg_s((unsigned long)gcspr_el0, SYS_GCSPR_EL0); write_sysreg_s(gcspr_el0, SYS_GCSPR_EL0);
return 0; return 0;
} }