1 /*
2 * Check decoding of arch_prctl syscall.
3 *
4 * Copyright (c) 2021-2022 The strace developers.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "tests.h"
11 #include "scno.h"
12
13 #ifdef __NR_arch_prctl
14
15 # include <stdio.h>
16 # include <stdlib.h>
17 # include <unistd.h>
18 # include <linux/prctl.h>
19
20 # define XLAT_MACROS_ONLY
21 # include "xlat/archvals.h"
22 # undef XLAT_MACROS_ONLY
23
24 # include "xlat.h"
25 # include "xlat/x86_xfeature_bits.h"
26 # include "xlat/x86_xfeatures.h"
27
28 # ifdef INJECT_RETVAL
29 # define INJ_STR " (INJECTED)\n"
30 # else
31 # define INJ_STR "\n"
32 # endif
33
34 # define ARRAY_END(a_) ((a_) + ARRAY_SIZE(a_))
35
36 static long
37 sys_arch_prctl(unsigned int cmd, kernel_ulong_t arg)
38 {
39 return syscall(__NR_arch_prctl, cmd, arg, (unsigned long) -3U,
40 (unsigned long) -4U,
41 (unsigned long) -5U);
42 }
43
44 static long
45 arch_prctl_marker(void)
46 {
47 return sys_arch_prctl(-1U, (unsigned long) -2U);
48 }
49
50 int
51 main(int argc, char *argv[])
52 {
53 const kernel_ulong_t dummy = (kernel_ulong_t) 0xbadfaceddeadbeefULL;
54 const char *errstr;
55 long rc;
56
57 arch_prctl_marker();
58
59 # ifdef INJECT_RETVAL
60 unsigned long num_skip;
61 long inject_retval;
62 bool locked = false;
63
64 if (argc < 3)
65 error_msg_and_fail("Usage: %s NUM_SKIP INJECT_RETVAL", argv[0]);
66
67 num_skip = strtoul(argv[1], NULL, 0);
68 inject_retval = strtol(argv[2], NULL, 0);
69
70 for (size_t i = 0; i < num_skip; i++) {
71 if (arch_prctl_marker() != inject_retval)
72 continue;
73
74 locked = true;
75 break;
76 }
77
78 if (!locked)
79 error_msg_and_fail("Have not locked on arch_prctl(-1, -2)"
80 " returning %ld", inject_retval);
81 # endif /* INJECT_RETVAL */
82
83 TAIL_ALLOC_OBJECT_CONST_PTR(uint64_t, u64_p);
84
85 /* Unknown commands */
86 static const uint32_t unk_cmds[] = {
87 0, 0x1,
88 0x1000, 0x1005,
89 0x1010, 0x1013,
90 0x1020, 0x1026,
91 0x1030, 0x1031,
92 0x1100, 0x1101,
93 0x2000, 0x2004,
94 0x2010, 0x2011,
95 0x2100, 0x2101,
96 0x3000, 0x3001,
97 0xdeadc0de };
98
99 for (size_t i = 0; i < ARRAY_SIZE(unk_cmds); i++) {
100 rc = sys_arch_prctl(unk_cmds[i], 0);
101 printf("arch_prctl(" XLAT_UNKNOWN_FMT("%#x", "ARCH_???")
102 ", 0) = %s" INJ_STR,
103 unk_cmds[i], sprintrc(rc));
104
105 rc = sys_arch_prctl(unk_cmds[i], (kernel_ulong_t) dummy);
106 printf("arch_prctl(" XLAT_UNKNOWN_FMT("%#x", "ARCH_???")
107 ", %#llx) = %s" INJ_STR,
108 unk_cmds[i], (unsigned long long) dummy, sprintrc(rc));
109
110 rc = sys_arch_prctl(unk_cmds[i], (uintptr_t) u64_p);
111 printf("arch_prctl(" XLAT_UNKNOWN_FMT("%#x", "ARCH_???")
112 ", %p) = %s" INJ_STR,
113 unk_cmds[i], u64_p, sprintrc(rc));
114 }
115
116 /* Default decoding */
117 static const struct strval32 def_cmds[] = {
118 { ARG_XLAT_KNOWN(0x1001, "ARCH_SET_GS") },
119 # ifdef INJECT_RETVAL
120 { ARG_XLAT_KNOWN(0x1002, "ARCH_SET_FS") },
121 # endif
122 { ARG_XLAT_KNOWN(0x1012, "ARCH_SET_CPUID") },
123 { ARG_XLAT_KNOWN(0x2001, "ARCH_MAP_VDSO_X32") },
124 { ARG_XLAT_KNOWN(0x2002, "ARCH_MAP_VDSO_32") },
125 { ARG_XLAT_KNOWN(0x2003, "ARCH_MAP_VDSO_64") },
126 };
127
128 for (const struct strval32 *p = def_cmds; p < ARRAY_END(def_cmds); p++)
129 {
130 rc = sys_arch_prctl(p->val, (kernel_ulong_t) dummy);
131 printf("arch_prctl(%s, %#llx) = %s" INJ_STR,
132 p->str, (unsigned long long) dummy, sprintrc(rc));
133
134 rc = sys_arch_prctl(p->val, (uintptr_t) u64_p);
135 printf("arch_prctl(%s, %p) = %s" INJ_STR,
136 p->str, u64_p, sprintrc(rc));
137
138 rc = sys_arch_prctl(p->val, 0);
139 printf("arch_prctl(%s, 0) = %s" INJ_STR, p->str, sprintrc(rc));
140 }
141
142 /* ARCH_GET_GS, ARCH_GET_FS */
143 static const struct strval32 kptr_cmds[] = {
144 # ifdef INJECT_RETVAL
145 { ARG_XLAT_KNOWN(0x1003, "ARCH_GET_FS") },
146 # endif
147 { ARG_XLAT_KNOWN(0x1004, "ARCH_GET_GS") },
148 };
149 TAIL_ALLOC_OBJECT_CONST_PTR(kernel_ulong_t, kulong_p);
150 const kernel_ulong_t ptrs[] = {
151 (kernel_ulong_t) 0xdeadfacecafebeefULL,
152 (uintptr_t) (kulong_p + 1),
153 (uintptr_t) kulong_p ,
154 0
155 };
156
157 for (const struct strval32 *p = kptr_cmds; p < ARRAY_END(kptr_cmds);
158 p++) {
159 rc = sys_arch_prctl(p->val, 0);
160 printf("arch_prctl(%s, NULL) = %s" INJ_STR,
161 p->str, sprintrc(rc));
162
163 rc = sys_arch_prctl(p->val, (uintptr_t) (kulong_p + 1));
164 printf("arch_prctl(%s, %p) = %s" INJ_STR,
165 p->str, kulong_p + 1, sprintrc(rc));
166
167 for (size_t j = 0; j < ARRAY_SIZE(ptrs); j++) {
168 *kulong_p = ptrs[j];
169 uint32_t wr_cmd = p->val == ARCH_GET_GS ? ARCH_SET_GS
170 : ARCH_SET_FS;
171 # if !XLAT_RAW
172 const char *wr_str = p->val == ARCH_GET_GS
173 ? "ARCH_SET_GS" : "ARCH_SET_FS";
174 # endif
175 rc = sys_arch_prctl(wr_cmd, *kulong_p);
176 printf("arch_prctl(" XLAT_FMT ", %#llx) = %s" INJ_STR,
177 XLAT_SEL(wr_cmd, wr_str),
178 (unsigned long long) *kulong_p, sprintrc(rc));
179
180 rc = sys_arch_prctl(p->val, (uintptr_t) kulong_p);
181 errstr = sprintrc(rc);
182 printf("arch_prctl(%s, ", p->str);
183 if (rc >= 0) {
184 if (*kulong_p) {
185 printf("[%#llx]",
186 (unsigned long long) *kulong_p);
187 } else {
188 printf("[NULL]");
189 }
190 } else {
191 printf("%p", kulong_p);
192 }
193 printf(") = %s" INJ_STR, errstr);
194 }
195 }
196
197 /* ARCH_GET_CPUID */
198 rc = sys_arch_prctl(ARCH_GET_CPUID, 0xdeadc0de);
199 printf("arch_prctl(" XLAT_FMT ") = %s" INJ_STR,
200 XLAT_ARGS(ARCH_GET_CPUID), sprintrc(rc));
201
202 /* xfeature mask get */
203 static const struct strval32 xfget_cmds[] = {
204 { ARG_XLAT_KNOWN(0x1021, "ARCH_GET_XCOMP_SUPP") },
205 { ARG_XLAT_KNOWN(0x1022, "ARCH_GET_XCOMP_PERM") },
206 { ARG_XLAT_KNOWN(0x1024, "ARCH_GET_XCOMP_GUEST_PERM") },
207 };
208 static const struct strval64 xfget_vals[] = {
209 { ARG_STR(0) },
210 { ARG_XLAT_UNKNOWN(0x1, "XFEATURE_MASK_FP") },
211 { ARG_XLAT_UNKNOWN(0x2, "XFEATURE_MASK_SSE") },
212 { ARG_XLAT_UNKNOWN(0x3, "XFEATURE_MASK_FPSSE") },
213 { ARG_XLAT_UNKNOWN(0x20, "XFEATURE_MASK_OPMASK") },
214 { ARG_XLAT_UNKNOWN(0xc0, "XFEATURE_MASK_ZMM_Hi256"
215 "|XFEATURE_MASK_Hi16_ZMM") },
216 { ARG_XLAT_UNKNOWN(0xe0, "XFEATURE_MASK_AVX512") },
217 { ARG_XLAT_UNKNOWN(0x20000, "XFEATURE_MASK_XTILE_CFG") },
218 { ARG_XLAT_UNKNOWN(0x40000, "XFEATURE_MASK_XTILE_DATA") },
219 { ARG_XLAT_UNKNOWN(0x60000, "XFEATURE_MASK_XTILE") },
220 { ARG_XLAT_UNKNOWN(0xbadfaced,
221 "XFEATURE_MASK_FP|XFEATURE_MASK_YMM"
222 "|XFEATURE_MASK_BNDREGS|XFEATURE_MASK_AVX512"
223 "|XFEATURE_MASK_PASID|XFEATURE_MASK_LBR"
224 "|XFEATURE_MASK_XTILE|0xbad92800") },
225 { ARG_XLAT_UNKNOWN(0x687ff,
226 "XFEATURE_MASK_FPSSE|XFEATURE_MASK_YMM"
227 "|XFEATURE_MASK_BNDREGS|XFEATURE_MASK_BNDCSR"
228 "|XFEATURE_MASK_AVX512|XFEATURE_MASK_PT"
229 "|XFEATURE_MASK_PKRU|XFEATURE_MASK_PASID"
230 "|XFEATURE_MASK_LBR|XFEATURE_MASK_XTILE") },
231 { ARG_XLAT_UNKNOWN(0xfffffffffff97800, "XFEATURE_MASK_???") },
232 };
233
234 for (const struct strval32 *p = xfget_cmds; p < ARRAY_END(xfget_cmds);
235 p++) {
236 rc = sys_arch_prctl(p->val, 0);
237 printf("arch_prctl(%s, NULL) = %s" INJ_STR,
238 p->str, sprintrc(rc));
239
240 rc = sys_arch_prctl(p->val, (uintptr_t) (u64_p + 1));
241 printf("arch_prctl(%s, %p) = %s" INJ_STR,
242 p->str, u64_p + 1, sprintrc(rc));
243
244 for (const struct strval64 *q = xfget_vals;
245 q < ARRAY_END(xfget_vals); q++) {
246 *u64_p = q->val;
247 rc = sys_arch_prctl(p->val, (uintptr_t) u64_p);
248 errstr = sprintrc(rc);
249 printf("arch_prctl(%s, ", p->str);
250 if (rc >= 0) {
251 # ifdef INJECT_RETVAL
252 printf("[%s]", q->str);
253 # else
254 if (*u64_p) {
255 printf("[%#llx" NRAW(" /* "),
256 (unsigned long long) *u64_p);
257 # if !XLAT_RAW
258 printflags(x86_xfeatures, *u64_p, NULL);
259 # endif
260 printf(NRAW(" */") "]");
261 } else {
262 printf("[0]");
263 }
264 # endif
265 } else {
266 printf("%p", u64_p);
267 }
268 printf(") = %s" INJ_STR, errstr);
269 }
270 }
271
272 /* xfeature in arg, xfeature mask in ret */
273 static const struct strval32 xfreq_cmds[] = {
274 { ARG_XLAT_KNOWN(0x1023, "ARCH_REQ_XCOMP_PERM") },
275 { ARG_XLAT_KNOWN(0x1025, "ARCH_REQ_XCOMP_GUEST_PERM") },
276 };
277 static const struct strval32 xfreq_vals[] = {
278 { ARG_XLAT_UNKNOWN(0, "XFEATURE_FP") },
279 { ARG_XLAT_UNKNOWN(0x8, "XFEATURE_PT_UNIMPLEMENTED_SO_FAR") },
280 { ARG_XLAT_UNKNOWN(0xb, "XFEATURE_???") },
281 { ARG_XLAT_UNKNOWN(0xc, "XFEATURE_???") },
282 { ARG_XLAT_UNKNOWN(0xd, "XFEATURE_???") },
283 { ARG_XLAT_UNKNOWN(0xe, "XFEATURE_???") },
284 { ARG_XLAT_UNKNOWN(0xf, "XFEATURE_LBR") },
285 { ARG_XLAT_UNKNOWN(0x10, "XFEATURE_???") },
286 { ARG_XLAT_UNKNOWN(0x11, "XFEATURE_XTILE_CFG") },
287 { ARG_XLAT_UNKNOWN(0x12, "XFEATURE_XTILE_DATA") },
288 { ARG_XLAT_UNKNOWN(0x13, "XFEATURE_???") },
289 { ARG_XLAT_UNKNOWN(0xdeadface, "XFEATURE_???") },
290 };
291
292 for (const struct strval32 *p = xfreq_cmds; p < ARRAY_END(xfreq_cmds);
293 p++) {
294 for (const struct strval32 *q = xfreq_vals;
295 q < ARRAY_END(xfreq_vals); q++) {
296 rc = sys_arch_prctl(p->val, q->val);
297 errstr = sprintrc(rc);
298 printf("arch_prctl(%s, %s) = ", p->str, q->str);
299 if (rc > 0) {
300 printf("%#lx", rc);
301 # if !XLAT_RAW
302 if (rc & x86_xfeatures->flags_mask) {
303 printf(" (");
304 printflags(x86_xfeatures, rc, NULL);
305 printf(")");
306 }
307 # endif
308 printf(INJ_STR);
309 } else {
310 printf("%s" INJ_STR, errstr);
311 }
312 }
313 }
314
315 puts("+++ exited with 0 +++");
316 return 0;
317 }
318
319 #else
320
321 SKIP_MAIN_UNDEFINED("__NR_arch_prctl")
322
323 #endif