arm64/ptrace: Expose GCS via ptrace and core files

Provide a new register type NT_ARM_GCS reporting the current GCS mode
and pointer for EL0.  Due to the interactions with allocation and
deallocation of Guarded Control Stacks we do not permit any changes to
the GCS mode via ptrace, only GCSPR_EL0 may be changed.

Reviewed-by: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20241001-arm64-gcs-v13-27-222b78d87eee@kernel.org
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
This commit is contained in:
Mark Brown 2024-10-01 23:59:06 +01:00 committed by Catalin Marinas
parent 16f47bb9ac
commit 7ec3b57cb2
3 changed files with 70 additions and 1 deletions

View file

@ -324,6 +324,14 @@ struct user_za_header {
#define ZA_PT_SIZE(vq) \
(ZA_PT_ZA_OFFSET + ZA_PT_ZA_SIZE(vq))
/* GCS state (NT_ARM_GCS) */
struct user_gcs {
__u64 features_enabled;
__u64 features_locked;
__u64 gcspr_el0;
};
#endif /* __ASSEMBLY__ */
#endif /* _UAPI__ASM_PTRACE_H */

View file

@ -34,6 +34,7 @@
#include <asm/cpufeature.h>
#include <asm/debug-monitors.h>
#include <asm/fpsimd.h>
#include <asm/gcs.h>
#include <asm/mte.h>
#include <asm/pointer_auth.h>
#include <asm/stacktrace.h>
@ -1473,6 +1474,52 @@ static int poe_set(struct task_struct *target, const struct
}
#endif
#ifdef CONFIG_ARM64_GCS
static int gcs_get(struct task_struct *target,
const struct user_regset *regset,
struct membuf to)
{
struct user_gcs user_gcs;
if (!system_supports_gcs())
return -EINVAL;
if (target == current)
gcs_preserve_current_state();
user_gcs.features_enabled = target->thread.gcs_el0_mode;
user_gcs.features_locked = target->thread.gcs_el0_locked;
user_gcs.gcspr_el0 = target->thread.gcspr_el0;
return membuf_write(&to, &user_gcs, sizeof(user_gcs));
}
static int gcs_set(struct task_struct *target, const struct
user_regset *regset, unsigned int pos,
unsigned int count, const void *kbuf, const
void __user *ubuf)
{
int ret;
struct user_gcs user_gcs;
if (!system_supports_gcs())
return -EINVAL;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &user_gcs, 0, -1);
if (ret)
return ret;
if (user_gcs.features_enabled & ~PR_SHADOW_STACK_SUPPORTED_STATUS_MASK)
return -EINVAL;
target->thread.gcs_el0_mode = user_gcs.features_enabled;
target->thread.gcs_el0_locked = user_gcs.features_locked;
target->thread.gcspr_el0 = user_gcs.gcspr_el0;
return 0;
}
#endif
enum aarch64_regset {
REGSET_GPR,
REGSET_FPR,
@ -1503,7 +1550,10 @@ enum aarch64_regset {
REGSET_TAGGED_ADDR_CTRL,
#endif
#ifdef CONFIG_ARM64_POE
REGSET_POE
REGSET_POE,
#endif
#ifdef CONFIG_ARM64_GCS
REGSET_GCS,
#endif
};
@ -1674,6 +1724,16 @@ static const struct user_regset aarch64_regsets[] = {
.set = poe_set,
},
#endif
#ifdef CONFIG_ARM64_GCS
[REGSET_GCS] = {
.core_note_type = NT_ARM_GCS,
.n = sizeof(struct user_gcs) / sizeof(u64),
.size = sizeof(u64),
.align = sizeof(u64),
.regset_get = gcs_get,
.set = gcs_set,
},
#endif
};
static const struct user_regset_view user_aarch64_view = {

View file

@ -443,6 +443,7 @@ typedef struct elf64_shdr {
#define NT_ARM_ZT 0x40d /* ARM SME ZT registers */
#define NT_ARM_FPMR 0x40e /* ARM floating point mode register */
#define NT_ARM_POE 0x40f /* ARM POE registers */
#define NT_ARM_GCS 0x410 /* ARM GCS state */
#define NT_ARC_V2 0x600 /* ARCv2 accumulator/extra registers */
#define NT_VMCOREDD 0x700 /* Vmcore Device Dump Note */
#define NT_MIPS_DSP 0x800 /* MIPS DSP ASE registers */