1 /*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993-1996 Rick Sladkey <jrs@world.std.com>
5 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 2002-2004 Roland McGrath <roland@redhat.com>
7 * Copyright (c) 2010 Andreas Schwab <schwab@linux-m68k.org>
8 * Copyright (c) 2014-2015 Dmitry V. Levin <ldv@strace.io>
9 * Copyright (c) 2014-2021 The strace developers.
10 * All rights reserved.
11 *
12 * SPDX-License-Identifier: LGPL-2.1-or-later
13 */
14
15 #include "defs.h"
16
17 #ifdef HAVE_STRUCT_USER_DESC
18
19 # include <asm/ldt.h>
20
21 # include "xstring.h"
22
23 void
24 print_user_desc(struct tcb *const tcp, const kernel_ulong_t addr,
25 enum user_desc_print_filter filter)
26 {
27 struct user_desc desc;
28 unsigned *entry_number = get_tcb_priv_data(tcp);
29
30 switch (filter) {
31 case USER_DESC_ENTERING:
32 if (umove_or_printaddr(tcp, addr, &desc.entry_number))
33 return;
34
35 break;
36
37 case USER_DESC_EXITING:
38 if (!addr || !verbose(tcp))
39 return;
40 if (syserror(tcp) || umove(tcp, addr, &desc)) {
41 if (entry_number) {
42 tprint_struct_next();
43 tprint_more_data_follows();
44 tprint_struct_end();
45 }
46
47 return;
48 }
49
50 break;
51
52 case USER_DESC_BOTH:
53 if (umove_or_printaddr(tcp, addr, &desc))
54 return;
55
56 break;
57 }
58
59 if (filter & USER_DESC_ENTERING) {
60 tprint_struct_begin();
61 PRINT_FIELD_ID(desc, entry_number);
62
63 /*
64 * If we don't print the whole structure now, let's save it for
65 * later.
66 */
67 if (filter == USER_DESC_ENTERING) {
68 entry_number = xmalloc(sizeof(*entry_number));
69
70 *entry_number = desc.entry_number;
71 set_tcb_priv_data(tcp, entry_number, free);
72 }
73 }
74
75 if (filter & USER_DESC_EXITING) {
76 /*
77 * It should be the same in case of get_thread_area, but we can
78 * never be sure...
79 */
80 if (filter == USER_DESC_EXITING) {
81 if (entry_number) {
82 if (*entry_number != desc.entry_number) {
83 tprint_value_changed();
84 PRINT_VAL_ID(desc.entry_number);
85 }
86 } else {
87 /*
88 * This is really strange. If we are here, it
89 * means that we failed on entering but somehow
90 * succeeded on exiting.
91 */
92 tprint_value_changed();
93 tprint_struct_begin();
94 PRINT_FIELD_ID(desc, entry_number);
95 }
96 }
97
98 tprint_struct_next();
99 PRINT_FIELD_0X(desc, base_addr);
100 tprint_struct_next();
101 PRINT_FIELD_0X(desc, limit);
102 tprint_struct_next();
103 PRINT_FIELD_U_CAST(desc, seg_32bit, unsigned int);
104 tprint_struct_next();
105 PRINT_FIELD_U_CAST(desc, contents, unsigned int);
106 tprint_struct_next();
107 PRINT_FIELD_U_CAST(desc, read_exec_only, unsigned int);
108 tprint_struct_next();
109 PRINT_FIELD_U_CAST(desc, limit_in_pages, unsigned int);
110 tprint_struct_next();
111 PRINT_FIELD_U_CAST(desc, seg_not_present, unsigned int);
112 tprint_struct_next();
113 PRINT_FIELD_U_CAST(desc, useable, unsigned int);
114
115 # ifdef HAVE_STRUCT_USER_DESC_LM
116 /* lm is totally ignored for 32-bit processes */
117 if (current_klongsize == 8) {
118 tprint_struct_next();
119 PRINT_FIELD_U_CAST(desc, lm, unsigned int);
120 }
121 # endif /* HAVE_STRUCT_USER_DESC_LM */
122
123 tprint_struct_end();
124 }
125 }
126
127 SYS_FUNC(modify_ldt)
128 {
129 if (entering(tcp)) {
130 /* func */
131 PRINT_VAL_D((int) tcp->u_arg[0]);
132 tprint_arg_next();
133
134 /* ptr */
135 if (tcp->u_arg[2] != sizeof(struct user_desc))
136 printaddr(tcp->u_arg[1]);
137 else
138 print_user_desc(tcp, tcp->u_arg[1], USER_DESC_BOTH);
139 tprint_arg_next();
140
141 PRINT_VAL_U(tcp->u_arg[2]);
142
143 return 0;
144 }
145
146 /*
147 * For some reason ("tht ABI for sys_modify_ldt() expects
148 * 'int'"), modify_ldt clips higher bits on x86_64.
149 */
150
151 if (syserror(tcp) || (kernel_ulong_t) tcp->u_rval < 0xfffff000)
152 return 0;
153
154 tcp->u_error = -(unsigned int) tcp->u_rval;
155
156 return 0;
157 }
158
159 SYS_FUNC(set_thread_area)
160 {
161 if (entering(tcp)) {
162 print_user_desc(tcp, tcp->u_arg[0], USER_DESC_BOTH);
163 } else {
164 struct user_desc desc;
165
166 if (!verbose(tcp) || syserror(tcp) ||
167 umove(tcp, tcp->u_arg[0], &desc) < 0) {
168 /* returned entry_number is not available */
169 } else {
170 static char outstr[32];
171
172 xsprintf(outstr, "entry_number=%u", desc.entry_number);
173 tcp->auxstr = outstr;
174 return RVAL_STR;
175 }
176 }
177 return 0;
178 }
179
180 SYS_FUNC(get_thread_area)
181 {
182 print_user_desc(tcp, tcp->u_arg[0],
183 entering(tcp) ? USER_DESC_ENTERING : USER_DESC_EXITING);
184 return 0;
185 }
186
187 #endif /* HAVE_STRUCT_USER_DESC */
188
189 #if defined(M68K) || defined(MIPS)
190 SYS_FUNC(set_thread_area)
191 {
192 printaddr(tcp->u_arg[0]);
193
194 return RVAL_DECODED;
195
196 }
197 #endif
198
199 #if defined(M68K)
200 SYS_FUNC(get_thread_area)
201 {
202 return RVAL_DECODED | RVAL_HEX;
203 }
204 #endif