Skip to content

Commit 63f0c60

Browse files
ctmarinaswilldeacon
authored andcommitted
arm64: Introduce prctl() options to control the tagged user addresses ABI
It is not desirable to relax the ABI to allow tagged user addresses into the kernel indiscriminately. This patch introduces a prctl() interface for enabling or disabling the tagged ABI with a global sysctl control for preventing applications from enabling the relaxed ABI (meant for testing user-space prctl() return error checking without reconfiguring the kernel). The ABI properties are inherited by threads of the same application and fork()'ed children but cleared on execve(). A Kconfig option allows the overall disabling of the relaxed ABI. The PR_SET_TAGGED_ADDR_CTRL will be expanded in the future to handle MTE-specific settings like imprecise vs precise exceptions. Reviewed-by: Kees Cook <[email protected]> Signed-off-by: Catalin Marinas <[email protected]> Signed-off-by: Andrey Konovalov <[email protected]> Signed-off-by: Will Deacon <[email protected]>
1 parent 2b835e2 commit 63f0c60

File tree

7 files changed

+111
-1
lines changed

7 files changed

+111
-1
lines changed

arch/arm64/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,6 +1110,15 @@ config ARM64_SW_TTBR0_PAN
11101110
zeroed area and reserved ASID. The user access routines
11111111
restore the valid TTBR0_EL1 temporarily.
11121112

1113+
config ARM64_TAGGED_ADDR_ABI
1114+
bool "Enable the tagged user addresses syscall ABI"
1115+
default y
1116+
help
1117+
When this option is enabled, user applications can opt in to a
1118+
relaxed ABI via prctl() allowing tagged addresses to be passed
1119+
to system calls as pointer arguments. For details, see
1120+
Documentation/arm64/tagged-address-abi.txt.
1121+
11131122
menuconfig COMPAT
11141123
bool "Kernel support for 32-bit EL0"
11151124
depends on ARM64_4K_PAGES || EXPERT

arch/arm64/include/asm/processor.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,14 @@ extern void __init minsigstksz_setup(void);
306306
/* PR_PAC_RESET_KEYS prctl */
307307
#define PAC_RESET_KEYS(tsk, arg) ptrauth_prctl_reset_keys(tsk, arg)
308308

309+
#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
310+
/* PR_{SET,GET}_TAGGED_ADDR_CTRL prctl */
311+
long set_tagged_addr_ctrl(unsigned long arg);
312+
long get_tagged_addr_ctrl(void);
313+
#define SET_TAGGED_ADDR_CTRL(arg) set_tagged_addr_ctrl(arg)
314+
#define GET_TAGGED_ADDR_CTRL() get_tagged_addr_ctrl()
315+
#endif
316+
309317
/*
310318
* For CONFIG_GCC_PLUGIN_STACKLEAK
311319
*

arch/arm64/include/asm/thread_info.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ void arch_release_task_struct(struct task_struct *tsk);
9090
#define TIF_SVE 23 /* Scalable Vector Extension in use */
9191
#define TIF_SVE_VL_INHERIT 24 /* Inherit sve_vl_onexec across exec */
9292
#define TIF_SSBD 25 /* Wants SSB mitigation */
93+
#define TIF_TAGGED_ADDR 26 /* Allow tagged user addresses */
9394

9495
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
9596
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)

arch/arm64/include/asm/uaccess.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,9 @@ static inline unsigned long __range_ok(const void __user *addr, unsigned long si
6262
{
6363
unsigned long ret, limit = current_thread_info()->addr_limit;
6464

65-
addr = untagged_addr(addr);
65+
if (IS_ENABLED(CONFIG_ARM64_TAGGED_ADDR_ABI) &&
66+
test_thread_flag(TIF_TAGGED_ADDR))
67+
addr = untagged_addr(addr);
6668

6769
__chk_user_ptr(addr);
6870
asm volatile(

arch/arm64/kernel/process.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/kernel.h>
2020
#include <linux/mm.h>
2121
#include <linux/stddef.h>
22+
#include <linux/sysctl.h>
2223
#include <linux/unistd.h>
2324
#include <linux/user.h>
2425
#include <linux/delay.h>
@@ -38,6 +39,7 @@
3839
#include <trace/events/power.h>
3940
#include <linux/percpu.h>
4041
#include <linux/thread_info.h>
42+
#include <linux/prctl.h>
4143

4244
#include <asm/alternative.h>
4345
#include <asm/arch_gicv3.h>
@@ -307,11 +309,18 @@ static void tls_thread_flush(void)
307309
}
308310
}
309311

312+
static void flush_tagged_addr_state(void)
313+
{
314+
if (IS_ENABLED(CONFIG_ARM64_TAGGED_ADDR_ABI))
315+
clear_thread_flag(TIF_TAGGED_ADDR);
316+
}
317+
310318
void flush_thread(void)
311319
{
312320
fpsimd_flush_thread();
313321
tls_thread_flush();
314322
flush_ptrace_hw_breakpoint(current);
323+
flush_tagged_addr_state();
315324
}
316325

317326
void release_thread(struct task_struct *dead_task)
@@ -565,3 +574,67 @@ void arch_setup_new_exec(void)
565574

566575
ptrauth_thread_init_user(current);
567576
}
577+
578+
#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
579+
/*
580+
* Control the relaxed ABI allowing tagged user addresses into the kernel.
581+
*/
582+
static unsigned int tagged_addr_prctl_allowed = 1;
583+
584+
long set_tagged_addr_ctrl(unsigned long arg)
585+
{
586+
if (!tagged_addr_prctl_allowed)
587+
return -EINVAL;
588+
if (is_compat_task())
589+
return -EINVAL;
590+
if (arg & ~PR_TAGGED_ADDR_ENABLE)
591+
return -EINVAL;
592+
593+
update_thread_flag(TIF_TAGGED_ADDR, arg & PR_TAGGED_ADDR_ENABLE);
594+
595+
return 0;
596+
}
597+
598+
long get_tagged_addr_ctrl(void)
599+
{
600+
if (!tagged_addr_prctl_allowed)
601+
return -EINVAL;
602+
if (is_compat_task())
603+
return -EINVAL;
604+
605+
if (test_thread_flag(TIF_TAGGED_ADDR))
606+
return PR_TAGGED_ADDR_ENABLE;
607+
608+
return 0;
609+
}
610+
611+
/*
612+
* Global sysctl to disable the tagged user addresses support. This control
613+
* only prevents the tagged address ABI enabling via prctl() and does not
614+
* disable it for tasks that already opted in to the relaxed ABI.
615+
*/
616+
static int zero;
617+
static int one = 1;
618+
619+
static struct ctl_table tagged_addr_sysctl_table[] = {
620+
{
621+
.procname = "tagged_addr",
622+
.mode = 0644,
623+
.data = &tagged_addr_prctl_allowed,
624+
.maxlen = sizeof(int),
625+
.proc_handler = proc_dointvec_minmax,
626+
.extra1 = &zero,
627+
.extra2 = &one,
628+
},
629+
{ }
630+
};
631+
632+
static int __init tagged_addr_init(void)
633+
{
634+
if (!register_sysctl("abi", tagged_addr_sysctl_table))
635+
return -EINVAL;
636+
return 0;
637+
}
638+
639+
core_initcall(tagged_addr_init);
640+
#endif /* CONFIG_ARM64_TAGGED_ADDR_ABI */

include/uapi/linux/prctl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,4 +229,9 @@ struct prctl_mm_map {
229229
# define PR_PAC_APDBKEY (1UL << 3)
230230
# define PR_PAC_APGAKEY (1UL << 4)
231231

232+
/* Tagged user address controls for arm64 */
233+
#define PR_SET_TAGGED_ADDR_CTRL 55
234+
#define PR_GET_TAGGED_ADDR_CTRL 56
235+
# define PR_TAGGED_ADDR_ENABLE (1UL << 0)
236+
232237
#endif /* _LINUX_PRCTL_H */

kernel/sys.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,12 @@
124124
#ifndef PAC_RESET_KEYS
125125
# define PAC_RESET_KEYS(a, b) (-EINVAL)
126126
#endif
127+
#ifndef SET_TAGGED_ADDR_CTRL
128+
# define SET_TAGGED_ADDR_CTRL(a) (-EINVAL)
129+
#endif
130+
#ifndef GET_TAGGED_ADDR_CTRL
131+
# define GET_TAGGED_ADDR_CTRL() (-EINVAL)
132+
#endif
127133

128134
/*
129135
* this is where the system-wide overflow UID and GID are defined, for
@@ -2492,6 +2498,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
24922498
return -EINVAL;
24932499
error = PAC_RESET_KEYS(me, arg2);
24942500
break;
2501+
case PR_SET_TAGGED_ADDR_CTRL:
2502+
error = SET_TAGGED_ADDR_CTRL(arg2);
2503+
break;
2504+
case PR_GET_TAGGED_ADDR_CTRL:
2505+
error = GET_TAGGED_ADDR_CTRL();
2506+
break;
24952507
default:
24962508
error = -EINVAL;
24972509
break;

0 commit comments

Comments
 (0)