Skip to content

Commit

Permalink
arm64: add prctl control for resetting ptrauth keys
Browse files Browse the repository at this point in the history
Add an arm64-specific prctl to allow a thread to reinitialize its
pointer authentication keys to random values. This can be useful when
exec() is not used for starting new processes, to ensure that different
processes still have different keys.

Signed-off-by: Kristina Martsenko <[email protected]>
Signed-off-by: Will Deacon <[email protected]>
  • Loading branch information
kristina-martsenko authored and wildea01 committed Dec 13, 2018
1 parent ccc4381 commit ba83088
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 0 deletions.
3 changes: 3 additions & 0 deletions arch/arm64/include/asm/pointer_auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ static inline void ptrauth_keys_switch(struct ptrauth_keys *keys)
__ptrauth_key_install(APGA, keys->apga);
}

extern int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg);

/*
* The EL0 pointer bits used by a pointer authentication code.
* This is dependent on TBI0 being enabled, or bits 63:56 would also apply.
Expand All @@ -86,6 +88,7 @@ do { \
ptrauth_keys_switch(&(tsk)->thread_info.keys_user)

#else /* CONFIG_ARM64_PTR_AUTH */
#define ptrauth_prctl_reset_keys(tsk, arg) (-EINVAL)
#define ptrauth_strip_insn_pac(lr) (lr)
#define ptrauth_thread_init_user(tsk)
#define ptrauth_thread_switch(tsk)
Expand Down
4 changes: 4 additions & 0 deletions arch/arm64/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include <asm/hw_breakpoint.h>
#include <asm/lse.h>
#include <asm/pgtable-hwdef.h>
#include <asm/pointer_auth.h>
#include <asm/ptrace.h>
#include <asm/types.h>

Expand Down Expand Up @@ -289,6 +290,9 @@ extern void __init minsigstksz_setup(void);
#define SVE_SET_VL(arg) sve_set_current_vl(arg)
#define SVE_GET_VL() sve_get_current_vl()

/* PR_PAC_RESET_KEYS prctl */
#define PAC_RESET_KEYS(tsk, arg) ptrauth_prctl_reset_keys(tsk, arg)

/*
* For CONFIG_GCC_PLUGIN_STACKLEAK
*
Expand Down
1 change: 1 addition & 0 deletions arch/arm64/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
arm64-obj-$(CONFIG_CRASH_CORE) += crash_core.o
arm64-obj-$(CONFIG_ARM_SDE_INTERFACE) += sdei.o
arm64-obj-$(CONFIG_ARM64_SSBD) += ssbd.o
arm64-obj-$(CONFIG_ARM64_PTR_AUTH) += pointer_auth.o

obj-y += $(arm64-obj-y) vdso/ probes/
obj-m += $(arm64-obj-m)
Expand Down
47 changes: 47 additions & 0 deletions arch/arm64/kernel/pointer_auth.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: GPL-2.0

#include <linux/errno.h>
#include <linux/prctl.h>
#include <linux/random.h>
#include <linux/sched.h>
#include <asm/cpufeature.h>
#include <asm/pointer_auth.h>

int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg)
{
struct ptrauth_keys *keys = &tsk->thread_info.keys_user;
unsigned long addr_key_mask = PR_PAC_APIAKEY | PR_PAC_APIBKEY |
PR_PAC_APDAKEY | PR_PAC_APDBKEY;
unsigned long key_mask = addr_key_mask | PR_PAC_APGAKEY;

if (!system_supports_address_auth() && !system_supports_generic_auth())
return -EINVAL;

if (!arg) {
ptrauth_keys_init(keys);
ptrauth_keys_switch(keys);
return 0;
}

if (arg & ~key_mask)
return -EINVAL;

if (((arg & addr_key_mask) && !system_supports_address_auth()) ||
((arg & PR_PAC_APGAKEY) && !system_supports_generic_auth()))
return -EINVAL;

if (arg & PR_PAC_APIAKEY)
get_random_bytes(&keys->apia, sizeof(keys->apia));
if (arg & PR_PAC_APIBKEY)
get_random_bytes(&keys->apib, sizeof(keys->apib));
if (arg & PR_PAC_APDAKEY)
get_random_bytes(&keys->apda, sizeof(keys->apda));
if (arg & PR_PAC_APDBKEY)
get_random_bytes(&keys->apdb, sizeof(keys->apdb));
if (arg & PR_PAC_APGAKEY)
get_random_bytes(&keys->apga, sizeof(keys->apga));

ptrauth_keys_switch(keys);

return 0;
}
8 changes: 8 additions & 0 deletions include/uapi/linux/prctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,4 +219,12 @@ struct prctl_mm_map {
# define PR_SPEC_DISABLE (1UL << 2)
# define PR_SPEC_FORCE_DISABLE (1UL << 3)

/* Reset arm64 pointer authentication keys */
#define PR_PAC_RESET_KEYS 54
# define PR_PAC_APIAKEY (1UL << 0)
# define PR_PAC_APIBKEY (1UL << 1)
# define PR_PAC_APDAKEY (1UL << 2)
# define PR_PAC_APDBKEY (1UL << 3)
# define PR_PAC_APGAKEY (1UL << 4)

#endif /* _LINUX_PRCTL_H */
8 changes: 8 additions & 0 deletions kernel/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@
#ifndef SVE_GET_VL
# define SVE_GET_VL() (-EINVAL)
#endif
#ifndef PAC_RESET_KEYS
# define PAC_RESET_KEYS(a, b) (-EINVAL)
#endif

/*
* this is where the system-wide overflow UID and GID are defined, for
Expand Down Expand Up @@ -2476,6 +2479,11 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
return -EINVAL;
error = arch_prctl_spec_ctrl_set(me, arg2, arg3);
break;
case PR_PAC_RESET_KEYS:
if (arg3 || arg4 || arg5)
return -EINVAL;
error = PAC_RESET_KEYS(me, arg2);
break;
default:
error = -EINVAL;
break;
Expand Down

0 comments on commit ba83088

Please sign in to comment.