1 /*
2 * Check decoding of set_thread_area and get_thread_area syscalls on x86
3 * architecture.
4 *
5 * Copyright (c) 2018-2019 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "tests.h"
12
13 #include "scno.h"
14
15 #if defined __NR_get_thread_area && defined __NR_set_thread_area \
16 && defined HAVE_STRUCT_USER_DESC
17
18 # include <assert.h>
19 # include <errno.h>
20 # include <stdio.h>
21 # include <stdint.h>
22 # include <string.h>
23 # include <unistd.h>
24
25 # include "print_user_desc.c"
26
27 long errnum;
28
29 static void
30 printptr(kernel_ulong_t ptr, const char *ptr_str)
31 {
32 if (ptr_str)
33 printf("%s", ptr_str);
34 else
35 printf("%#llx", zero_extend_signed_to_ull(ptr));
36 }
37
38 /**
39 * Perform set_thread_area call along with printing the expected output.
40 *
41 * @param ptr_val Pointer to thread area argument.
42 * @param ptr_str Explicit string representation of the argument.
43 * @param valid Whether argument points to the valid memory and its contents
44 * should be decoded.
45 * @param entry_number_str explicit decoding of the entry_number field.
46 */
47 static long
48 set_thread_area(kernel_ulong_t ptr_val, const char *ptr_str, bool valid,
49 const char *entry_number_str)
50 {
51 struct user_desc *ptr = (struct user_desc *) (uintptr_t) ptr_val;
52 long rc = -1;
53 int saved_errno;
54
55 rc = syscall(__NR_set_thread_area, ptr_val);
56 saved_errno = errno;
57 printf("set_thread_area(");
58
59 if (valid)
60 print_user_desc(ptr, entry_number_str);
61 else
62 printptr(ptr_val, ptr_str);
63
64 errno = saved_errno;
65 printf(") = %s", sprintrc(rc));
66 if (!rc)
67 printf(" (entry_number=%u)", ptr->entry_number);
68
69 puts("");
70
71 return rc;
72 }
73
74 /**
75 * Perform get_thread_are call along with printing the expected output and
76 * checking the result against the argument of the previous set_thread_area
77 * call, if it had place.
78 *
79 * @param ptr_val Pointer to thread area argument.
80 * @param ptr_str Explicit string representation of the argument.
81 * @param valid Whether argument points to the valid memory and its contents
82 * should be decoded.
83 * @param set_rc Return code of the previous set_thread_area call.
84 * @param expected The value of the argument passed to the previous
85 * set_thread_area call.
86 */
87 static void
88 get_thread_area(kernel_ulong_t ptr_val, const char *ptr_str, bool valid,
89 long set_rc, kernel_ulong_t expected)
90 {
91 struct user_desc *ptr = (struct user_desc *) (uintptr_t) ptr_val;
92 struct user_desc *expected_ptr =
93 (struct user_desc *) (uintptr_t) expected;
94 int saved_errno;
95 long rc;
96
97 rc = syscall(__NR_get_thread_area, ptr_val);
98 saved_errno = errno;
99
100 printf("get_thread_area(");
101
102 if (valid && !rc) {
103 if (!set_rc) {
104 assert(ptr->entry_number == expected_ptr->entry_number);
105 assert(ptr->base_addr == expected_ptr->base_addr);
106 assert(ptr->limit == expected_ptr->limit);
107 assert(ptr->seg_32bit == expected_ptr->seg_32bit);
108 assert(ptr->contents == expected_ptr->contents);
109 assert(ptr->read_exec_only ==
110 expected_ptr->read_exec_only);
111 assert(ptr->limit_in_pages ==
112 expected_ptr->limit_in_pages);
113 assert(ptr->seg_not_present ==
114 expected_ptr->seg_not_present);
115 assert(ptr->useable == expected_ptr->useable);
116 /*
117 * We do not check lm as 32-bit processes ignore it, and
118 * only 32-bit processes can successfully execute
119 * get_thread_area.
120 */
121 }
122
123 print_user_desc(ptr,
124 (int) ptr->entry_number == -1 ? "-1" : NULL);
125 } else {
126 printptr(ptr_val, ptr_str);
127 }
128
129 errno = saved_errno;
130 printf(") = %s\n", sprintrc(rc));
131 }
132
133 int main(void)
134 {
135 TAIL_ALLOC_OBJECT_CONST_PTR(struct user_desc, ta1);
136 TAIL_ALLOC_OBJECT_CONST_PTR(struct user_desc, ta2);
137 TAIL_ALLOC_OBJECT_CONST_PTR(unsigned int, bogus_entry_number);
138
139 long set_rc = -1;
140
141 /*
142 * Let's do some weird syscall, it will mark the beginning of our
143 * expected output.
144 */
145 syscall(__NR_reboot, 0, 0, 0, 0);
146
147 set_rc = set_thread_area((uintptr_t) ARG_STR(NULL), false, NULL);
148 get_thread_area((uintptr_t) ARG_STR(NULL), false, set_rc,
149 (uintptr_t) NULL);
150
151 set_rc = set_thread_area(-1, NULL, false, NULL);
152 get_thread_area(-1, NULL, false, set_rc, -1);
153
154 fill_memory(ta1, sizeof(*ta1));
155 fill_memory_ex(ta2, sizeof(*ta2), 0xA5, 0x5A);
156
157 set_thread_area((uintptr_t) (ta1 + 1), NULL, false, NULL);
158
159 set_thread_area((uintptr_t) bogus_entry_number, NULL, false, NULL);
160
161 set_thread_area((uintptr_t) ta1, NULL, true, NULL);
162
163 ta1->entry_number = -1;
164 ta1->base_addr = 0;
165 ta1->limit = 0;
166 ta1->contents = 1;
167 ta1->seg_32bit = 1;
168 ta1->seg_not_present = 0;
169
170 set_rc = set_thread_area((uintptr_t) ta1, NULL, true, "-1");
171
172 *bogus_entry_number = 2718281828U;
173 get_thread_area((uintptr_t) bogus_entry_number,
174 "{entry_number=2718281828, ...}",
175 false, set_rc, (uintptr_t) ta1);
176
177 /* That one should return -EFAULT on i386 */
178 *bogus_entry_number = 12;
179 get_thread_area((uintptr_t) bogus_entry_number,
180 "{entry_number=12, ...}",
181 false, set_rc, (uintptr_t) ta1);
182
183 ta2->entry_number = 3141592653U;
184 get_thread_area((uintptr_t) ta2, "{entry_number=3141592653, ...}",
185 false, set_rc, (uintptr_t) ta1);
186
187 ta2->entry_number = -1;
188 get_thread_area((uintptr_t) ta2, "{entry_number=-1, ...}",
189 false, set_rc, (uintptr_t) ta1);
190
191 ta2->entry_number = ta1->entry_number;
192 assert(set_rc == 0 || (int) ta2->entry_number == -1);
193 get_thread_area((uintptr_t) ta2, "{entry_number=-1, ...}",
194 true, set_rc, (uintptr_t) ta1);
195
196 puts("+++ exited with 0 +++");
197
198 return 0;
199 }
200
201 #else
202
203 SKIP_MAIN_UNDEFINED("__NR_get_thread_area && __NR_set_thread_area"
204 " && HAVE_STRUCT_USER_DESC");
205
206 #endif