1 /*
2 * Check decoding of UBI ioctl commands.
3 *
4 * Copyright (c) 2016-2021 The strace developers.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "tests.h"
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/ioctl.h>
16 #include <mtd/ubi-user.h>
17
18 static const unsigned long long llmagic = 0xdeadbeefbadc0dedULL;
19 static const unsigned long lmagic = (unsigned long) 0xdeadbeefbadc0dedULL;
20 static const unsigned int imagic = 0xdeadbeef;
21
22 static const char *errstr;
23
24 static int
25 do_ioctl(kernel_ulong_t cmd, kernel_ulong_t arg)
26 {
27 int rc = ioctl(-1, cmd, arg);
28 errstr = sprintrc(rc);
29
30 #ifdef INJECT_RETVAL
31 if (rc != INJECT_RETVAL)
32 error_msg_and_fail("Return value [%d] does not match"
33 " expectations [%d]", rc, INJECT_RETVAL);
34
35 static char inj_errstr[4096];
36
37 snprintf(inj_errstr, sizeof(inj_errstr), "%s (INJECTED)", errstr);
38 errstr = inj_errstr;
39 #endif
40
41 return rc;
42 }
43
44 static int
45 do_ioctl_ptr(kernel_ulong_t cmd, const void *arg)
46 {
47 return do_ioctl(cmd, (uintptr_t) arg);
48 }
49
50 #ifdef INJECT_RETVAL
51 static void
52 skip_ioctls(int argc, const char *argv[])
53 {
54 if (argc < 2)
55 error_msg_and_fail("Usage: %s NUM_SKIP", argv[0]);
56
57 unsigned long num_skip = strtoul(argv[1], NULL, 0);
58
59 for (size_t i = 0; i < num_skip; ++i) {
60 int rc = ioctl(-1, UBI_IOCATT, 0);
61 printf("ioctl(-1, UBI_IOCATT, NULL) = %s%s\n", sprintrc(rc),
62 rc == INJECT_RETVAL ? " (INJECTED)" : "");
63 if (rc == INJECT_RETVAL)
64 return;
65 }
66
67 error_msg_and_fail("Issued %lu ioctl syscalls but failed"
68 " to detect an injected return code %d",
69 num_skip, INJECT_RETVAL);
70 }
71 #endif /* INJECT_RETVAL */
72
73 int
74 main(int argc, const char *argv[])
75 {
76 #ifdef INJECT_RETVAL
77 skip_ioctls(argc, argv);
78 #endif
79
80 static const struct {
81 unsigned int cmd;
82 const char *str;
83 }
84 noarg_cmds[] = {
85 { ARG_STR(UBI_IOCVOLCRBLK) },
86 { ARG_STR(UBI_IOCVOLRMBLK) },
87 },
88 pint_cmds[] = {
89 { ARG_STR(UBI_IOCDET) },
90 { ARG_STR(UBI_IOCEBER) },
91 { ARG_STR(UBI_IOCEBISMAP) },
92 { ARG_STR(UBI_IOCEBUNMAP) },
93 { ARG_STR(UBI_IOCRMVOL) },
94 { ARG_STR(UBI_IOCRPEB) },
95 { ARG_STR(UBI_IOCSPEB) },
96 }, pint64_cmds[] = {
97 { ARG_STR(UBI_IOCVOLUP) },
98 }, ptr_cmds[] = {
99 { ARG_STR(UBI_IOCATT) },
100 { ARG_STR(UBI_IOCEBCH) },
101 { ARG_STR(UBI_IOCEBMAP) },
102 { ARG_STR(UBI_IOCMKVOL) },
103 { ARG_STR(UBI_IOCRNVOL) },
104 { ARG_STR(UBI_IOCRSVOL) },
105 { ARG_STR(UBI_IOCSETVOLPROP) },
106 }, attach_cmds[] = {
107 { ARG_STR(UBI_IOCATT) },
108 }, leb_cmds[] = {
109 { ARG_STR(UBI_IOCEBCH) },
110 }, map_cmds[] = {
111 { ARG_STR(UBI_IOCEBMAP) },
112 }, mkvol_cmds[] = {
113 { ARG_STR(UBI_IOCMKVOL) },
114 }, rnvol_cmds[] = {
115 { ARG_STR(UBI_IOCRNVOL) },
116 }, rsvol_cmds[] = {
117 { ARG_STR(UBI_IOCRSVOL) },
118 }, prop_cmds[] = {
119 { ARG_STR(UBI_IOCSETVOLPROP) },
120 };
121
122 for (size_t i = 0; i < ARRAY_SIZE(noarg_cmds); ++i) {
123 do_ioctl(noarg_cmds[i].cmd, lmagic);
124 printf("ioctl(-1, %s) = %s\n",
125 noarg_cmds[i].str, errstr);
126 }
127
128 TAIL_ALLOC_OBJECT_CONST_PTR(int, pint);
129 *pint = imagic;
130
131 for (size_t i = 0; i < ARRAY_SIZE(pint_cmds); ++i) {
132 do_ioctl_ptr(pint_cmds[i].cmd, pint);
133 printf("ioctl(-1, %s, [%d]) = %s\n",
134 pint_cmds[i].str, *pint, errstr);
135 }
136
137 TAIL_ALLOC_OBJECT_CONST_PTR(int64_t, pint64);
138 *pint64 = (int64_t) llmagic;
139
140 for (size_t i = 0; i < ARRAY_SIZE(pint64_cmds); ++i) {
141 do_ioctl_ptr(pint64_cmds[i].cmd, pint64);
142 printf("ioctl(-1, %s, [%jd]) = %s\n",
143 pint64_cmds[i].str, (intmax_t) *pint64, errstr);
144 }
145
146 void *const efault = tail_alloc(1);
147
148 for (size_t i = 0; i < ARRAY_SIZE(ptr_cmds); ++i) {
149 do_ioctl(ptr_cmds[i].cmd, 0);
150 printf("ioctl(-1, %s, NULL) = %s\n",
151 ptr_cmds[i].str, errstr);
152 do_ioctl_ptr(ptr_cmds[i].cmd, efault);
153 printf("ioctl(-1, %s, %p) = %s\n",
154 ptr_cmds[i].str, efault, errstr);
155 }
156
157 TAIL_ALLOC_OBJECT_CONST_PTR(struct ubi_attach_req, attach);
158 fill_memory(attach, sizeof(*attach));
159
160 for (size_t i = 0; i < ARRAY_SIZE(attach_cmds); ++i) {
161 int rc = do_ioctl_ptr(attach_cmds[i].cmd, attach);
162 printf("ioctl(-1, %s, {ubi_num=%d, mtd_num=%d"
163 ", vid_hdr_offset=%d, max_beb_per1024=%hd}",
164 attach_cmds[i].str, attach->ubi_num,
165 attach->mtd_num, attach->vid_hdr_offset,
166 attach->max_beb_per1024);
167 if (rc >= 0)
168 printf(" => [%d]", attach->ubi_num);
169 printf(") = %s\n", errstr);
170 }
171
172 TAIL_ALLOC_OBJECT_CONST_PTR(struct ubi_leb_change_req, leb);
173 fill_memory(leb, sizeof(*leb));
174 leb->dtype = 3;
175
176 for (size_t i = 0; i < ARRAY_SIZE(leb_cmds); ++i) {
177 do_ioctl_ptr(leb_cmds[i].cmd, leb);
178 printf("ioctl(-1, %s, {lnum=%d, bytes=%d, dtype=%s}) = %s\n",
179 leb_cmds[i].str, leb->lnum, leb->bytes, "UBI_UNKNOWN",
180 errstr);
181 }
182
183 TAIL_ALLOC_OBJECT_CONST_PTR(struct ubi_map_req, map);
184 fill_memory(map, sizeof(*map));
185 map->dtype = 3;
186
187 for (size_t i = 0; i < ARRAY_SIZE(map_cmds); ++i) {
188 do_ioctl_ptr(map_cmds[i].cmd, map);
189 printf("ioctl(-1, %s, {lnum=%d, dtype=%s}) = %s\n",
190 map_cmds[i].str, map->lnum, "UBI_UNKNOWN", errstr);
191 }
192
193 TAIL_ALLOC_OBJECT_CONST_PTR(struct ubi_mkvol_req, mkvol);
194 fill_memory(mkvol, sizeof(*mkvol));
195 mkvol->vol_type = 4;
196 mkvol->flags = 1;
197 fill_memory_ex(mkvol->name, sizeof(mkvol->name), '0', 10);
198
199 for (size_t i = 0; i < ARRAY_SIZE(mkvol_cmds); ++i) {
200 static const int lens[] = {
201 -1, 0, 1, UBI_MAX_VOLUME_NAME,
202 UBI_MAX_VOLUME_NAME + 1
203 };
204 for (size_t j = 0; j < ARRAY_SIZE(lens); ++j) {
205 mkvol->name_len = lens[j];
206 int len = CLAMP(mkvol->name_len, 0,
207 UBI_MAX_VOLUME_NAME);
208 int rc = do_ioctl_ptr(mkvol_cmds[i].cmd, mkvol);
209 printf("ioctl(-1, %s, {vol_id=%d, alignment=%d"
210 ", bytes=%jd, vol_type=%s, flags=%s"
211 ", name_len=%hd, name=\"%.*s\"...}",
212 mkvol_cmds[i].str, mkvol->vol_id,
213 mkvol->alignment, (intmax_t) mkvol->bytes,
214 "UBI_STATIC_VOLUME",
215 "UBI_VOL_SKIP_CRC_CHECK_FLG",
216 mkvol->name_len, len, mkvol->name);
217 if (rc >= 0)
218 printf(" => [%d]", mkvol->vol_id);
219 printf(") = %s\n", errstr);
220 }
221 }
222
223 TAIL_ALLOC_OBJECT_CONST_PTR(struct ubi_rnvol_req, rnvol);
224
225 for (size_t i = 0; i < ARRAY_SIZE(rnvol_cmds); ++i) {
226 fill_memory(rnvol, sizeof(*rnvol));
227 do_ioctl_ptr(rnvol_cmds[i].cmd, rnvol);
228 printf("ioctl(-1, %s, {count=%d, ents=[]}) = %s\n",
229 rnvol_cmds[i].str, rnvol->count, errstr);
230
231 rnvol->count = 1;
232 do_ioctl_ptr(rnvol_cmds[i].cmd, rnvol);
233 printf("ioctl(-1, %s, {count=%d, ents=[{vol_id=%d"
234 ", name_len=%hd, name=\"\"...}]}) = %s\n",
235 rnvol_cmds[i].str, rnvol->count,
236 rnvol->ents[0].vol_id, rnvol->ents[0].name_len, errstr);
237
238 rnvol->count = UBI_MAX_RNVOL + 1;
239 for (size_t j = 0; j < UBI_MAX_RNVOL; ++j) {
240 fill_memory_ex(rnvol->ents[j].name,
241 sizeof(rnvol->ents[j].name), '0', 10);
242 }
243 rnvol->ents[0].name_len = 0;
244 rnvol->ents[1].name_len = 1;
245 rnvol->ents[2].name_len = 1;
246 rnvol->ents[2].name[1] = '\0';
247 rnvol->ents[3].name_len = 2;
248 rnvol->ents[3].name[1] = '\0';
249 rnvol->ents[4].name_len = UBI_MAX_VOLUME_NAME;
250 rnvol->ents[5].name_len = UBI_MAX_VOLUME_NAME;
251 rnvol->ents[5].name[UBI_MAX_VOLUME_NAME] = '\0';
252 rnvol->ents[6].name_len = UBI_MAX_VOLUME_NAME;
253 rnvol->ents[6].name[UBI_MAX_VOLUME_NAME - 1] = '\0';
254 rnvol->ents[7].name_len = UBI_MAX_VOLUME_NAME + 1;
255 rnvol->ents[8].name_len = UBI_MAX_VOLUME_NAME + 1;
256 rnvol->ents[8].name[UBI_MAX_VOLUME_NAME] = '\0';
257 do_ioctl_ptr(rnvol_cmds[i].cmd, rnvol);
258 printf("ioctl(-1, %s, {count=%d, ents=[",
259 rnvol_cmds[i].str, rnvol->count);
260 for (size_t j = 0; j < UBI_MAX_RNVOL; ++j) {
261 int len = CLAMP(rnvol->ents[j].name_len, 0,
262 UBI_MAX_VOLUME_NAME);
263 bool dots = rnvol->ents[j].name[len] &&
264 (len <= 0 || rnvol->ents[j].name[len - 1]);
265 printf("%s{vol_id=%d, name_len=%hd, name=\"%.*s\"%s}",
266 j ? ", " : "",
267 rnvol->ents[j].vol_id,
268 rnvol->ents[j].name_len,
269 len, rnvol->ents[j].name,
270 dots ? "..." : "");
271 }
272 printf("]}) = %s\n", errstr);
273 }
274
275 TAIL_ALLOC_OBJECT_CONST_PTR(struct ubi_rsvol_req, rsvol);
276 fill_memory(rsvol, sizeof(*rsvol));
277
278 for (size_t i = 0; i < ARRAY_SIZE(rsvol_cmds); ++i) {
279 do_ioctl_ptr(rsvol_cmds[i].cmd, rsvol);
280 printf("ioctl(-1, %s, {bytes=%jd, vol_id=%d}) = %s\n",
281 rsvol_cmds[i].str, (intmax_t) rsvol->bytes,
282 rsvol->vol_id, errstr);
283 }
284
285 TAIL_ALLOC_OBJECT_CONST_PTR(struct ubi_set_vol_prop_req, prop);
286 fill_memory(prop, sizeof(*prop));
287 prop->property = UBI_VOL_PROP_DIRECT_WRITE;
288
289 for (size_t i = 0; i < ARRAY_SIZE(prop_cmds); ++i) {
290 do_ioctl_ptr(prop_cmds[i].cmd, prop);
291 printf("ioctl(-1, %s, {property=%s, value=%#jx}) = %s\n",
292 prop_cmds[i].str, "UBI_VOL_PROP_DIRECT_WRITE",
293 (uintmax_t) prop->value, errstr);
294 }
295
296 do_ioctl(_IO(0x6f, 0x35), lmagic);
297 printf("ioctl(-1, %s, %#lx) = %s\n", "NET_REMOVE_IF", lmagic, errstr);
298
299 puts("+++ exited with 0 +++");
300 return 0;
301 }