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
57static const char str129[] = STR32 STR32 STR32 STR32 "6";
58
59static const __u64 dts_sector_base = (__u64) 0xdeadca75facef157ULL;
60static const __u64 dts_sector_step = (__u64) 0x100000001ULL;
61static const __u64 dts_length_base = (__u64) 0xbadc0dedda7a1057ULL;
62static const __u64 dts_length_step = (__u64) 0x700000007ULL;
63static const __s32 dts_status_base = (__s32) 3141592653U;
64static const __s32 dts_status_step = 0x1234;
65
66static const size_t min_sizeof_dm_ioctl =
67	offsetof(struct dm_ioctl, data);
68
69static 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
84struct 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
108struct dm_target_msg_test {
109	struct dm_ioctl ioc;
110	struct dm_target_msg msg;
111};
112
113struct args {
114	unsigned int arg;
115	const char *str;
116	bool has_params;
117	bool has_event_nr;
118};
119
120
121static void
122init_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
135static void
136init_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
150static void
151print_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
162int
163main(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
775SKIP_MAIN_UNDEFINED("HAVE_LINUX_DM_IOCTL_H")
776
777#endif /* HAVE_LINUX_DM_IOCTL_H */
778