Home | History | Annotate | Download | only in tests-m32
      1 /*
      2  * Check decoding of DM_* commands of ioctl syscall.
      3  *
      4  * Copyright (c) 2016 Mikulas Patocka <mpatocka (at) redhat.com>
      5  * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr (at) 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
    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
    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
    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
    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