lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Thu, 10 Mar 2022 16:45:45 +0530
From:   Bharata B Rao <bharata@....com>
To:     <linux-kernel@...r.kernel.org>
CC:     <linux-mm@...ck.org>, <x86@...nel.org>,
        <kirill.shutemov@...ux.intel.com>, <tglx@...utronix.de>,
        <mingo@...hat.com>, <bp@...en8.de>, <dave.hansen@...ux.intel.com>,
        <catalin.marinas@....com>, <will@...nel.org>, <shuah@...nel.org>,
        <oleg@...hat.com>, <ananth.narayan@....com>,
        "Bharata B Rao" <bharata@....com>
Subject: [RFC PATCH v0 6/6] x86: Add prctl() options to control tagged user addresses ABI

Provide an option for applications to opt-in for a relaxed
tagged ABI via prtcl(). This allows them to pass tagged addresses
to syscalls as pointer arguments.

The implementation is kept separate for AMD UAI as the equivalent
implementation for Intel LAM is likely to be different.

Signed-off-by: Bharata B Rao <bharata@....com>
---
 arch/x86/Kconfig                 |   9 +++
 arch/x86/include/asm/processor.h |  12 +++
 arch/x86/include/asm/uaccess.h   |   3 +-
 arch/x86/kernel/process.c        | 134 +++++++++++++++++++++++++++++++
 4 files changed, 157 insertions(+), 1 deletion(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 9f5bd41bf660..b73414eb1c01 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2436,6 +2436,15 @@ config STRICT_SIGALTSTACK_SIZE
 
 source "kernel/livepatch/Kconfig"
 
+config X86_TAGGED_ADDR_ABI
+	bool "Enable the tagged user addresses syscall ABI"
+	depends on X86_64 && CPU_SUP_AMD
+	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.
+
 endmenu
 
 config ARCH_HAS_ADD_PAGES
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 2c5f12ae7d04..414e2c039c34 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -863,4 +863,16 @@ bool arch_is_platform_page(u64 paddr);
 #define arch_is_platform_page arch_is_platform_page
 #endif
 
+#ifdef CONFIG_X86_TAGGED_ADDR_ABI
+/* PR_{SET,GET}_TAGGED_ADDR_CTRL prctl */
+long set_tagged_addr_ctrl(struct task_struct *task, unsigned long flags,
+			  int __user *nr_bits, int __user *offset);
+long get_tagged_addr_ctrl(struct task_struct *task,
+			  int __user *nr_bits, int __user *offset);
+#define SET_TAGGED_ADDR_CTRL(flags, nr_bits, offset)	\
+	set_tagged_addr_ctrl(current, flags, nr_bits, offset)
+#define GET_TAGGED_ADDR_CTRL(nr_bits, offset)		\
+	get_tagged_addr_ctrl(current, nr_bits, offset)
+#endif
+
 #endif /* _ASM_X86_PROCESSOR_H */
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index feb2e21c7e09..e415523dc425 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -38,7 +38,8 @@ static inline bool __chk_range_not_ok(unsigned long addr, unsigned long size, un
 static inline bool __range_not_ok(const void __user *addr, unsigned long size,
 				  unsigned long limit)
 {
-	if (test_thread_flag(TIF_TAGGED_ADDR))
+	if (IS_ENABLED(CONFIG_X86_TAGGED_ADDR_ABI) &&
+	    (current->flags & PF_KTHREAD || test_thread_flag(TIF_TAGGED_ADDR)))
 		addr = untagged_addr(addr);
 
 	__chk_user_ptr(addr);
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 81d8ef036637..2bc44efdd994 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -26,6 +26,7 @@
 #include <linux/elf-randomize.h>
 #include <trace/events/power.h>
 #include <linux/hw_breakpoint.h>
+#include <linux/sysctl.h>
 #include <asm/cpu.h>
 #include <asm/apic.h>
 #include <linux/uaccess.h>
@@ -231,6 +232,12 @@ static void pkru_flush_thread(void)
 	pkru_write_default();
 }
 
+static void flush_tagged_addr_state(void)
+{
+	if (IS_ENABLED(CONFIG_X86_TAGGED_ADDR_ABI))
+		clear_thread_flag(TIF_TAGGED_ADDR);
+}
+
 void flush_thread(void)
 {
 	struct task_struct *tsk = current;
@@ -240,6 +247,7 @@ void flush_thread(void)
 
 	fpu_flush_thread();
 	pkru_flush_thread();
+	flush_tagged_addr_state();
 }
 
 void disable_TSC(void)
@@ -1000,3 +1008,129 @@ long do_arch_prctl_common(struct task_struct *task, int option,
 
 	return -EINVAL;
 }
+
+#ifdef CONFIG_X86_TAGGED_ADDR_ABI
+/*
+ * Control the relaxed ABI allowing tagged user addresses into the kernel.
+ */
+static unsigned int tagged_addr_disabled;
+
+#ifdef CONFIG_CPU_SUP_AMD
+#define UAI_TAG_BITS	7
+
+static long amd_set_tagged_addr_ctrl(unsigned long flags, int __user *nr_bits,
+				     int __user *offset)
+{
+	int val;
+
+	if (!boot_cpu_has(X86_FEATURE_UAI))
+		return -EINVAL;
+
+	/* Disable tagging */
+	if (!(flags & PR_TAGGED_ADDR_ENABLE)) {
+		clear_thread_flag(TIF_TAGGED_ADDR);
+		return 0;
+	}
+
+	if (!nr_bits || !offset)
+		return -EINVAL;
+
+	/*
+	 * Do not allow the enabling of the tagged address ABI if globally
+	 * disabled via sysctl abi.tagged_addr_disabled.
+	 */
+	if (tagged_addr_disabled)
+		return -EINVAL;
+
+	if (get_user(val, nr_bits))
+		return -EFAULT;
+
+	if (val != UAI_TAG_BITS)
+		return -EINVAL;
+
+	if (put_user(val, nr_bits) || put_user(64 - val, offset))
+		return -EFAULT;
+
+	set_thread_flag(TIF_TAGGED_ADDR);
+	return 0;
+}
+
+static long amd_get_tagged_addr_ctrl(int __user *nr_bits, int __user *offset)
+{
+	long ret = 0;
+
+	if (!boot_cpu_has(X86_FEATURE_UAI))
+		return -EINVAL;
+
+	if (test_thread_flag(TIF_TAGGED_ADDR)) {
+		if (nr_bits && put_user(UAI_TAG_BITS, nr_bits))
+			return -EFAULT;
+		if (offset && put_user(64 - UAI_TAG_BITS, offset))
+			return -EFAULT;
+		ret = PR_TAGGED_ADDR_ENABLE;
+	} else {
+		/* Report max tag size */
+		if (nr_bits && put_user(UAI_TAG_BITS, nr_bits))
+			return -EFAULT;
+	}
+	return ret;
+}
+#endif
+
+long set_tagged_addr_ctrl(struct task_struct *task, unsigned long flags,
+			  int __user *nr_bits, int __user *offset)
+{
+	unsigned long valid_mask = PR_TAGGED_ADDR_ENABLE;
+
+	if (in_32bit_syscall())
+		return -EINVAL;
+
+	if (flags & ~valid_mask)
+		return -EINVAL;
+
+	if (IS_ENABLED(CONFIG_CPU_SUP_AMD))
+		return amd_set_tagged_addr_ctrl(flags, nr_bits, offset);
+	else
+		return -EINVAL;
+}
+
+long get_tagged_addr_ctrl(struct task_struct *task,
+			  int __user *nr_bits, int __user *offset)
+{
+
+	if (in_32bit_syscall())
+		return -EINVAL;
+
+	if (IS_ENABLED(CONFIG_CPU_SUP_AMD))
+		return amd_get_tagged_addr_ctrl(nr_bits, offset);
+	else
+		return -EINVAL;
+}
+
+/*
+ * 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 struct ctl_table tagged_addr_sysctl_table[] = {
+	{
+		.procname	= "tagged_addr_disabled",
+		.mode		= 0644,
+		.data		= &tagged_addr_disabled,
+		.maxlen		= sizeof(int),
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= SYSCTL_ZERO,
+		.extra2		= SYSCTL_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_X86_TAGGED_ADDR_ABI */
-- 
2.25.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ