@@ -367,10 +367,14 @@ extern void __init minsigstksz_setup(void);
#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
/* PR_{SET,GET}_TAGGED_ADDR_CTRL prctl */
-long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg);
-long get_tagged_addr_ctrl(struct task_struct *task);
-#define SET_TAGGED_ADDR_CTRL(arg) set_tagged_addr_ctrl(current, arg)
-#define GET_TAGGED_ADDR_CTRL() get_tagged_addr_ctrl(current)
+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
/*
@@ -621,15 +621,21 @@ void arch_setup_new_exec(void)
}
#ifdef CONFIG_ARM64_TAGGED_ADDR_ABI
+
+#define TBI_TAG_BITS 8
+#define TBI_TAG_SHIFT 56
+
/*
* Control the relaxed ABI allowing tagged user addresses into the kernel.
*/
static unsigned int tagged_addr_disabled;
-long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg)
+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;
struct thread_info *ti = task_thread_info(task);
+ int val;
if (is_compat_thread(ti))
return -EINVAL;
@@ -637,25 +643,41 @@ long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg)
if (system_supports_mte())
valid_mask |= PR_MTE_TCF_MASK | PR_MTE_TAG_MASK;
- if (arg & ~valid_mask)
+ if (flags & ~valid_mask)
return -EINVAL;
+ if (nr_bits) {
+ if (get_user(val, nr_bits))
+ return -EFAULT;
+ if (val > TBI_TAG_BITS || val < 1)
+ return -EINVAL;
+ }
+
/*
* Do not allow the enabling of the tagged address ABI if globally
* disabled via sysctl abi.tagged_addr_disabled.
*/
- if (arg & PR_TAGGED_ADDR_ENABLE && tagged_addr_disabled)
+ if (flags & PR_TAGGED_ADDR_ENABLE && tagged_addr_disabled)
return -EINVAL;
- if (set_mte_ctrl(task, arg) != 0)
+ if (set_mte_ctrl(task, flags) != 0)
return -EINVAL;
- update_ti_thread_flag(ti, TIF_TAGGED_ADDR, arg & PR_TAGGED_ADDR_ENABLE);
+ if (flags & PR_TAGGED_ADDR_ENABLE) {
+ if (nr_bits && put_user(TBI_TAG_BITS, nr_bits))
+ return -EFAULT;
+ if (offset && put_user(TBI_TAG_SHIFT, offset))
+ return -EFAULT;
+ }
+
+ update_ti_thread_flag(ti, TIF_TAGGED_ADDR,
+ flags & PR_TAGGED_ADDR_ENABLE);
return 0;
}
-long get_tagged_addr_ctrl(struct task_struct *task)
+long get_tagged_addr_ctrl(struct task_struct *task,
+ int __user *nr_bits, int __user *offset)
{
long ret = 0;
struct thread_info *ti = task_thread_info(task);
@@ -663,8 +685,17 @@ long get_tagged_addr_ctrl(struct task_struct *task)
if (is_compat_thread(ti))
return -EINVAL;
- if (test_ti_thread_flag(ti, TIF_TAGGED_ADDR))
+ if (test_ti_thread_flag(ti, TIF_TAGGED_ADDR)) {
ret = PR_TAGGED_ADDR_ENABLE;
+ if (nr_bits && put_user(TBI_TAG_BITS, nr_bits))
+ return -EFAULT;
+ if (offset && put_user(TBI_TAG_SHIFT, offset))
+ return -EFAULT;
+ } else {
+ /* Report maximum tag size */
+ if (nr_bits && put_user(TBI_TAG_BITS, nr_bits))
+ return -EFAULT;
+ }
ret |= get_mte_ctrl(task);
@@ -1073,7 +1073,7 @@ static int tagged_addr_ctrl_get(struct task_struct *target,
const struct user_regset *regset,
struct membuf to)
{
- long ctrl = get_tagged_addr_ctrl(target);
+ long ctrl = get_tagged_addr_ctrl(target, NULL, NULL);
if (IS_ERR_VALUE(ctrl))
return ctrl;
@@ -1093,7 +1093,7 @@ static int tagged_addr_ctrl_set(struct task_struct *target, const struct
if (ret)
return ret;
- return set_tagged_addr_ctrl(target, ctrl);
+ return set_tagged_addr_ctrl(target, ctrl, NULL, NULL);
}
#endif
@@ -126,10 +126,10 @@
# define PAC_GET_ENABLED_KEYS(a) (-EINVAL)
#endif
#ifndef SET_TAGGED_ADDR_CTRL
-# define SET_TAGGED_ADDR_CTRL(a) (-EINVAL)
+# define SET_TAGGED_ADDR_CTRL(a, b, c) (-EINVAL)
#endif
#ifndef GET_TAGGED_ADDR_CTRL
-# define GET_TAGGED_ADDR_CTRL() (-EINVAL)
+# define GET_TAGGED_ADDR_CTRL(a, b) (-EINVAL)
#endif
/*
@@ -2557,14 +2557,16 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
error = PAC_GET_ENABLED_KEYS(me);
break;
case PR_SET_TAGGED_ADDR_CTRL:
- if (arg3 || arg4 || arg5)
+ if (arg5)
return -EINVAL;
- error = SET_TAGGED_ADDR_CTRL(arg2);
+ error = SET_TAGGED_ADDR_CTRL(arg2, (int __user *)arg3,
+ (int __user *)arg4);
break;
case PR_GET_TAGGED_ADDR_CTRL:
- if (arg2 || arg3 || arg4 || arg5)
+ if (arg4 || arg5)
return -EINVAL;
- error = GET_TAGGED_ADDR_CTRL();
+ error = GET_TAGGED_ADDR_CTRL((int __user *)arg2,
+ (int __user *)arg3);
break;
case PR_SET_IO_FLUSHER:
if (!capable(CAP_SYS_RESOURCE))
deleted file mode 100644
@@ -1,31 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <sys/prctl.h>
-#include <sys/utsname.h>
-
-#define SHIFT_TAG(tag) ((uint64_t)(tag) << 56)
-#define SET_TAG(ptr, tag) (((uint64_t)(ptr) & ~SHIFT_TAG(0xff)) | \
- SHIFT_TAG(tag))
-
-int main(void)
-{
- static int tbi_enabled = 0;
- unsigned long tag = 0;
- struct utsname *ptr;
- int err;
-
- if (prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0) == 0)
- tbi_enabled = 1;
- ptr = (struct utsname *)malloc(sizeof(*ptr));
- if (tbi_enabled)
- tag = 0x42;
- ptr = (struct utsname *)SET_TAG(ptr, tag);
- err = uname(ptr);
- free(ptr);
-
- return err;
-}
similarity index 100%
rename from tools/testing/selftests/arm64/tags/.gitignore
rename to tools/testing/selftests/vm/tags/.gitignore
similarity index 100%
rename from tools/testing/selftests/arm64/tags/Makefile
rename to tools/testing/selftests/vm/tags/Makefile
similarity index 100%
rename from tools/testing/selftests/arm64/tags/run_tags_test.sh
rename to tools/testing/selftests/vm/tags/run_tags_test.sh
new file mode 100644
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/prctl.h>
+#include <sys/utsname.h>
+
+static int tag_bits;
+static int tag_offset;
+
+#define SHIFT_TAG(tag) ((uint64_t)(tag) << tag_offset)
+#define SET_TAG(ptr, tag) (((uint64_t)(ptr) & ~SHIFT_TAG((1 << tag_bits) - 1)) \
+ | SHIFT_TAG(tag))
+
+static int max_tag_bits(void)
+{
+ int nr;
+
+ if (prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0) < 0)
+ return 0;
+
+ if (prctl(PR_GET_TAGGED_ADDR_CTRL, &nr, 0, 0) < 0)
+ return 8; /* Assume ARM TBI */
+
+ return nr;
+}
+
+int main(void)
+{
+ static int tags_enabled;
+ unsigned long tag = 0;
+ struct utsname *ptr;
+ int err;
+
+ tag_bits = max_tag_bits();
+
+ if (tag_bits && !prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE,
+ &tag_bits, &tag_offset, 0)) {
+ tags_enabled = 1;
+ } else if (tag_bits == 8 && !prctl(PR_SET_TAGGED_ADDR_CTRL,
+ PR_TAGGED_ADDR_ENABLE, 0, 0)) {
+ /* ARM TBI with legacy interface*/
+ tags_enabled = 1;
+ tag_offset = 56;
+ }
+
+ ptr = (struct utsname *)malloc(sizeof(*ptr));
+ if (tags_enabled) {
+ tag = (1UL << tag_bits) - 1;
+ ptr = (struct utsname *)SET_TAG(ptr, tag);
+ }
+ err = uname(ptr);
+ printf("Sysname: %s\n", ptr->sysname);
+ free(ptr);
+
+ return err;
+}