1 /*
2 * Support for decoding of personality-dependent VT ioctl commands.
3 *
4 * Copyright (c) 2019-2021 Eugene Syromyatnikov <evgsyr@gmail.com>
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: LGPL-2.1-or-later
8 */
9
10 #include "defs.h"
11
12 #include <linux/kd.h>
13
14 #include DEF_MPERS_TYPE(struct_unimapdesc)
15 #include DEF_MPERS_TYPE(struct_consolefontdesc)
16 #include DEF_MPERS_TYPE(struct_console_font)
17 #include DEF_MPERS_TYPE(struct_console_font_op)
18
19 typedef struct unimapdesc struct_unimapdesc;
20 typedef struct consolefontdesc struct_consolefontdesc;
21 typedef struct console_font struct_console_font;
22 typedef struct console_font_op struct_console_font_op;
23
24 #include MPERS_DEFS
25
26 #include "print_fields.h"
27
28 #include "xlat/kd_font_flags.h"
29 #include "xlat/kd_font_ops.h"
30
31 #define XLAT_MACROS_ONLY
32 # include "xlat/kd_ioctl_cmds.h"
33 #undef XLAT_MACROS_ONLY
34
35
36 static bool
37 print_unipair_array_member(struct tcb *tcp, void *elem_buf,
38 size_t elem_size, void *data)
39 {
40 struct unipair *val = elem_buf;
41
42 tprint_struct_begin();
43 PRINT_FIELD_X(*val, unicode);
44 tprint_struct_next();
45 PRINT_FIELD_X(*val, fontpos);
46 tprint_struct_end();
47
48 return true;
49 }
50
51 static int
52 kd_unimap(struct tcb *const tcp, const kernel_ulong_t arg, const bool get)
53 {
54 struct_unimapdesc val;
55 struct unipair elem;
56 uint16_t cnt;
57
58 if (entering(tcp))
59 tprint_arg_next();
60
61 if (umove_or_printaddr_ignore_syserror(tcp, arg, &val)) {
62 if (exiting(tcp))
63 tprint_struct_end();
64
65 return RVAL_IOCTL_DECODED;
66 }
67
68 if (entering(tcp)) {
69 set_tcb_priv_ulong(tcp, val.entry_ct);
70 tprint_struct_begin();
71 PRINT_FIELD_U(val, entry_ct);
72
73 if (get)
74 return 0;
75 } else {
76 tprint_value_changed();
77 PRINT_VAL_U(val.entry_ct);
78 }
79
80 if (exiting(tcp) && syserror(tcp) && tcp->u_error != ENOMEM) {
81 tprint_struct_next();
82 PRINT_FIELD_PTR(val, entries);
83 tprint_struct_end();
84 return RVAL_IOCTL_DECODED;
85 }
86
87 cnt = entering(tcp) ? val.entry_ct : get_tcb_priv_ulong(tcp);
88
89 tprint_struct_next();
90 tprints_field_name("entries");
91 print_array(tcp, (mpers_ptr_t) val.entries, cnt, &elem, sizeof(elem),
92 tfetch_mem, print_unipair_array_member, 0);
93
94 tprint_struct_end();
95
96 return get && entering(tcp) ? 0 : RVAL_IOCTL_DECODED;
97 }
98
99 static void
100 print_consolefontdesc(struct tcb *const tcp, const struct_consolefontdesc *cfd,
101 const bool get)
102 {
103 tprint_struct_begin();
104 PRINT_FIELD_U(*cfd, charcount);
105 tprint_struct_next();
106 PRINT_FIELD_U(*cfd, charheight);
107 tprint_struct_next();
108 if (get) {
109 PRINT_FIELD_PTR(*cfd, chardata);
110 } else {
111 tprints_field_name("chardata");
112 printstr_ex(tcp, (mpers_ptr_t) cfd->chardata,
113 MIN(cfd->charcount, 512) * 32, QUOTE_FORCE_HEX);
114 }
115
116 tprint_struct_end();
117 }
118
119 static int
120 kd_fontx(struct tcb *const tcp, const kernel_ulong_t arg, const bool get)
121 {
122 struct_consolefontdesc val;
123
124 if (entering(tcp)) {
125 tprint_arg_next();
126
127 if (umove_or_printaddr(tcp, arg, &val))
128 return RVAL_IOCTL_DECODED;
129 } else {
130 if (syserror(tcp) || umove(tcp, arg, &val))
131 return RVAL_IOCTL_DECODED;
132
133 tprint_value_changed();
134 }
135
136 print_consolefontdesc(tcp, &val, get && entering(tcp));
137
138 return get && entering(tcp) ? 0 : RVAL_IOCTL_DECODED;
139 }
140
141 static void
142 print_console_font_op(struct tcb *const tcp, const struct_console_font_op *cfo)
143 {
144 enum { KERNEL_MAX_FONT_NAME = 32 };
145
146 tprint_struct_begin();
147
148 if (entering(tcp)) {
149 PRINT_FIELD_XVAL(*cfo, op, kd_font_ops, "KD_FONT_OP_???");
150
151 switch (cfo->op) {
152 case KD_FONT_OP_SET_DEFAULT:
153 case KD_FONT_OP_COPY:
154 break;
155 default:
156 tprint_struct_next();
157 PRINT_FIELD_FLAGS(*cfo, flags, kd_font_flags,
158 "KD_FONT_FLAG_???");
159 }
160
161 tprint_struct_next();
162 }
163
164 switch (cfo->op) {
165 case KD_FONT_OP_COPY:
166 PRINT_FIELD_U(*cfo, height);
167 break;
168 default:
169 PRINT_FIELD_U(*cfo, width);
170 tprint_struct_next();
171 PRINT_FIELD_U(*cfo, height);
172 }
173
174 switch (cfo->op) {
175 case KD_FONT_OP_SET_DEFAULT:
176 case KD_FONT_OP_COPY:
177 break;
178 default:
179 tprint_struct_next();
180 PRINT_FIELD_U(*cfo, charcount);
181 }
182
183 switch (cfo->op) {
184 case KD_FONT_OP_GET:
185 if (entering(tcp)) {
186 tprint_struct_next();
187 PRINT_FIELD_PTR(*cfo, data);
188 break;
189 }
190 ATTRIBUTE_FALLTHROUGH;
191
192 case KD_FONT_OP_SET:
193 tprint_struct_next();
194 tprints_field_name("data");
195 printstr_ex(tcp, (mpers_ptr_t) cfo->data,
196 ROUNDUP_DIV(MIN(cfo->width, 32), 8) * 32 *
197 MIN(cfo->charcount, 512),
198 QUOTE_FORCE_HEX);
199 break;
200
201 case KD_FONT_OP_SET_DEFAULT:
202 if (entering(tcp)) {
203 tprint_struct_next();
204 tprints_field_name("data");
205 printstr_ex(tcp, (mpers_ptr_t) cfo->data,
206 KERNEL_MAX_FONT_NAME,
207 QUOTE_0_TERMINATED
208 | QUOTE_EXPECT_TRAILING_0);
209 }
210 break;
211
212 case KD_FONT_OP_COPY:
213 break;
214
215 default:
216 tprint_struct_next();
217 PRINT_FIELD_PTR(*cfo, data);
218 }
219
220 tprint_struct_end();
221 }
222
223 static int
224 kd_font_op(struct tcb *const tcp, const kernel_ulong_t arg)
225 {
226 struct_console_font_op val;
227
228 if (entering(tcp)) {
229 tprint_arg_next();
230
231 if (umove_or_printaddr(tcp, arg, &val))
232 return RVAL_IOCTL_DECODED;
233 } else {
234 if (syserror(tcp) || umove(tcp, arg, &val))
235 return RVAL_IOCTL_DECODED;
236
237 tprint_value_changed();
238 }
239
240 print_console_font_op(tcp, &val);
241
242 switch (val.op) {
243 case KD_FONT_OP_SET:
244 case KD_FONT_OP_COPY:
245 return RVAL_IOCTL_DECODED;
246 }
247
248 return entering(tcp) ? 0 : RVAL_IOCTL_DECODED;
249 }
250
251 MPERS_PRINTER_DECL(int, kd_mpers_ioctl, struct tcb *const tcp,
252 const unsigned int code, const kernel_ulong_t arg)
253 {
254 switch (code)
255 {
256 case GIO_UNIMAP:
257 case PIO_UNIMAP:
258 return kd_unimap(tcp, arg, code == GIO_UNIMAP);
259
260 case GIO_FONTX:
261 case PIO_FONTX:
262 return kd_fontx(tcp, arg, code == GIO_FONTX);
263
264 case KDFONTOP:
265 return kd_font_op(tcp, arg);
266 }
267
268 return RVAL_DECODED;
269 }