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