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