Skip to content

Commit ba83088

Browse files
kristina-martsenkowildea01
authored andcommitted
arm64: add prctl control for resetting ptrauth keys
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]>
1 parent ccc4381 commit ba83088

File tree

6 files changed

+71
-0
lines changed

6 files changed

+71
-0
lines changed

arch/arm64/include/asm/pointer_auth.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ static inline void ptrauth_keys_switch(struct ptrauth_keys *keys)
6363
__ptrauth_key_install(APGA, keys->apga);
6464
}
6565

66+
extern int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg);
67+
6668
/*
6769
* The EL0 pointer bits used by a pointer authentication code.
6870
* This is dependent on TBI0 being enabled, or bits 63:56 would also apply.
@@ -86,6 +88,7 @@ do { \
8688
ptrauth_keys_switch(&(tsk)->thread_info.keys_user)
8789

8890
#else /* CONFIG_ARM64_PTR_AUTH */
91+
#define ptrauth_prctl_reset_keys(tsk, arg) (-EINVAL)
8992
#define ptrauth_strip_insn_pac(lr) (lr)
9093
#define ptrauth_thread_init_user(tsk)
9194
#define ptrauth_thread_switch(tsk)

arch/arm64/include/asm/processor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include <asm/hw_breakpoint.h>
4545
#include <asm/lse.h>
4646
#include <asm/pgtable-hwdef.h>
47+
#include <asm/pointer_auth.h>
4748
#include <asm/ptrace.h>
4849
#include <asm/types.h>
4950

@@ -289,6 +290,9 @@ extern void __init minsigstksz_setup(void);
289290
#define SVE_SET_VL(arg) sve_set_current_vl(arg)
290291
#define SVE_GET_VL() sve_get_current_vl()
291292

293+
/* PR_PAC_RESET_KEYS prctl */
294+
#define PAC_RESET_KEYS(tsk, arg) ptrauth_prctl_reset_keys(tsk, arg)
295+
292296
/*
293297
* For CONFIG_GCC_PLUGIN_STACKLEAK
294298
*

arch/arm64/kernel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
5858
arm64-obj-$(CONFIG_CRASH_CORE) += crash_core.o
5959
arm64-obj-$(CONFIG_ARM_SDE_INTERFACE) += sdei.o
6060
arm64-obj-$(CONFIG_ARM64_SSBD) += ssbd.o
61+
arm64-obj-$(CONFIG_ARM64_PTR_AUTH) += pointer_auth.o
6162

6263
obj-y += $(arm64-obj-y) vdso/ probes/
6364
obj-m += $(arm64-obj-m)

arch/arm64/kernel/pointer_auth.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/errno.h>
4+
#include <linux/prctl.h>
5+
#include <linux/random.h>
6+
#include <linux/sched.h>
7+
#include <asm/cpufeature.h>
8+
#include <asm/pointer_auth.h>
9+
10+
int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg)
11+
{
12+
struct ptrauth_keys *keys = &tsk->thread_info.keys_user;
13+
unsigned long addr_key_mask = PR_PAC_APIAKEY | PR_PAC_APIBKEY |
14+
PR_PAC_APDAKEY | PR_PAC_APDBKEY;
15+
unsigned long key_mask = addr_key_mask | PR_PAC_APGAKEY;
16+
17+
if (!system_supports_address_auth() && !system_supports_generic_auth())
18+
return -EINVAL;
19+
20+
if (!arg) {
21+
ptrauth_keys_init(keys);
22+
ptrauth_keys_switch(keys);
23+
return 0;
24+
}
25+
26+
if (arg & ~key_mask)
27+
return -EINVAL;
28+
29+
if (((arg & addr_key_mask) && !system_supports_address_auth()) ||
30+
((arg & PR_PAC_APGAKEY) && !system_supports_generic_auth()))
31+
return -EINVAL;
32+
33+
if (arg & PR_PAC_APIAKEY)
34+
get_random_bytes(&keys->apia, sizeof(keys->apia));
35+
if (arg & PR_PAC_APIBKEY)
36+
get_random_bytes(&keys->apib, sizeof(keys->apib));
37+
if (arg & PR_PAC_APDAKEY)
38+
get_random_bytes(&keys->apda, sizeof(keys->apda));
39+
if (arg & PR_PAC_APDBKEY)
40+
get_random_bytes(&keys->apdb, sizeof(keys->apdb));
41+
if (arg & PR_PAC_APGAKEY)
42+
get_random_bytes(&keys->apga, sizeof(keys->apga));
43+
44+
ptrauth_keys_switch(keys);
45+
46+
return 0;
47+
}

include/uapi/linux/prctl.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,4 +219,12 @@ struct prctl_mm_map {
219219
# define PR_SPEC_DISABLE (1UL << 2)
220220
# define PR_SPEC_FORCE_DISABLE (1UL << 3)
221221

222+
/* Reset arm64 pointer authentication keys */
223+
#define PR_PAC_RESET_KEYS 54
224+
# define PR_PAC_APIAKEY (1UL << 0)
225+
# define PR_PAC_APIBKEY (1UL << 1)
226+
# define PR_PAC_APDAKEY (1UL << 2)
227+
# define PR_PAC_APDBKEY (1UL << 3)
228+
# define PR_PAC_APGAKEY (1UL << 4)
229+
222230
#endif /* _LINUX_PRCTL_H */

kernel/sys.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@
121121
#ifndef SVE_GET_VL
122122
# define SVE_GET_VL() (-EINVAL)
123123
#endif
124+
#ifndef PAC_RESET_KEYS
125+
# define PAC_RESET_KEYS(a, b) (-EINVAL)
126+
#endif
124127

125128
/*
126129
* this is where the system-wide overflow UID and GID are defined, for
@@ -2476,6 +2479,11 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
24762479
return -EINVAL;
24772480
error = arch_prctl_spec_ctrl_set(me, arg2, arg3);
24782481
break;
2482+
case PR_PAC_RESET_KEYS:
2483+
if (arg3 || arg4 || arg5)
2484+
return -EINVAL;
2485+
error = PAC_RESET_KEYS(me, arg2);
2486+
break;
24792487
default:
24802488
error = -EINVAL;
24812489
break;

0 commit comments

Comments
 (0)