mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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 <keescook@chromium.org> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Andrey Konovalov <andreyknvl@google.com> Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
		
							parent
							
								
									2b835e24b5
								
							
						
					
					
						commit
						63f0c60379
					
				
					 7 changed files with 111 additions and 1 deletions
				
			
		| 
						 | 
				
			
			@ -1110,6 +1110,15 @@ config ARM64_SW_TTBR0_PAN
 | 
			
		|||
	  zeroed area and reserved ASID. The user access routines
 | 
			
		||||
	  restore the valid TTBR0_EL1 temporarily.
 | 
			
		||||
 | 
			
		||||
config ARM64_TAGGED_ADDR_ABI
 | 
			
		||||
	bool "Enable the tagged user addresses syscall ABI"
 | 
			
		||||
	default y
 | 
			
		||||
	help
 | 
			
		||||
	  When this option is enabled, user applications can opt in to a
 | 
			
		||||
	  relaxed ABI via prctl() allowing tagged addresses to be passed
 | 
			
		||||
	  to system calls as pointer arguments. For details, see
 | 
			
		||||
	  Documentation/arm64/tagged-address-abi.txt.
 | 
			
		||||
 | 
			
		||||
menuconfig COMPAT
 | 
			
		||||
	bool "Kernel support for 32-bit EL0"
 | 
			
		||||
	depends on ARM64_4K_PAGES || EXPERT
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -306,6 +306,14 @@ extern void __init minsigstksz_setup(void);
 | 
			
		|||
/* PR_PAC_RESET_KEYS prctl */
 | 
			
		||||
#define PAC_RESET_KEYS(tsk, arg)	ptrauth_prctl_reset_keys(tsk, arg)
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
 | 
			
		||||
/* PR_{SET,GET}_TAGGED_ADDR_CTRL prctl */
 | 
			
		||||
long set_tagged_addr_ctrl(unsigned long arg);
 | 
			
		||||
long get_tagged_addr_ctrl(void);
 | 
			
		||||
#define SET_TAGGED_ADDR_CTRL(arg)	set_tagged_addr_ctrl(arg)
 | 
			
		||||
#define GET_TAGGED_ADDR_CTRL()		get_tagged_addr_ctrl()
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * For CONFIG_GCC_PLUGIN_STACKLEAK
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -90,6 +90,7 @@ void arch_release_task_struct(struct task_struct *tsk);
 | 
			
		|||
#define TIF_SVE			23	/* Scalable Vector Extension in use */
 | 
			
		||||
#define TIF_SVE_VL_INHERIT	24	/* Inherit sve_vl_onexec across exec */
 | 
			
		||||
#define TIF_SSBD		25	/* Wants SSB mitigation */
 | 
			
		||||
#define TIF_TAGGED_ADDR		26	/* Allow tagged user addresses */
 | 
			
		||||
 | 
			
		||||
#define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 | 
			
		||||
#define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -62,6 +62,8 @@ static inline unsigned long __range_ok(const void __user *addr, unsigned long si
 | 
			
		|||
{
 | 
			
		||||
	unsigned long ret, limit = current_thread_info()->addr_limit;
 | 
			
		||||
 | 
			
		||||
	if (IS_ENABLED(CONFIG_ARM64_TAGGED_ADDR_ABI) &&
 | 
			
		||||
	    test_thread_flag(TIF_TAGGED_ADDR))
 | 
			
		||||
		addr = untagged_addr(addr);
 | 
			
		||||
 | 
			
		||||
	__chk_user_ptr(addr);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@
 | 
			
		|||
#include <linux/kernel.h>
 | 
			
		||||
#include <linux/mm.h>
 | 
			
		||||
#include <linux/stddef.h>
 | 
			
		||||
#include <linux/sysctl.h>
 | 
			
		||||
#include <linux/unistd.h>
 | 
			
		||||
#include <linux/user.h>
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -38,6 +39,7 @@
 | 
			
		|||
#include <trace/events/power.h>
 | 
			
		||||
#include <linux/percpu.h>
 | 
			
		||||
#include <linux/thread_info.h>
 | 
			
		||||
#include <linux/prctl.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/alternative.h>
 | 
			
		||||
#include <asm/arch_gicv3.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -307,11 +309,18 @@ static void tls_thread_flush(void)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void flush_tagged_addr_state(void)
 | 
			
		||||
{
 | 
			
		||||
	if (IS_ENABLED(CONFIG_ARM64_TAGGED_ADDR_ABI))
 | 
			
		||||
		clear_thread_flag(TIF_TAGGED_ADDR);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void flush_thread(void)
 | 
			
		||||
{
 | 
			
		||||
	fpsimd_flush_thread();
 | 
			
		||||
	tls_thread_flush();
 | 
			
		||||
	flush_ptrace_hw_breakpoint(current);
 | 
			
		||||
	flush_tagged_addr_state();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void release_thread(struct task_struct *dead_task)
 | 
			
		||||
| 
						 | 
				
			
			@ -565,3 +574,67 @@ void arch_setup_new_exec(void)
 | 
			
		|||
 | 
			
		||||
	ptrauth_thread_init_user(current);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
 | 
			
		||||
/*
 | 
			
		||||
 * Control the relaxed ABI allowing tagged user addresses into the kernel.
 | 
			
		||||
 */
 | 
			
		||||
static unsigned int tagged_addr_prctl_allowed = 1;
 | 
			
		||||
 | 
			
		||||
long set_tagged_addr_ctrl(unsigned long arg)
 | 
			
		||||
{
 | 
			
		||||
	if (!tagged_addr_prctl_allowed)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	if (is_compat_task())
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	if (arg & ~PR_TAGGED_ADDR_ENABLE)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	update_thread_flag(TIF_TAGGED_ADDR, arg & PR_TAGGED_ADDR_ENABLE);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
long get_tagged_addr_ctrl(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!tagged_addr_prctl_allowed)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	if (is_compat_task())
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (test_thread_flag(TIF_TAGGED_ADDR))
 | 
			
		||||
		return PR_TAGGED_ADDR_ENABLE;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Global sysctl to disable the tagged user addresses support. This control
 | 
			
		||||
 * only prevents the tagged address ABI enabling via prctl() and does not
 | 
			
		||||
 * disable it for tasks that already opted in to the relaxed ABI.
 | 
			
		||||
 */
 | 
			
		||||
static int zero;
 | 
			
		||||
static int one = 1;
 | 
			
		||||
 | 
			
		||||
static struct ctl_table tagged_addr_sysctl_table[] = {
 | 
			
		||||
	{
 | 
			
		||||
		.procname	= "tagged_addr",
 | 
			
		||||
		.mode		= 0644,
 | 
			
		||||
		.data		= &tagged_addr_prctl_allowed,
 | 
			
		||||
		.maxlen		= sizeof(int),
 | 
			
		||||
		.proc_handler	= proc_dointvec_minmax,
 | 
			
		||||
		.extra1		= &zero,
 | 
			
		||||
		.extra2		= &one,
 | 
			
		||||
	},
 | 
			
		||||
	{ }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int __init tagged_addr_init(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!register_sysctl("abi", tagged_addr_sysctl_table))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
core_initcall(tagged_addr_init);
 | 
			
		||||
#endif	/* CONFIG_ARM64_TAGGED_ADDR_ABI */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -229,4 +229,9 @@ struct prctl_mm_map {
 | 
			
		|||
# define PR_PAC_APDBKEY			(1UL << 3)
 | 
			
		||||
# define PR_PAC_APGAKEY			(1UL << 4)
 | 
			
		||||
 | 
			
		||||
/* Tagged user address controls for arm64 */
 | 
			
		||||
#define PR_SET_TAGGED_ADDR_CTRL		55
 | 
			
		||||
#define PR_GET_TAGGED_ADDR_CTRL		56
 | 
			
		||||
# define PR_TAGGED_ADDR_ENABLE		(1UL << 0)
 | 
			
		||||
 | 
			
		||||
#endif /* _LINUX_PRCTL_H */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										12
									
								
								kernel/sys.c
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								kernel/sys.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -124,6 +124,12 @@
 | 
			
		|||
#ifndef PAC_RESET_KEYS
 | 
			
		||||
# define PAC_RESET_KEYS(a, b)	(-EINVAL)
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef SET_TAGGED_ADDR_CTRL
 | 
			
		||||
# define SET_TAGGED_ADDR_CTRL(a)	(-EINVAL)
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef GET_TAGGED_ADDR_CTRL
 | 
			
		||||
# define GET_TAGGED_ADDR_CTRL()		(-EINVAL)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 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,
 | 
			
		|||
			return -EINVAL;
 | 
			
		||||
		error = PAC_RESET_KEYS(me, arg2);
 | 
			
		||||
		break;
 | 
			
		||||
	case PR_SET_TAGGED_ADDR_CTRL:
 | 
			
		||||
		error = SET_TAGGED_ADDR_CTRL(arg2);
 | 
			
		||||
		break;
 | 
			
		||||
	case PR_GET_TAGGED_ADDR_CTRL:
 | 
			
		||||
		error = GET_TAGGED_ADDR_CTRL();
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		error = -EINVAL;
 | 
			
		||||
		break;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue