• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Check decoding of DM_* commands of ioctl syscall.
3  *
4  * Copyright (c) 2016 Mikulas Patocka <mpatocka@redhat.com>
5  * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
6  * Copyright (c) 2016-2017 The strace developers.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "tests.h"
33 
34 #ifdef HAVE_LINUX_DM_IOCTL_H
35 
36 # include <errno.h>
37 # include <inttypes.h>
38 # include <stdbool.h>
39 # include <stdio.h>
40 # include <stddef.h>
41 # include <string.h>
42 # include <sys/ioctl.h>
43 # include <linux/ioctl.h>
44 # include <linux/dm-ioctl.h>
45 
46 # ifndef VERBOSE
47 #  define VERBOSE 0
48 # endif
49 
50 # define STR32 "AbCdEfGhIjKlMnOpQrStUvWxYz012345"
51 
52 # define ALIGNED_SIZE(s_, t_) \
53 	(((s_) + (ALIGNOF(t_) - 1UL)) & ~(ALIGNOF(t_) - 1UL))
54 # define ALIGNED_OFFSET(t_, m_) \
55 	ALIGNED_SIZE(offsetof(t_, m_), t_)
56 
57 static const char str129[] = STR32 STR32 STR32 STR32 "6";
58 
59 static const __u64 dts_sector_base = (__u64) 0xdeadca75facef157ULL;
60 static const __u64 dts_sector_step = (__u64) 0x100000001ULL;
61 static const __u64 dts_length_base = (__u64) 0xbadc0dedda7a1057ULL;
62 static const __u64 dts_length_step = (__u64) 0x700000007ULL;
63 static const __s32 dts_status_base = (__s32) 3141592653U;
64 static const __s32 dts_status_step = 0x1234;
65 
66 static const size_t min_sizeof_dm_ioctl =
67 	offsetof(struct dm_ioctl, data);
68 
69 static struct s {
70 	struct dm_ioctl ioc;
71 	union {
72 		struct {
73 			struct dm_target_spec target_spec;
74 			char target_params[256];
75 		} ts;
76 		struct {
77 			struct dm_target_msg target_msg;
78 			char target_string[256];
79 		} tm;
80 		char string[256];
81 	} u;
82 } s;
83 
84 struct dm_table_open_test {
85 	struct dm_ioctl ioc;
86 	struct dm_target_spec target0;
87 	char param0[1];
88 	struct dm_target_spec target1;
89 	char param1[2];
90 	struct dm_target_spec target2;
91 	char param2[3];
92 	struct dm_target_spec target3;
93 	char param3[4];
94 	struct dm_target_spec target4;
95 	char param4[5];
96 	struct dm_target_spec target5;
97 	char param5[6];
98 	struct dm_target_spec target6;
99 	char param6[7];
100 	struct dm_target_spec target7;
101 	char param7[8];
102 	struct dm_target_spec target8;
103 	char param8[9];
104 	struct dm_target_spec target9;
105 	char param9[10];
106 };
107 
108 struct dm_target_msg_test {
109 	struct dm_ioctl ioc;
110 	struct dm_target_msg msg;
111 };
112 
113 struct args {
114 	unsigned int arg;
115 	const char *str;
116 	bool has_params;
117 	bool has_event_nr;
118 };
119 
120 
121 static void
init_s(struct dm_ioctl * s,size_t size,size_t offs)122 init_s(struct dm_ioctl *s, size_t size, size_t offs)
123 {
124 	memset(s, 0, size);
125 	s->version[0] = DM_VERSION_MAJOR;
126 	s->version[1] = 1;
127 	s->version[2] = 2;
128 	s->data_size = size;
129 	s->data_start = offs;
130 	s->dev = 0x1234;
131 	strcpy(s->name, "nnn");
132 	strcpy(s->uuid, "uuu");
133 }
134 
135 static void
init_dm_target_spec(struct dm_target_spec * ptr,uint32_t id)136 init_dm_target_spec(struct dm_target_spec *ptr, uint32_t id)
137 {
138 	ptr->sector_start = dts_sector_base + dts_sector_step * id;
139 	ptr->length       = dts_length_base + dts_length_step * id;
140 	ptr->status       = dts_status_base + dts_status_step * id;
141 
142 	strncpy(ptr->target_type, str129 +
143 		id % (sizeof(str129) - sizeof(ptr->target_type)),
144 		id % (sizeof(ptr->target_type) + 1));
145 	if (id % (sizeof(ptr->target_type) + 1) < sizeof(ptr->target_type))
146 		ptr->target_type[id % (sizeof(ptr->target_type) + 1)] = '\0';
147 }
148 
149 # if VERBOSE
150 static void
print_dm_target_spec(struct dm_target_spec * ptr,uint32_t id)151 print_dm_target_spec(struct dm_target_spec *ptr, uint32_t id)
152 {
153 	printf("{sector_start=%" PRI__u64 ", length=%" PRI__u64 ", "
154 	       "target_type=\"%.*s\", string=",
155 	       dts_sector_base + dts_sector_step * id,
156 	       dts_length_base + dts_length_step * id,
157 	       (int) (id % (sizeof(ptr->target_type) + 1)),
158 	       str129 + id % (sizeof(str129) - sizeof(ptr->target_type)));
159 }
160 # endif /* VERBOSE */
161 
162 int
main(void)163 main(void)
164 {
165 	static kernel_ulong_t dummy_dm_ioctl1 =
166 		_IOC(_IOC_READ, DM_IOCTL, 0, 0x1fff);
167 	static kernel_ulong_t dummy_dm_ioctl2 =
168 		_IOC(_IOC_READ|_IOC_WRITE, DM_IOCTL, 0xed, 0);
169 	static kernel_ulong_t dummy_dm_arg =
170 		(kernel_ulong_t) 0xbadc0dedda7a1057ULL;
171 	/* We can't check these properly for now */
172 	static struct args dummy_check_cmds_nodev[] = {
173 		{ ARG_STR(DM_REMOVE_ALL),    false },
174 		{ ARG_STR(DM_LIST_DEVICES),  true  },
175 		{ ARG_STR(DM_LIST_VERSIONS), true  },
176 	};
177 	static struct args dummy_check_cmds[] = {
178 		{ ARG_STR(DM_DEV_CREATE),    false },
179 		{ ARG_STR(DM_DEV_REMOVE),    false, true },
180 		{ ARG_STR(DM_DEV_STATUS),    false },
181 		{ ARG_STR(DM_DEV_WAIT),      true,  true },
182 		{ ARG_STR(DM_TABLE_CLEAR),   false },
183 		{ ARG_STR(DM_TABLE_DEPS),    true  },
184 		{ ARG_STR(DM_TABLE_STATUS),  true  },
185 	};
186 
187 	struct dm_ioctl *unaligned_dm_arg =
188 		tail_alloc(offsetof(struct dm_ioctl, data));
189 	struct dm_ioctl *dm_arg =
190 		tail_alloc(ALIGNED_OFFSET(struct dm_ioctl, data));
191 	struct dm_table_open_test *dm_arg_open1 =
192 		tail_alloc(ALIGNED_OFFSET(struct dm_table_open_test, target1));
193 	struct dm_table_open_test *dm_arg_open2 =
194 		tail_alloc(ALIGNED_OFFSET(struct dm_table_open_test, param1));
195 	struct dm_table_open_test *dm_arg_open3 =
196 		tail_alloc(ALIGNED_OFFSET(struct dm_table_open_test, target9));
197 	struct dm_target_msg_test *dm_arg_msg =
198 		tail_alloc(sizeof(*dm_arg_msg));
199 
200 	long rc;
201 	const char *errstr;
202 	unsigned int i;
203 
204 
205 	/* Incorrect operation */
206 	ioctl(-1, _IOW(DM_IOCTL, 0xde, int), dm_arg);
207 	printf("ioctl(-1, _IOC(_IOC_WRITE, %#x, 0xde, %#zx), %p) = "
208 	       "-1 EBADF (%m)\n",
209 	       DM_IOCTL, sizeof(int), dm_arg);
210 
211 	ioctl(-1, dummy_dm_ioctl1, 0);
212 	printf("ioctl(-1, _IOC(_IOC_READ, %#x, 0, %#x), 0) = -1 EBADF (%m)\n",
213 	       DM_IOCTL, (unsigned int) _IOC_SIZE(dummy_dm_ioctl1));
214 
215 	ioctl(-1, dummy_dm_ioctl2, dummy_dm_arg);
216 	printf("ioctl(-1, _IOC(_IOC_READ|_IOC_WRITE, %#x, %#x, 0), %#lx) = "
217 	       "-1 EBADF (%m)\n",
218 	       DM_IOCTL, (unsigned int) _IOC_NR(dummy_dm_ioctl2),
219 	       (unsigned long) dummy_dm_arg);
220 
221 
222 	/* DM_VERSION */
223 	/* Incorrect pointer */
224 	ioctl(-1, DM_VERSION, dm_arg + 1);
225 	printf("ioctl(-1, DM_VERSION, %p) = -1 EBADF (%m)\n", dm_arg + 1);
226 
227 	/* Incorrect data_size */
228 	init_s(dm_arg, 0, 0);
229 	ioctl(-1, DM_VERSION, &s);
230 	printf("ioctl(-1, DM_VERSION, %p) = -1 EBADF (%m)\n", &s);
231 
232 	/* Incorrect version */
233 	init_s(dm_arg, min_sizeof_dm_ioctl, 0);
234 	dm_arg->version[0] = 0xbadc0ded;
235 	dm_arg->version[1] = 0xbadc0dee;
236 	dm_arg->version[2] = 0xbadc0def;
237 	ioctl(-1, DM_VERSION, dm_arg);
238 	printf("ioctl(-1, DM_VERSION, {version=%u.%u.%u"
239 	       " /* unsupported device mapper ABI version */}) = "
240 	       "-1 EBADF (%m)\n", 0xbadc0ded, 0xbadc0dee, 0xbadc0def);
241 
242 	/* Incorrect data_size */
243 	init_s(dm_arg, 14, 64);
244 	ioctl(-1, DM_VERSION, dm_arg);
245 	printf("ioctl(-1, DM_VERSION, {version=4.1.2, data_size=14"
246 	       " /* data_size too small */}) = -1 EBADF (%m)\n");
247 
248 	/* Unterminated name/uuid */
249 	init_s(dm_arg, min_sizeof_dm_ioctl, 0);
250 	strncpy(dm_arg->name, str129, sizeof(dm_arg->name));
251 	strncpy(dm_arg->uuid, str129, sizeof(dm_arg->uuid));
252 	ioctl(-1, DM_VERSION, dm_arg);
253 	printf("ioctl(-1, DM_VERSION, {version=4.1.2, data_size=%zu, "
254 	       "dev=makedev(18, 52), name=\"%.127s\", uuid=\"%.128s\", "
255 	       "flags=0}) = -1 EBADF (%m)\n",
256 	       min_sizeof_dm_ioctl, str129, str129);
257 
258 	/* Normal call */
259 	init_s(dm_arg, min_sizeof_dm_ioctl, 0);
260 	ioctl(-1, DM_VERSION, dm_arg);
261 	printf("ioctl(-1, DM_VERSION, "
262 	       "{version=4.1.2, data_size=%zu, "
263 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0}) = "
264 	       "-1 EBADF (%m)\n", min_sizeof_dm_ioctl);
265 
266 	/* Zero dev, name, uuid */
267 	init_s(dm_arg, min_sizeof_dm_ioctl, 0);
268 	dm_arg->data_size = 0xfacefeed;
269 	dm_arg->dev = 0;
270 	dm_arg->name[0] = '\0';
271 	dm_arg->uuid[0] = '\0';
272 	ioctl(-1, DM_VERSION, dm_arg);
273 	printf("ioctl(-1, DM_VERSION, "
274 	       "{version=4.1.2, data_size=%u, flags=0}) = "
275 	       "-1 EBADF (%m)\n", 0xfacefeed);
276 
277 	/* Flag */
278 	init_s(dm_arg, min_sizeof_dm_ioctl, 0);
279 	dm_arg->flags = 0xffffffff;
280 	ioctl(-1, DM_VERSION, dm_arg);
281 	printf("ioctl(-1, DM_VERSION, "
282 	       "{version=4.1.2, data_size=%zu, "
283 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags="
284 	       "DM_READONLY_FLAG|DM_SUSPEND_FLAG|DM_EXISTS_FLAG|"
285 	       "DM_PERSISTENT_DEV_FLAG|DM_STATUS_TABLE_FLAG|"
286 	       "DM_ACTIVE_PRESENT_FLAG|DM_INACTIVE_PRESENT_FLAG|"
287 	       "DM_BUFFER_FULL_FLAG|DM_SKIP_BDGET_FLAG|DM_SKIP_LOCKFS_FLAG|"
288 	       "DM_NOFLUSH_FLAG|DM_QUERY_INACTIVE_TABLE_FLAG|"
289 	       "DM_UEVENT_GENERATED_FLAG|DM_UUID_FLAG|DM_SECURE_DATA_FLAG|"
290 	       "DM_DATA_OUT_FLAG|DM_DEFERRED_REMOVE|DM_INTERNAL_SUSPEND_FLAG|"
291 	       "0xfff80080}) = -1 EBADF (%m)\n",
292 	       min_sizeof_dm_ioctl);
293 
294 	/* Normal call */
295 	init_s(&s.ioc, sizeof(s.ioc), 0);
296 	ioctl(-1, DM_VERSION, &s);
297 	printf("ioctl(-1, DM_VERSION, "
298 	       "{version=4.1.2, data_size=%zu, "
299 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0}) = "
300 	       "-1 EBADF (%m)\n", sizeof(s.ioc));
301 
302 
303 	/* DM_REMOVE_ALL */
304 	/* DM_LIST_DEVICES */
305 	/* DM_LIST_VERSIONS */
306 	for (i = 0; i < ARRAY_SIZE(dummy_check_cmds_nodev); i++) {
307 		init_s(dm_arg, min_sizeof_dm_ioctl, 0);
308 		ioctl(-1, dummy_check_cmds_nodev[i].arg, dm_arg);
309 		printf("ioctl(-1, %s, {version=4.1.2, data_size=%zu%s, "
310 		       "flags=0}) = -1 EBADF (%m)\n",
311 		       dummy_check_cmds_nodev[i].str,
312 		       min_sizeof_dm_ioctl,
313 		       dummy_check_cmds_nodev[i].has_params ?
314 		       ", data_start=0" : "");
315 	}
316 
317 
318 	/* DM_DEV_CREATE */
319 	/* DM_DEV_REMOVE */
320 	/* DM_DEV_STATUS */
321 	/* DM_DEV_WAIT */
322 	/* DM_TABLE_CLEAR */
323 	/* DM_TABLE_DEPS */
324 	/* DM_TABLE_STATUS */
325 	for (i = 0; i < ARRAY_SIZE(dummy_check_cmds); i++) {
326 		init_s(dm_arg, min_sizeof_dm_ioctl, 0);
327 		ioctl(-1, dummy_check_cmds[i].arg, dm_arg);
328 		printf("ioctl(-1, %s, {version=4.1.2, data_size=%zu%s, "
329 		       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\"%s, "
330 		       "flags=0}) = -1 EBADF (%m)\n",
331 		       dummy_check_cmds[i].str, min_sizeof_dm_ioctl,
332 		       dummy_check_cmds[i].has_params ? ", data_start=0" : "",
333 		       dummy_check_cmds[i].has_event_nr ? ", event_nr=0" : "");
334 	}
335 
336 
337 	/* DM_DEV_SUSPEND */
338 	init_s(&s.ioc, sizeof(s.ioc), 0);
339 	s.ioc.flags = DM_SUSPEND_FLAG;
340 	s.ioc.event_nr = 0xbadc0ded;
341 	ioctl(-1, DM_DEV_SUSPEND, &s);
342 	printf("ioctl(-1, DM_DEV_SUSPEND, "
343 	       "{version=4.1.2, data_size=%zu, "
344 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
345 	       "flags=DM_SUSPEND_FLAG}) = -1 EBADF (%m)\n", sizeof(s.ioc));
346 
347 	init_s(&s.ioc, sizeof(s.ioc), 0);
348 	s.ioc.event_nr = 0xbadc0ded;
349 	ioctl(-1, DM_DEV_SUSPEND, &s);
350 	printf("ioctl(-1, DM_DEV_SUSPEND, "
351 	       "{version=4.1.2, data_size=%zu, dev=makedev(18, 52), "
352 	       "name=\"nnn\", uuid=\"uuu\", event_nr=3134983661, "
353 	       "flags=0}) = -1 EBADF (%m)\n", sizeof(s.ioc));
354 
355 
356 	/* DM_TABLE_LOAD */
357 	init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
358 	s.ioc.target_count = 1;
359 	s.u.ts.target_spec.sector_start = 0x10;
360 	s.u.ts.target_spec.length = 0x20;
361 	s.u.ts.target_spec.next =
362 		sizeof(s.u.ts.target_spec) + sizeof(s.u.ts.target_params);
363 	strcpy(s.u.ts.target_spec.target_type, "tgt");
364 	strcpy(s.u.ts.target_params, "tparams");
365 	ioctl(-1, DM_TABLE_LOAD, &s);
366 	printf("ioctl(-1, DM_TABLE_LOAD, "
367 	       "{version=4.1.2, data_size=%u, data_start=%u, "
368 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
369 	       "target_count=1, flags=0, "
370 # if VERBOSE
371 	       "{sector_start=16, length=32, target_type=\"tgt\", "
372 	       "string=\"tparams\"}"
373 # else /* !VERBOSE */
374 	       "..."
375 # endif /* VERBOSE */
376 	       "}) = -1 EBADF (%m)\n", s.ioc.data_size, s.ioc.data_start);
377 
378 	/* No targets */
379 	init_s(dm_arg, min_sizeof_dm_ioctl, min_sizeof_dm_ioctl);
380 	dm_arg->data_size = sizeof(*dm_arg);
381 	dm_arg->target_count = 0;
382 	ioctl(-1, DM_TABLE_LOAD, dm_arg);
383 	printf("ioctl(-1, DM_TABLE_LOAD, "
384 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
385 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
386 	       "target_count=0, flags=0}) = -1 EBADF (%m)\n",
387 	       sizeof(*dm_arg), min_sizeof_dm_ioctl);
388 
389 	/* Invalid data_start */
390 	init_s(dm_arg, min_sizeof_dm_ioctl, 0xfffffff8);
391 	dm_arg->data_size = sizeof(*dm_arg);
392 	dm_arg->target_count = 1234;
393 	ioctl(-1, DM_TABLE_LOAD, dm_arg);
394 	printf("ioctl(-1, DM_TABLE_LOAD, "
395 	       "{version=4.1.2, data_size=%zu, data_start=%u, "
396 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
397 	       "target_count=1234, flags=0, "
398 # if VERBOSE
399 	       "??? /* misplaced struct dm_target_spec */"
400 # else
401 	       "..."
402 # endif /* VERBOSE */
403 	       "}) = -1 EBADF (%m)\n", sizeof(*dm_arg), 0xfffffff8);
404 
405 	/* Inaccessible pointer */
406 	init_s(&dm_arg_open1->ioc, offsetof(struct dm_table_open_test, target1),
407 	       offsetof(struct dm_table_open_test, target1));
408 	dm_arg_open1->ioc.data_size = sizeof(*dm_arg_open1);
409 	dm_arg_open1->ioc.target_count = 0xdeaddea1;
410 	ioctl(-1, DM_TABLE_LOAD, dm_arg_open1);
411 	printf("ioctl(-1, DM_TABLE_LOAD, "
412 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
413 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
414 	       "target_count=3735936673, flags=0, "
415 # if VERBOSE
416 	       "%p"
417 # else /* !VERBOSE */
418 	       "..."
419 # endif /* VERBOSE */
420 	       "}) = -1 EBADF (%m)\n", sizeof(*dm_arg_open1),
421 	       offsetof(struct dm_table_open_test, target1)
422 # if VERBOSE
423 	       , (char *) dm_arg_open1 +
424 	       offsetof(struct dm_table_open_test, target1)
425 # endif /* VERBOSE */
426 	       );
427 
428 	/* Inaccessible string */
429 	init_s(&dm_arg_open2->ioc, offsetof(struct dm_table_open_test, param1),
430 	       offsetof(struct dm_table_open_test, target1));
431 	dm_arg_open2->ioc.data_size = sizeof(*dm_arg_open2);
432 	dm_arg_open2->ioc.target_count = 2;
433 	init_dm_target_spec(&dm_arg_open2->target1, 7);
434 	dm_arg_open2->target1.next =
435 		offsetof(struct dm_table_open_test, target3) -
436 		offsetof(struct dm_table_open_test, target1);
437 	rc = ioctl(-1, DM_TABLE_LOAD, dm_arg_open2);
438 	errstr = sprintrc(rc);
439 	printf("ioctl(-1, DM_TABLE_LOAD, "
440 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
441 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
442 	       "target_count=2, flags=0, ",
443 	       sizeof(*dm_arg_open2),
444 	       offsetof(struct dm_table_open_test, target1));
445 # if VERBOSE
446 	print_dm_target_spec(&dm_arg_open2->target1, 7);
447 	printf("%p}, %p",
448 	       (char *) dm_arg_open2 +
449 	       offsetof(struct dm_table_open_test, param1),
450 	       (char *) dm_arg_open2 +
451 	       offsetof(struct dm_table_open_test, target3));
452 # else /* !VERBOSE */
453 	printf("...");
454 # endif /* VERBOSE */
455 	printf("}) = %s\n", errstr);
456 
457 	/* Incorrect next */
458 	init_s(&dm_arg_open3->ioc, offsetof(struct dm_table_open_test, target5),
459 	       offsetof(struct dm_table_open_test, target0));
460 	dm_arg_open3->ioc.target_count = 4;
461 
462 	init_dm_target_spec(&dm_arg_open3->target0, 9);
463 	dm_arg_open3->target0.next =
464 		offsetof(struct dm_table_open_test, target1) -
465 		offsetof(struct dm_table_open_test, target0);
466 	dm_arg_open3->param0[0] = '\0';
467 
468 	init_dm_target_spec(&dm_arg_open3->target1, 15);
469 	dm_arg_open3->target1.next =
470 		offsetof(struct dm_table_open_test, target3) -
471 		offsetof(struct dm_table_open_test, target1);
472 	dm_arg_open3->param1[0] = '\377';
473 	dm_arg_open3->param1[1] = '\0';
474 
475 	init_dm_target_spec(&dm_arg_open3->target3, 42);
476 	dm_arg_open3->target3.next = 0xdeadbeef;
477 	dm_arg_open3->param3[0] = '\1';
478 	dm_arg_open3->param3[1] = '\2';
479 	dm_arg_open3->param3[2] = '\0';
480 
481 	rc = ioctl(-1, DM_TABLE_LOAD, dm_arg_open3);
482 	errstr = sprintrc(rc);
483 	printf("ioctl(-1, DM_TABLE_LOAD, "
484 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
485 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
486 	       "target_count=4, flags=0, ",
487 	       offsetof(struct dm_table_open_test, target5),
488 	       offsetof(struct dm_table_open_test, target0));
489 # if VERBOSE
490 	print_dm_target_spec(&dm_arg_open3->target0, 9);
491 	printf("\"\"}, ");
492 	print_dm_target_spec(&dm_arg_open3->target1, 15);
493 	printf("\"\\377\"}, ");
494 	print_dm_target_spec(&dm_arg_open3->target1, 42);
495 	printf("\"\\1\\2\"}, ??? /* misplaced struct dm_target_spec */");
496 # else /* !VERBOSE */
497 	printf("...");
498 # endif /* VERBOSE */
499 	printf("}) = %s\n", errstr);
500 
501 	#define FILL_DM_TARGET(id, id_next) \
502 		do { \
503 			init_dm_target_spec(&dm_arg_open3->target##id, id); \
504 			dm_arg_open3->target##id.next = \
505 				offsetof(struct dm_table_open_test, \
506 					 target##id_next) - \
507 				offsetof(struct dm_table_open_test, \
508 					 target##id); \
509 			strncpy(dm_arg_open3->param##id, str129 + id * 2, id); \
510 			dm_arg_open3->param##id[id] = '\0'; \
511 		} while (0)
512 	#define PRINT_DM_TARGET(id) \
513 		do { \
514 			print_dm_target_spec(&dm_arg_open3->target##id, id); \
515 			printf("\"%.*s\"}, ", id, str129 + id * 2); \
516 		} while (0)
517 
518 	/* max_strlen limit */
519 	init_s(&dm_arg_open3->ioc, offsetof(struct dm_table_open_test, target9),
520 	       offsetof(struct dm_table_open_test, target0));
521 	dm_arg_open3->ioc.data_size = sizeof(*dm_arg_open3);
522 	dm_arg_open3->ioc.target_count = 0xbadc0ded;
523 	FILL_DM_TARGET(0, 1);
524 	FILL_DM_TARGET(1, 2);
525 	FILL_DM_TARGET(2, 3);
526 	FILL_DM_TARGET(3, 4);
527 	FILL_DM_TARGET(4, 5);
528 	FILL_DM_TARGET(5, 6);
529 	FILL_DM_TARGET(6, 7);
530 	FILL_DM_TARGET(7, 8);
531 	FILL_DM_TARGET(8, 9);
532 	rc = ioctl(-1, DM_TABLE_LOAD, dm_arg_open3);
533 	errstr = sprintrc(rc);
534 	printf("ioctl(-1, DM_TABLE_LOAD, "
535 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
536 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
537 	       "target_count=3134983661, flags=0, ",
538 	       sizeof(*dm_arg_open3),
539 	       offsetof(struct dm_table_open_test, target0));
540 # if VERBOSE
541 	PRINT_DM_TARGET(0);
542 	PRINT_DM_TARGET(1);
543 	PRINT_DM_TARGET(2);
544 	PRINT_DM_TARGET(3);
545 	PRINT_DM_TARGET(4);
546 	PRINT_DM_TARGET(5);
547 	PRINT_DM_TARGET(6);
548 	PRINT_DM_TARGET(7);
549 	PRINT_DM_TARGET(8);
550 # endif /* VERBOSE */
551 	printf("...}) = %s\n", errstr);
552 
553 
554 	/* DM_TARGET_MSG */
555 	init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
556 	s.u.tm.target_msg.sector = 0x1234;
557 	strcpy(s.u.string + offsetof(struct dm_target_msg, message),
558 	       "long target msg");
559 	ioctl(-1, DM_TARGET_MSG, &s);
560 	printf("ioctl(-1, DM_TARGET_MSG, "
561 	       "{version=4.1.2, data_size=%u, data_start=%u, "
562 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, "
563 # if VERBOSE
564 	       "{sector=4660, message=\"long targ\"...}"
565 # else /* !VERBOSE */
566 	       "..."
567 # endif /* VERBOSE */
568 	       "}) = -1 EBADF (%m)\n",
569 	       s.ioc.data_size, s.ioc.data_start);
570 
571 	/* Invalid data_start */
572 	init_s(dm_arg, min_sizeof_dm_ioctl, min_sizeof_dm_ioctl);
573 	dm_arg->data_size = sizeof(*dm_arg);
574 	ioctl(-1, DM_TARGET_MSG, dm_arg);
575 	printf("ioctl(-1, DM_TARGET_MSG, "
576 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
577 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, "
578 # if VERBOSE
579 	       "??? /* misplaced struct dm_target_msg */"
580 # else /* !VERBOSE */
581 	       "..."
582 # endif /* VERBOSE */
583 	       "}) = -1 EBADF (%m)\n",
584 	       sizeof(*dm_arg), min_sizeof_dm_ioctl);
585 
586 	/* Invalid data_start */
587 	init_s(dm_arg, min_sizeof_dm_ioctl, 0xffffffff);
588 	dm_arg->data_size = sizeof(*dm_arg);
589 	ioctl(-1, DM_TARGET_MSG, dm_arg);
590 	printf("ioctl(-1, DM_TARGET_MSG, "
591 	       "{version=4.1.2, data_size=%zu, data_start=%u, "
592 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, "
593 # if VERBOSE
594 	       "??? /* misplaced struct dm_target_msg */"
595 # else /* !VERBOSE */
596 	       "..."
597 # endif /* VERBOSE */
598 	       "}) = -1 EBADF (%m)\n",
599 	       sizeof(*dm_arg), 0xffffffff);
600 
601 	/* Inaccessible pointer */
602 	init_s(dm_arg, min_sizeof_dm_ioctl, 0);
603 	dm_arg->data_size = sizeof(*dm_arg) + sizeof(struct dm_target_msg);
604 	dm_arg->data_start = sizeof(*dm_arg);
605 	ioctl(-1, DM_TARGET_MSG, dm_arg);
606 	printf("ioctl(-1, DM_TARGET_MSG, "
607 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
608 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, "
609 # if VERBOSE
610 	       "%p"
611 # else /* !VERBOSE */
612 	       "..."
613 # endif /* VERBOSE */
614 	       "}) = -1 EBADF (%m)\n",
615 	       sizeof(*dm_arg) + sizeof(struct dm_target_msg),
616 	       sizeof(*dm_arg)
617 # if VERBOSE
618 	       , (char *) dm_arg + sizeof(*dm_arg)
619 # endif /* VERBOSE */
620 	       );
621 
622 	/* Inaccessible string */
623 	init_s(&dm_arg_msg->ioc, sizeof(*dm_arg_msg),
624 	       offsetof(struct dm_target_msg_test, msg));
625 	dm_arg_msg->ioc.data_size = sizeof(*dm_arg_msg) + 1;
626 	dm_arg_msg->msg.sector = (__u64) 0xdeadbeeffacef157ULL;
627 	rc = ioctl(-1, DM_TARGET_MSG, dm_arg_msg);
628 	errstr = sprintrc(rc);
629 	printf("ioctl(-1, DM_TARGET_MSG, "
630 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
631 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, ",
632 	       sizeof(*dm_arg_msg) + 1,
633 	       offsetof(struct dm_target_msg_test, msg));
634 # if VERBOSE
635 	printf("{sector=%" PRI__u64 ", message=%p}",
636 	       (__u64) 0xdeadbeeffacef157ULL,
637 	       (char *) dm_arg_msg +
638 	       offsetof(struct dm_target_msg_test, msg.message));
639 # else /* !VERBOSE */
640 	printf("...");
641 # endif /* VERBOSE */
642 	printf("}) = %s\n", errstr);
643 
644 	/* Zero-sied string */
645 	init_s(&dm_arg_msg->ioc, sizeof(*dm_arg_msg),
646 	       offsetof(struct dm_target_msg_test, msg));
647 	dm_arg_msg->msg.sector = (__u64) 0xdeadbeeffacef157ULL;
648 	rc = ioctl(-1, DM_TARGET_MSG, dm_arg_msg);
649 	errstr = sprintrc(rc);
650 	printf("ioctl(-1, DM_TARGET_MSG, "
651 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
652 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, ",
653 	       sizeof(*dm_arg_msg), offsetof(struct dm_target_msg_test, msg));
654 # if VERBOSE
655 	printf("{sector=%" PRI__u64 ", message=\"\"}",
656 	       (__u64) 0xdeadbeeffacef157ULL);
657 # else /* !VERBOSE */
658 	printf("...");
659 # endif /* VERBOSE */
660 	printf("}) = %s\n", errstr);
661 
662 
663 	/* DM_DEV_SET_GEOMETRY */
664 	init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
665 	strcpy(s.u.string, "10 20 30 40");
666 	ioctl(-1, DM_DEV_SET_GEOMETRY, &s);
667 	printf("ioctl(-1, DM_DEV_SET_GEOMETRY, "
668 	       "{version=4.1.2, data_size=%u, data_start=%u, "
669 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, "
670 # if VERBOSE
671 	       "string=\"10 20 30 \"..."
672 # else /* !VERBOSE */
673 	       "..."
674 # endif /* VERBOSE */
675 	       "}) = -1 EBADF (%m)\n",
676 	       s.ioc.data_size, s.ioc.data_start);
677 
678 
679 	/* DM_DEV_RENAME */
680 	/* Inaccessible data */
681 	init_s(dm_arg, min_sizeof_dm_ioctl, min_sizeof_dm_ioctl);
682 	dm_arg->data_size = sizeof(*dm_arg);
683 	memcpy(unaligned_dm_arg, dm_arg, offsetof(struct dm_ioctl, data));
684 	ioctl(-1, DM_DEV_RENAME, unaligned_dm_arg);
685 	printf("ioctl(-1, DM_DEV_RENAME, "
686 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
687 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", event_nr=0, "
688 	       "flags=0, "
689 # if VERBOSE
690 	       "string=%p"
691 # else /* !VERBOSE */
692 	       "..."
693 # endif /* VERBOSE */
694 	       "}) = -1 EBADF (%m)\n",
695 	       sizeof(*unaligned_dm_arg), min_sizeof_dm_ioctl
696 # if VERBOSE
697 	       , (char *) unaligned_dm_arg + min_sizeof_dm_ioctl
698 # endif /* VERBOSE */
699 	       );
700 
701 	/* Incorrect data_start data */
702 	init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
703 	s.ioc.data_start = 0xdeadbeef;
704 	ioctl(-1, DM_DEV_RENAME, &s);
705 	printf("ioctl(-1, DM_DEV_RENAME, "
706 	       "{version=4.1.2, data_size=%u, data_start=3735928559, "
707 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", event_nr=0, "
708 	       "flags=0, "
709 # if VERBOSE
710 	       "??? /* misplaced string */"
711 # else /* !VERBOSE */
712 	       "..."
713 # endif /* VERBOSE */
714 	       "}) = -1 EBADF (%m)\n",
715 	       s.ioc.data_size);
716 
717 	/* Strange but still valid data_start */
718 	init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
719 	/* Curiously, this is a valid structure */
720 	s.ioc.data_start = offsetof(struct dm_ioctl, name) + 1;
721 	ioctl(-1, DM_DEV_RENAME, &s);
722 	printf("ioctl(-1, DM_DEV_RENAME, "
723 	       "{version=4.1.2, data_size=%u, data_start=%zu, "
724 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", event_nr=0, "
725 	       "flags=0, "
726 # if VERBOSE
727 	       "string=\"nn\""
728 # else /* !VERBOSE */
729 	       "..."
730 # endif /* VERBOSE */
731 	       "}) = -1 EBADF (%m)\n",
732 	       s.ioc.data_size,
733 	       offsetof(struct dm_ioctl, name) + 1);
734 
735 	/* Correct data */
736 	init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
737 	strcpy(s.u.string, "new long name");
738 	ioctl(-1, DM_DEV_RENAME, &s);
739 	printf("ioctl(-1, DM_DEV_RENAME, "
740 	       "{version=4.1.2, data_size=%u, data_start=%u, "
741 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", event_nr=0, "
742 	       "flags=0, "
743 # if VERBOSE
744 	       "string=\"new long \"..."
745 # else /* !VERBOSE */
746 	       "..."
747 # endif /* VERBOSE */
748 	       "}) = -1 EBADF (%m)\n",
749 	       s.ioc.data_size, s.ioc.data_start);
750 
751 
752 	/* DM_TABLE_LOAD */
753 	init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
754 	s.ioc.target_count = -1U;
755 	ioctl(-1, DM_TABLE_LOAD, &s);
756 	printf("ioctl(-1, DM_TABLE_LOAD, "
757 	       "{version=4.1.2, data_size=%u, data_start=%u, "
758 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
759 	       "target_count=4294967295, flags=0, "
760 # if VERBOSE
761 	       "{sector_start=0, length=0, target_type=\"\", string=\"\"}"
762 	       ", ??? /* misplaced struct dm_target_spec */"
763 # else
764 	       "..."
765 # endif /* VERBOSE */
766 	       "}) = -1 EBADF (%m)\n",
767 	       s.ioc.data_size, s.ioc.data_start);
768 
769 	puts("+++ exited with 0 +++");
770 	return 0;
771 }
772 
773 #else /* !HAVE_LINUX_DM_IOCTL_H */
774 
775 SKIP_MAIN_UNDEFINED("HAVE_LINUX_DM_IOCTL_H")
776 
777 #endif /* HAVE_LINUX_DM_IOCTL_H */
778