1 /*
2 * Check decoding of prctl PR_SME_SET_VL/PR_SME_GET_VL operations.
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 #include <stdio.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <linux/prctl.h>
16
17 #ifdef INJECT_RETVAL
18 # define INJ_STR " (INJECTED)"
19 #else
20 # define INJ_STR ""
21 #endif
22
23 #ifndef EXT
24 # define EXT SME
25 #endif
26
27 #define EXT_STR STRINGIFY_VAL(EXT)
28 #define GLUE_(a_, b_, c_) a_ ## b_ ## c_
29 #define GLUE(a_, b_, c_) GLUE_(a_, b_, c_)
30 #define _(pfx_, sfx_) GLUE(pfx_, EXT, sfx_)
31
32 #if !XLAT_RAW
33 static void
34 print_sme_vl_arg(kernel_ulong_t arg)
35 {
36 kernel_ulong_t flags = arg & ~_(PR_, _VL_LEN_MASK);
37
38 if (arg < 0x10000)
39 return;
40
41 printf(" (");
42
43 if (flags & _(PR_, _SET_VL_ONEXEC))
44 printf("PR_" EXT_STR "_SET_VL_ONEXEC");
45 if (flags & _(PR_, _VL_INHERIT)) {
46 printf("%sPR_" EXT_STR "_VL_INHERIT",
47 flags & _(PR_, _SET_VL_ONEXEC) ? "|" : "");
48 }
49
50 kernel_ulong_t leftover =
51 flags & ~(_(PR_, _SET_VL_ONEXEC)|_(PR_, _VL_INHERIT));
52 if (leftover) {
53 printf("%s%#llx",
54 leftover == flags ? "" : "|",
55 (unsigned long long) leftover);
56 }
57
58 kernel_ulong_t lens = arg & _(PR_, _VL_LEN_MASK);
59 printf("%s%#llx", flags ? "|" : "", (unsigned long long) lens);
60
61 printf(")");
62 }
63
64 #endif /* !XLAT_RAW */
65
66 int
67 main(int argc, char *argv[])
68 {
69 const char *errstr;
70 long rc;
71 size_t i;
72
73 prctl_marker();
74
75 #ifdef INJECT_RETVAL
76 unsigned long num_skip;
77 long inject_retval;
78 bool locked = false;
79
80 if (argc < 3)
81 error_msg_and_fail("Usage: %s NUM_SKIP INJECT_RETVAL", argv[0]);
82
83 num_skip = strtoul(argv[1], NULL, 0);
84 inject_retval = strtol(argv[2], NULL, 0);
85
86 for (size_t i = 0; i < num_skip; i++) {
87 if (prctl_marker() != inject_retval)
88 continue;
89
90 locked = true;
91 break;
92 }
93
94 if (!locked)
95 error_msg_and_fail("Have not locked on prctl(-1, -2, -3, -4"
96 ", -5) returning %ld", inject_retval);
97 #endif /* INJECT_RETVAL */
98
99 static const struct {
100 kernel_ulong_t val;
101 const char *str;
102 bool known;
103 } args[] = {
104 { ARG_STR(0) },
105 { ARG_STR(0xdead) },
106 { ARG_XLAT_KNOWN(0x10000, "0x10000|0") },
107 { ARG_XLAT_KNOWN(0x2ea57, "PR_" EXT_STR "_VL_INHERIT|0xea57") },
108 { ARG_XLAT_KNOWN(0x40000, "PR_" EXT_STR "_SET_VL_ONEXEC|0") },
109 { ARG_XLAT_KNOWN(0xfacefeed, "PR_" EXT_STR "_SET_VL_ONEXEC"
110 "|PR_" EXT_STR "_VL_INHERIT"
111 "|0xfac80000|0xfeed") },
112 { ARG_XLAT_KNOWN(0xbad00000, "0xbad00000|0") },
113 { ARG_XLAT_KNOWN(0xde90ded, "0xde90000|0xded") },
114 { (kernel_ulong_t) 0xbadc0ded0000faceULL,
115 #if SIZEOF_KERNEL_LONG_T > 4
116 XLAT_KNOWN(0xbadc0ded0000face, "0xbadc0ded00000000|0xface")
117 #else
118 "0xface"
119 #endif
120 },
121 };
122
123 for (i = 0; i < ARRAY_SIZE(args); i++) {
124 rc = syscall(__NR_prctl, _(PR_, _SET_VL), args[i].val, 1, 2, 3);
125 errstr = sprintrc(rc);
126 printf("prctl(" XLAT_FMT ", %s) = ",
127 XLAT_SEL(_(PR_, _SET_VL), "PR_" EXT_STR "_SET_VL"),
128 args[i].str);
129 if (rc >= 0) {
130 printf("%#lx", rc);
131 #if !XLAT_RAW
132 print_sme_vl_arg(rc);
133 #endif /* !XLAT_RAW */
134 puts(INJ_STR);
135 } else {
136 printf("%s" INJ_STR "\n", errstr);
137 }
138 }
139
140 rc = syscall(__NR_prctl, _(PR_, _GET_VL), 1, 2, 3, 4);
141 errstr = sprintrc(rc);
142 printf("prctl(" XLAT_FMT ") = ",
143 XLAT_SEL(_(PR_, _GET_VL), "PR_" EXT_STR "_GET_VL"));
144 if (rc >= 0) {
145 printf("%#lx", rc);
146 #if !XLAT_RAW
147 print_sme_vl_arg(rc);
148 #endif /* !XLAT_RAW */
149 puts(INJ_STR);
150 } else {
151 printf("%s" INJ_STR "\n", errstr);
152 }
153
154 puts("+++ exited with 0 +++");
155 return 0;
156 }