1 /*
2 * Check decoding of prctl PR_SET_TAGGED_ADDR_CTRL and PR_GET_TAGGED_ADDR_CTRL
3 * operations.
4 *
5 * Copyright (c) 2021 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "tests.h"
12 #include "scno.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <linux/prctl.h>
17
18 #if !XLAT_RAW
19 static void
20 print_tagged_addr_arg(kernel_ulong_t arg)
21 {
22 kernel_ulong_t val = arg & PR_TAGGED_ADDR_ENABLE;
23
24 printf("%sPR_TAGGED_ADDR_ENABLE", val ? "" : "!");
25 arg &= ~val;
26 val = arg & PR_MTE_TCF_MASK;
27 switch (val) {
28 case PR_MTE_TCF_NONE: printf("|PR_MTE_TCF_NONE"); break;
29 case PR_MTE_TCF_SYNC: printf("|PR_MTE_TCF_SYNC"); break;
30 case PR_MTE_TCF_ASYNC: printf("|PR_MTE_TCF_ASYNC"); break;
31 case PR_MTE_TCF_MASK: printf("|PR_MTE_TCF_MASK"); break;
32 }
33 arg &= ~val;
34 val = arg & PR_MTE_TAG_MASK;
35 if (val) {
36 printf("|%#llx<<PR_MTE_TAG_SHIFT",
37 (unsigned long long) val >> PR_MTE_TAG_SHIFT);
38 }
39 arg &= ~val;
40 if (arg)
41 printf("|%#llx", (unsigned long long) arg);
42 }
43 #endif /* !XLAT_RAW */
44
45 #ifdef INJECT_RETVAL
46 # define INJ_STR " (INJECTED)"
47 #else
48 # define INJ_STR ""
49 #endif
50
51 #if SIZEOF_KERNEL_LONG_T == 8
52 # define HIBITS(a) a
53 #else
54 # define HIBITS(a)
55 #endif
56
57 int
58 main(int argc, char *argv[])
59 {
60 prctl_marker();
61
62 #ifdef INJECT_RETVAL
63 unsigned long num_skip;
64 long inject_retval;
65 bool locked = false;
66
67 if (argc < 3)
68 error_msg_and_fail("Usage: %s NUM_SKIP INJECT_RETVAL", argv[0]);
69
70 num_skip = strtoul(argv[1], NULL, 0);
71 inject_retval = strtol(argv[2], NULL, 0);
72
73 for (size_t i = 0; i < num_skip; i++) {
74 if (prctl_marker() != inject_retval)
75 continue;
76
77 locked = true;
78 break;
79 }
80
81 if (!locked)
82 error_msg_and_fail("Have not locked on prctl(-1, -2, -3, -4"
83 ", -5) returning %ld", inject_retval);
84 #endif /* INJECT_RETVAL */
85
86 static const struct {
87 kernel_ulong_t val;
88 const char *str;
89 } args[] = {
90 { 0, "!PR_TAGGED_ADDR_ENABLE|PR_MTE_TCF_NONE" },
91 { /* 1 */ ARG_STR(PR_TAGGED_ADDR_ENABLE|PR_MTE_TCF_NONE) },
92 { 2, "!PR_TAGGED_ADDR_ENABLE|PR_MTE_TCF_SYNC" },
93 { /* 5 */ ARG_STR(PR_TAGGED_ADDR_ENABLE|PR_MTE_TCF_ASYNC) },
94 { 6, "!PR_TAGGED_ADDR_ENABLE|PR_MTE_TCF_MASK" },
95 { 8, "!PR_TAGGED_ADDR_ENABLE|PR_MTE_TCF_NONE|0x1<<PR_MTE_TAG_SHIFT" },
96 { /* 13 */ ARG_STR(PR_TAGGED_ADDR_ENABLE|PR_MTE_TCF_ASYNC|0x1<<PR_MTE_TAG_SHIFT) },
97 { 0x57ae57f4, "!PR_TAGGED_ADDR_ENABLE|PR_MTE_TCF_ASYNC"
98 "|0xcafe<<PR_MTE_TAG_SHIFT|0x57a80000" },
99 { (kernel_ulong_t) -1LLU, "PR_TAGGED_ADDR_ENABLE"
100 "|PR_MTE_TCF_MASK"
101 "|0xffff<<PR_MTE_TAG_SHIFT"
102 "|0x" HIBITS("ffffffff") "fff80000" },
103 };
104 long rc;
105 size_t i = 0;
106
107 for (i = 0; i < ARRAY_SIZE(args); i++) {
108 rc = syscall(__NR_prctl, PR_SET_TAGGED_ADDR_CTRL,
109 args[i].val, 1, 2, 3);
110 printf("prctl(" XLAT_KNOWN(0x37, "PR_SET_TAGGED_ADDR_CTRL") ", "
111 XLAT_FMT_LL ", 0x1, 0x2, 0x3) = %s" INJ_STR "\n",
112 XLAT_SEL((unsigned long long) args[i].val, args[i].str),
113 sprintrc(rc));
114 }
115
116 rc = syscall(__NR_prctl, PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
117 const char *errstr = sprintrc(rc);
118 printf("prctl(" XLAT_KNOWN(0x38, "PR_GET_TAGGED_ADDR_CTRL")
119 ", 0, 0, 0, 0) = ");
120 if (rc >= 0) {
121 printf("%#lx", rc);
122 #if !XLAT_RAW
123 for (i = 0; i < ARRAY_SIZE(args); i++) {
124 if (args[i].val == (unsigned long) rc) {
125 printf(" (%s)", args[i].str);
126 break;
127 }
128 }
129
130 if (i == ARRAY_SIZE(args)) {
131 printf(" (");
132 print_tagged_addr_arg(rc);
133 printf(")");
134 }
135 #endif /* !XLAT_RAW */
136 puts(INJ_STR);
137 } else {
138 printf("%s" INJ_STR "\n", errstr);
139 }
140
141 puts("+++ exited with 0 +++");
142 return 0;
143 }