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