@@ -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
@@ -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 */
@@ -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);
@@ -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 */
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@amd.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(-)