Skip to content

Commit eaf62ce

Browse files
brooniectmarinas
authored andcommitted
arm64/signal: Set up and restore the GCS context for signal handlers
When invoking a signal handler we use the GCS configuration and stack for the current thread. Since we implement signal return by calling the signal handler with a return address set up pointing to a trampoline in the vDSO we need to also configure any active GCS for this by pushing a frame for the trampoline onto the GCS. If we do not do this then signal return will generate a GCS protection fault. In order to guard against attempts to bypass GCS protections via signal return we only allow returning with GCSPR_EL0 pointing to an address where it was previously preempted by a signal. We do this by pushing a cap onto the GCS, this takes the form of an architectural GCS cap token with the top bit set and token type of 0 which we add on signal entry and validate and pop off on signal return. The combination of the top bit being set and the token type mean that this can't be interpreted as a valid token or address. Reviewed-by: Thiago Jung Bauermann <[email protected]> Reviewed-by: Catalin Marinas <[email protected]> Signed-off-by: Mark Brown <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Catalin Marinas <[email protected]>
1 parent 8f3e750 commit eaf62ce

File tree

2 files changed

+114
-5
lines changed

2 files changed

+114
-5
lines changed

arch/arm64/include/asm/gcs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <asm/uaccess.h>
1010

1111
struct kernel_clone_args;
12+
struct ksignal;
1213

1314
static inline void gcsb_dsync(void)
1415
{

arch/arm64/kernel/signal.c

Lines changed: 113 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <asm/elf.h>
2626
#include <asm/exception.h>
2727
#include <asm/cacheflush.h>
28+
#include <asm/gcs.h>
2829
#include <asm/ucontext.h>
2930
#include <asm/unistd.h>
3031
#include <asm/fpsimd.h>
@@ -34,6 +35,15 @@
3435
#include <asm/traps.h>
3536
#include <asm/vdso.h>
3637

38+
#ifdef CONFIG_ARM64_GCS
39+
#define GCS_SIGNAL_CAP(addr) (((unsigned long)addr) & GCS_CAP_ADDR_MASK)
40+
41+
static bool gcs_signal_cap_valid(u64 addr, u64 val)
42+
{
43+
return val == GCS_SIGNAL_CAP(addr);
44+
}
45+
#endif
46+
3747
/*
3848
* Do a signal return; undo the signal stack. These are aligned to 128-bit.
3949
*/
@@ -904,6 +914,58 @@ static int restore_sigframe(struct pt_regs *regs,
904914
return err;
905915
}
906916

917+
#ifdef CONFIG_ARM64_GCS
918+
static int gcs_restore_signal(void)
919+
{
920+
unsigned long __user *gcspr_el0;
921+
u64 cap;
922+
int ret;
923+
924+
if (!system_supports_gcs())
925+
return 0;
926+
927+
if (!(current->thread.gcs_el0_mode & PR_SHADOW_STACK_ENABLE))
928+
return 0;
929+
930+
gcspr_el0 = (unsigned long __user *)read_sysreg_s(SYS_GCSPR_EL0);
931+
932+
/*
933+
* Ensure that any changes to the GCS done via GCS operations
934+
* are visible to the normal reads we do to validate the
935+
* token.
936+
*/
937+
gcsb_dsync();
938+
939+
/*
940+
* GCSPR_EL0 should be pointing at a capped GCS, read the cap.
941+
* We don't enforce that this is in a GCS page, if it is not
942+
* then faults will be generated on GCS operations - the main
943+
* concern is to protect GCS pages.
944+
*/
945+
ret = copy_from_user(&cap, gcspr_el0, sizeof(cap));
946+
if (ret)
947+
return -EFAULT;
948+
949+
/*
950+
* Check that the cap is the actual GCS before replacing it.
951+
*/
952+
if (!gcs_signal_cap_valid((u64)gcspr_el0, cap))
953+
return -EINVAL;
954+
955+
/* Invalidate the token to prevent reuse */
956+
put_user_gcs(0, (__user void*)gcspr_el0, &ret);
957+
if (ret != 0)
958+
return -EFAULT;
959+
960+
write_sysreg_s(gcspr_el0 + 1, SYS_GCSPR_EL0);
961+
962+
return 0;
963+
}
964+
965+
#else
966+
static int gcs_restore_signal(void) { return 0; }
967+
#endif
968+
907969
SYSCALL_DEFINE0(rt_sigreturn)
908970
{
909971
struct pt_regs *regs = current_pt_regs();
@@ -927,6 +989,9 @@ SYSCALL_DEFINE0(rt_sigreturn)
927989
if (restore_sigframe(regs, frame))
928990
goto badframe;
929991

992+
if (gcs_restore_signal())
993+
goto badframe;
994+
930995
if (restore_altstack(&frame->uc.uc_stack))
931996
goto badframe;
932997

@@ -1189,15 +1254,56 @@ static int get_sigframe(struct rt_sigframe_user_layout *user,
11891254
return 0;
11901255
}
11911256

1192-
static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
1257+
#ifdef CONFIG_ARM64_GCS
1258+
1259+
static int gcs_signal_entry(__sigrestore_t sigtramp, struct ksignal *ksig)
1260+
{
1261+
unsigned long __user *gcspr_el0;
1262+
int ret = 0;
1263+
1264+
if (!system_supports_gcs())
1265+
return 0;
1266+
1267+
if (!task_gcs_el0_enabled(current))
1268+
return 0;
1269+
1270+
/*
1271+
* We are entering a signal handler, current register state is
1272+
* active.
1273+
*/
1274+
gcspr_el0 = (unsigned long __user *)read_sysreg_s(SYS_GCSPR_EL0);
1275+
1276+
/*
1277+
* Push a cap and the GCS entry for the trampoline onto the GCS.
1278+
*/
1279+
put_user_gcs((unsigned long)sigtramp, gcspr_el0 - 2, &ret);
1280+
put_user_gcs(GCS_SIGNAL_CAP(gcspr_el0 - 1), gcspr_el0 - 1, &ret);
1281+
if (ret != 0)
1282+
return ret;
1283+
1284+
gcspr_el0 -= 2;
1285+
write_sysreg_s((unsigned long)gcspr_el0, SYS_GCSPR_EL0);
1286+
1287+
return 0;
1288+
}
1289+
#else
1290+
1291+
static int gcs_signal_entry(__sigrestore_t sigtramp, struct ksignal *ksig)
1292+
{
1293+
return 0;
1294+
}
1295+
1296+
#endif
1297+
1298+
static int setup_return(struct pt_regs *regs, struct ksignal *ksig,
11931299
struct rt_sigframe_user_layout *user, int usig)
11941300
{
11951301
__sigrestore_t sigtramp;
11961302

11971303
regs->regs[0] = usig;
11981304
regs->sp = (unsigned long)user->sigframe;
11991305
regs->regs[29] = (unsigned long)&user->next_frame->fp;
1200-
regs->pc = (unsigned long)ka->sa.sa_handler;
1306+
regs->pc = (unsigned long)ksig->ka.sa.sa_handler;
12011307

12021308
/*
12031309
* Signal delivery is a (wacky) indirect function call in
@@ -1240,12 +1346,14 @@ static void setup_return(struct pt_regs *regs, struct k_sigaction *ka,
12401346
if (system_supports_poe())
12411347
write_sysreg_s(POR_EL0_INIT, SYS_POR_EL0);
12421348

1243-
if (ka->sa.sa_flags & SA_RESTORER)
1244-
sigtramp = ka->sa.sa_restorer;
1349+
if (ksig->ka.sa.sa_flags & SA_RESTORER)
1350+
sigtramp = ksig->ka.sa.sa_restorer;
12451351
else
12461352
sigtramp = VDSO_SYMBOL(current->mm->context.vdso, sigtramp);
12471353

12481354
regs->regs[30] = (unsigned long)sigtramp;
1355+
1356+
return gcs_signal_entry(sigtramp, ksig);
12491357
}
12501358

12511359
static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
@@ -1268,7 +1376,7 @@ static int setup_rt_frame(int usig, struct ksignal *ksig, sigset_t *set,
12681376
err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
12691377
err |= setup_sigframe(&user, regs, set);
12701378
if (err == 0) {
1271-
setup_return(regs, &ksig->ka, &user, usig);
1379+
err = setup_return(regs, ksig, &user, usig);
12721380
if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
12731381
err |= copy_siginfo_to_user(&frame->info, &ksig->info);
12741382
regs->regs[1] = (unsigned long)&frame->info;

0 commit comments

Comments
 (0)