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