782 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			782 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Check decoding of DM_* commands of ioctl syscall.
 | |
|  *
 | |
|  * Copyright (c) 2016 Mikulas Patocka <mpatocka@redhat.com>
 | |
|  * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
 | |
|  * Copyright (c) 2016-2018 The strace developers.
 | |
|  * All rights reserved.
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without
 | |
|  * modification, are permitted provided that the following conditions
 | |
|  * are met:
 | |
|  * 1. Redistributions of source code must retain the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer.
 | |
|  * 2. Redistributions in binary form must reproduce the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer in the
 | |
|  *    documentation and/or other materials provided with the distribution.
 | |
|  * 3. The name of the author may not be used to endorse or promote products
 | |
|  *    derived from this software without specific prior written permission.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 | |
|  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | |
|  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | |
|  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | |
|  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | |
|  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
|  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
|  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | |
|  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| #include "tests.h"
 | |
| 
 | |
| #ifdef HAVE_LINUX_DM_IOCTL_H
 | |
| 
 | |
| # include <errno.h>
 | |
| # include <inttypes.h>
 | |
| # include <stdio.h>
 | |
| # include <stddef.h>
 | |
| # include <string.h>
 | |
| # include <sys/ioctl.h>
 | |
| # include <linux/ioctl.h>
 | |
| # include <linux/dm-ioctl.h>
 | |
| 
 | |
| # ifndef VERBOSE
 | |
| #  define VERBOSE 0
 | |
| # endif
 | |
| 
 | |
| # define STR32 "AbCdEfGhIjKlMnOpQrStUvWxYz012345"
 | |
| 
 | |
| # define ALIGNED_SIZE(s_, t_) \
 | |
| 	(((s_) + (ALIGNOF(t_) - 1UL)) & ~(ALIGNOF(t_) - 1UL))
 | |
| # define ALIGNED_OFFSET(t_, m_) \
 | |
| 	ALIGNED_SIZE(offsetof(t_, m_), t_)
 | |
| 
 | |
| #  ifndef DM_DEV_ARM_POLL
 | |
| #   define DM_DEV_ARM_POLL     _IOWR(DM_IOCTL, 0x10, struct dm_ioctl)
 | |
| #  endif
 | |
| 
 | |
| static const char str129[] = STR32 STR32 STR32 STR32 "6";
 | |
| 
 | |
| static const __u64 dts_sector_base = (__u64) 0xdeadca75facef157ULL;
 | |
| static const __u64 dts_sector_step = (__u64) 0x100000001ULL;
 | |
| static const __u64 dts_length_base = (__u64) 0xbadc0dedda7a1057ULL;
 | |
| static const __u64 dts_length_step = (__u64) 0x700000007ULL;
 | |
| static const __s32 dts_status_base = (__s32) 3141592653U;
 | |
| static const __s32 dts_status_step = 0x1234;
 | |
| 
 | |
| static const size_t min_sizeof_dm_ioctl =
 | |
| 	offsetof(struct dm_ioctl, data);
 | |
| 
 | |
| static struct s {
 | |
| 	struct dm_ioctl ioc;
 | |
| 	union {
 | |
| 		struct {
 | |
| 			struct dm_target_spec target_spec;
 | |
| 			char target_params[256];
 | |
| 		} ts;
 | |
| 		struct {
 | |
| 			struct dm_target_msg target_msg;
 | |
| 			char target_string[256];
 | |
| 		} tm;
 | |
| 		char string[256];
 | |
| 	} u;
 | |
| } s;
 | |
| 
 | |
| struct dm_table_open_test {
 | |
| 	struct dm_ioctl ioc;
 | |
| 	struct dm_target_spec target0;
 | |
| 	char param0[1];
 | |
| 	struct dm_target_spec target1;
 | |
| 	char param1[2];
 | |
| 	struct dm_target_spec target2;
 | |
| 	char param2[3];
 | |
| 	struct dm_target_spec target3;
 | |
| 	char param3[4];
 | |
| 	struct dm_target_spec target4;
 | |
| 	char param4[5];
 | |
| 	struct dm_target_spec target5;
 | |
| 	char param5[6];
 | |
| 	struct dm_target_spec target6;
 | |
| 	char param6[7];
 | |
| 	struct dm_target_spec target7;
 | |
| 	char param7[8];
 | |
| 	struct dm_target_spec target8;
 | |
| 	char param8[9];
 | |
| 	struct dm_target_spec target9;
 | |
| 	char param9[10];
 | |
| };
 | |
| 
 | |
| struct dm_target_msg_test {
 | |
| 	struct dm_ioctl ioc;
 | |
| 	struct dm_target_msg msg;
 | |
| };
 | |
| 
 | |
| struct args {
 | |
| 	unsigned int arg;
 | |
| 	const char *str;
 | |
| 	bool has_params;
 | |
| 	bool has_event_nr;
 | |
| };
 | |
| 
 | |
| 
 | |
| static void
 | |
| init_s(struct dm_ioctl *s, size_t size, size_t offs)
 | |
| {
 | |
| 	memset(s, 0, size);
 | |
| 	s->version[0] = DM_VERSION_MAJOR;
 | |
| 	s->version[1] = 1;
 | |
| 	s->version[2] = 2;
 | |
| 	s->data_size = size;
 | |
| 	s->data_start = offs;
 | |
| 	s->dev = 0x1234;
 | |
| 	strcpy(s->name, "nnn");
 | |
| 	strcpy(s->uuid, "uuu");
 | |
| }
 | |
| 
 | |
| static void
 | |
| init_dm_target_spec(struct dm_target_spec *ptr, uint32_t id)
 | |
| {
 | |
| 	ptr->sector_start = dts_sector_base + dts_sector_step * id;
 | |
| 	ptr->length       = dts_length_base + dts_length_step * id;
 | |
| 	ptr->status       = dts_status_base + dts_status_step * id;
 | |
| 
 | |
| 	memcpy(ptr->target_type, str129 +
 | |
| 		id % (sizeof(str129) - sizeof(ptr->target_type)),
 | |
| 		id % (sizeof(ptr->target_type) + 1));
 | |
| 	if (id % (sizeof(ptr->target_type) + 1) < sizeof(ptr->target_type))
 | |
| 		ptr->target_type[id % (sizeof(ptr->target_type) + 1)] = '\0';
 | |
| }
 | |
| 
 | |
| # if VERBOSE
 | |
| static void
 | |
| print_dm_target_spec(struct dm_target_spec *ptr, uint32_t id)
 | |
| {
 | |
| 	printf("{sector_start=%" PRI__u64 ", length=%" PRI__u64 ", "
 | |
| 	       "target_type=\"%.*s\", string=",
 | |
| 	       dts_sector_base + dts_sector_step * id,
 | |
| 	       dts_length_base + dts_length_step * id,
 | |
| 	       (int) (id % (sizeof(ptr->target_type) + 1)),
 | |
| 	       str129 + id % (sizeof(str129) - sizeof(ptr->target_type)));
 | |
| }
 | |
| # endif /* VERBOSE */
 | |
| 
 | |
| int
 | |
| main(void)
 | |
| {
 | |
| 	static kernel_ulong_t dummy_dm_ioctl1 =
 | |
| 		_IOC(_IOC_READ, DM_IOCTL, 0, 0x1fff);
 | |
| 	static kernel_ulong_t dummy_dm_ioctl2 =
 | |
| 		_IOC(_IOC_READ|_IOC_WRITE, DM_IOCTL, 0xed, 0);
 | |
| 	static kernel_ulong_t dummy_dm_arg =
 | |
| 		(kernel_ulong_t) 0xbadc0dedda7a1057ULL;
 | |
| 	/* We can't check these properly for now */
 | |
| 	static struct args dummy_check_cmds_nodev[] = {
 | |
| 		{ ARG_STR(DM_REMOVE_ALL),    false },
 | |
| 		{ ARG_STR(DM_LIST_DEVICES),  true  },
 | |
| 		{ ARG_STR(DM_LIST_VERSIONS), true  },
 | |
| 	};
 | |
| 	static struct args dummy_check_cmds[] = {
 | |
| 		{ ARG_STR(DM_DEV_CREATE),    false },
 | |
| 		{ ARG_STR(DM_DEV_REMOVE),    false, true },
 | |
| 		{ ARG_STR(DM_DEV_STATUS),    false },
 | |
| 		{ ARG_STR(DM_DEV_WAIT),      true,  true },
 | |
| 		{ ARG_STR(DM_TABLE_CLEAR),   false },
 | |
| 		{ ARG_STR(DM_TABLE_DEPS),    true  },
 | |
| 		{ ARG_STR(DM_TABLE_STATUS),  true  },
 | |
| 		{ ARG_STR(DM_DEV_ARM_POLL),  false },
 | |
| 	};
 | |
| 
 | |
| 	struct dm_ioctl *unaligned_dm_arg =
 | |
| 		tail_alloc(offsetof(struct dm_ioctl, data));
 | |
| 	struct dm_ioctl *dm_arg =
 | |
| 		tail_alloc(ALIGNED_OFFSET(struct dm_ioctl, data));
 | |
| 	struct dm_table_open_test *dm_arg_open1 =
 | |
| 		tail_alloc(ALIGNED_OFFSET(struct dm_table_open_test, target1));
 | |
| 	struct dm_table_open_test *dm_arg_open2 =
 | |
| 		tail_alloc(ALIGNED_OFFSET(struct dm_table_open_test, param1));
 | |
| 	struct dm_table_open_test *dm_arg_open3 =
 | |
| 		tail_alloc(ALIGNED_OFFSET(struct dm_table_open_test, target9));
 | |
| 	struct dm_target_msg_test *dm_arg_msg =
 | |
| 		tail_alloc(sizeof(*dm_arg_msg));
 | |
| 
 | |
| 	long rc;
 | |
| 	const char *errstr;
 | |
| 	unsigned int i;
 | |
| 
 | |
| 
 | |
| 	/* Incorrect operation */
 | |
| 	ioctl(-1, _IOW(DM_IOCTL, 0xde, int), dm_arg);
 | |
| 	printf("ioctl(-1, _IOC(_IOC_WRITE, %#x, 0xde, %#zx), %p) = "
 | |
| 	       "-1 EBADF (%m)\n",
 | |
| 	       DM_IOCTL, sizeof(int), dm_arg);
 | |
| 
 | |
| 	ioctl(-1, dummy_dm_ioctl1, 0);
 | |
| 	printf("ioctl(-1, _IOC(_IOC_READ, %#x, 0, %#x), 0) = -1 EBADF (%m)\n",
 | |
| 	       DM_IOCTL, (unsigned int) _IOC_SIZE(dummy_dm_ioctl1));
 | |
| 
 | |
| 	ioctl(-1, dummy_dm_ioctl2, dummy_dm_arg);
 | |
| 	printf("ioctl(-1, _IOC(_IOC_READ|_IOC_WRITE, %#x, %#x, 0), %#lx) = "
 | |
| 	       "-1 EBADF (%m)\n",
 | |
| 	       DM_IOCTL, (unsigned int) _IOC_NR(dummy_dm_ioctl2),
 | |
| 	       (unsigned long) dummy_dm_arg);
 | |
| 
 | |
| 
 | |
| 	/* DM_VERSION */
 | |
| 	/* Incorrect pointer */
 | |
| 	ioctl(-1, DM_VERSION, dm_arg + 1);
 | |
| 	printf("ioctl(-1, DM_VERSION, %p) = -1 EBADF (%m)\n", dm_arg + 1);
 | |
| 
 | |
| 	/* Incorrect data_size */
 | |
| 	init_s(dm_arg, 0, 0);
 | |
| 	ioctl(-1, DM_VERSION, &s);
 | |
| 	printf("ioctl(-1, DM_VERSION, %p) = -1 EBADF (%m)\n", &s);
 | |
| 
 | |
| 	/* Incorrect version */
 | |
| 	init_s(dm_arg, min_sizeof_dm_ioctl, 0);
 | |
| 	dm_arg->version[0] = 0xbadc0ded;
 | |
| 	dm_arg->version[1] = 0xbadc0dee;
 | |
| 	dm_arg->version[2] = 0xbadc0def;
 | |
| 	ioctl(-1, DM_VERSION, dm_arg);
 | |
| 	printf("ioctl(-1, DM_VERSION, {version=%u.%u.%u"
 | |
| 	       " /* unsupported device mapper ABI version */}) = "
 | |
| 	       "-1 EBADF (%m)\n", 0xbadc0ded, 0xbadc0dee, 0xbadc0def);
 | |
| 
 | |
| 	/* Incorrect data_size */
 | |
| 	init_s(dm_arg, 14, 64);
 | |
| 	ioctl(-1, DM_VERSION, dm_arg);
 | |
| 	printf("ioctl(-1, DM_VERSION, {version=4.1.2, data_size=14"
 | |
| 	       " /* data_size too small */}) = -1 EBADF (%m)\n");
 | |
| 
 | |
| 	/* Unterminated name/uuid */
 | |
| 	init_s(dm_arg, min_sizeof_dm_ioctl, 0);
 | |
| 	memcpy(dm_arg->name, str129, sizeof(dm_arg->name));
 | |
| 	memcpy(dm_arg->uuid, str129, sizeof(dm_arg->uuid));
 | |
| 	ioctl(-1, DM_VERSION, dm_arg);
 | |
| 	printf("ioctl(-1, DM_VERSION, {version=4.1.2, data_size=%zu, "
 | |
| 	       "dev=makedev(18, 52), name=\"%.127s\"..., uuid=\"%.128s\"..., "
 | |
| 	       "flags=0}) = -1 EBADF (%m)\n",
 | |
| 	       min_sizeof_dm_ioctl, str129, str129);
 | |
| 
 | |
| 	/* Normal call */
 | |
| 	init_s(dm_arg, min_sizeof_dm_ioctl, 0);
 | |
| 	ioctl(-1, DM_VERSION, dm_arg);
 | |
| 	printf("ioctl(-1, DM_VERSION, "
 | |
| 	       "{version=4.1.2, data_size=%zu, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0}) = "
 | |
| 	       "-1 EBADF (%m)\n", min_sizeof_dm_ioctl);
 | |
| 
 | |
| 	/* Zero dev, name, uuid */
 | |
| 	init_s(dm_arg, min_sizeof_dm_ioctl, 0);
 | |
| 	dm_arg->data_size = 0xfacefeed;
 | |
| 	dm_arg->dev = 0;
 | |
| 	dm_arg->name[0] = '\0';
 | |
| 	dm_arg->uuid[0] = '\0';
 | |
| 	ioctl(-1, DM_VERSION, dm_arg);
 | |
| 	printf("ioctl(-1, DM_VERSION, "
 | |
| 	       "{version=4.1.2, data_size=%u, flags=0}) = "
 | |
| 	       "-1 EBADF (%m)\n", 0xfacefeed);
 | |
| 
 | |
| 	/* Flag */
 | |
| 	init_s(dm_arg, min_sizeof_dm_ioctl, 0);
 | |
| 	dm_arg->flags = 0xffffffff;
 | |
| 	ioctl(-1, DM_VERSION, dm_arg);
 | |
| 	printf("ioctl(-1, DM_VERSION, "
 | |
| 	       "{version=4.1.2, data_size=%zu, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags="
 | |
| 	       "DM_READONLY_FLAG|DM_SUSPEND_FLAG|DM_EXISTS_FLAG|"
 | |
| 	       "DM_PERSISTENT_DEV_FLAG|DM_STATUS_TABLE_FLAG|"
 | |
| 	       "DM_ACTIVE_PRESENT_FLAG|DM_INACTIVE_PRESENT_FLAG|"
 | |
| 	       "DM_BUFFER_FULL_FLAG|DM_SKIP_BDGET_FLAG|DM_SKIP_LOCKFS_FLAG|"
 | |
| 	       "DM_NOFLUSH_FLAG|DM_QUERY_INACTIVE_TABLE_FLAG|"
 | |
| 	       "DM_UEVENT_GENERATED_FLAG|DM_UUID_FLAG|DM_SECURE_DATA_FLAG|"
 | |
| 	       "DM_DATA_OUT_FLAG|DM_DEFERRED_REMOVE|DM_INTERNAL_SUSPEND_FLAG|"
 | |
| 	       "0xfff80080}) = -1 EBADF (%m)\n",
 | |
| 	       min_sizeof_dm_ioctl);
 | |
| 
 | |
| 	/* Normal call */
 | |
| 	init_s(&s.ioc, sizeof(s.ioc), 0);
 | |
| 	ioctl(-1, DM_VERSION, &s);
 | |
| 	printf("ioctl(-1, DM_VERSION, "
 | |
| 	       "{version=4.1.2, data_size=%zu, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0}) = "
 | |
| 	       "-1 EBADF (%m)\n", sizeof(s.ioc));
 | |
| 
 | |
| 
 | |
| 	/* DM_REMOVE_ALL */
 | |
| 	/* DM_LIST_DEVICES */
 | |
| 	/* DM_LIST_VERSIONS */
 | |
| 	for (i = 0; i < ARRAY_SIZE(dummy_check_cmds_nodev); i++) {
 | |
| 		init_s(dm_arg, min_sizeof_dm_ioctl, 0);
 | |
| 		ioctl(-1, dummy_check_cmds_nodev[i].arg, dm_arg);
 | |
| 		printf("ioctl(-1, %s, {version=4.1.2, data_size=%zu%s, "
 | |
| 		       "flags=0}) = -1 EBADF (%m)\n",
 | |
| 		       dummy_check_cmds_nodev[i].str,
 | |
| 		       min_sizeof_dm_ioctl,
 | |
| 		       dummy_check_cmds_nodev[i].has_params ?
 | |
| 		       ", data_start=0" : "");
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	/* DM_DEV_CREATE */
 | |
| 	/* DM_DEV_REMOVE */
 | |
| 	/* DM_DEV_STATUS */
 | |
| 	/* DM_DEV_WAIT */
 | |
| 	/* DM_TABLE_CLEAR */
 | |
| 	/* DM_TABLE_DEPS */
 | |
| 	/* DM_TABLE_STATUS */
 | |
| 	for (i = 0; i < ARRAY_SIZE(dummy_check_cmds); i++) {
 | |
| 		init_s(dm_arg, min_sizeof_dm_ioctl, 0);
 | |
| 		ioctl(-1, dummy_check_cmds[i].arg, dm_arg);
 | |
| 		printf("ioctl(-1, %s, {version=4.1.2, data_size=%zu%s, "
 | |
| 		       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\"%s, "
 | |
| 		       "flags=0}) = -1 EBADF (%m)\n",
 | |
| 		       dummy_check_cmds[i].str, min_sizeof_dm_ioctl,
 | |
| 		       dummy_check_cmds[i].has_params ? ", data_start=0" : "",
 | |
| 		       dummy_check_cmds[i].has_event_nr ? ", event_nr=0" : "");
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	/* DM_DEV_SUSPEND */
 | |
| 	init_s(&s.ioc, sizeof(s.ioc), 0);
 | |
| 	s.ioc.flags = DM_SUSPEND_FLAG;
 | |
| 	s.ioc.event_nr = 0xbadc0ded;
 | |
| 	ioctl(-1, DM_DEV_SUSPEND, &s);
 | |
| 	printf("ioctl(-1, DM_DEV_SUSPEND, "
 | |
| 	       "{version=4.1.2, data_size=%zu, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
 | |
| 	       "flags=DM_SUSPEND_FLAG}) = -1 EBADF (%m)\n", sizeof(s.ioc));
 | |
| 
 | |
| 	init_s(&s.ioc, sizeof(s.ioc), 0);
 | |
| 	s.ioc.event_nr = 0xbadc0ded;
 | |
| 	ioctl(-1, DM_DEV_SUSPEND, &s);
 | |
| 	printf("ioctl(-1, DM_DEV_SUSPEND, "
 | |
| 	       "{version=4.1.2, data_size=%zu, dev=makedev(18, 52), "
 | |
| 	       "name=\"nnn\", uuid=\"uuu\", event_nr=3134983661, "
 | |
| 	       "flags=0}) = -1 EBADF (%m)\n", sizeof(s.ioc));
 | |
| 
 | |
| 
 | |
| 	/* DM_TABLE_LOAD */
 | |
| 	init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
 | |
| 	s.ioc.target_count = 1;
 | |
| 	s.u.ts.target_spec.sector_start = 0x10;
 | |
| 	s.u.ts.target_spec.length = 0x20;
 | |
| 	s.u.ts.target_spec.next =
 | |
| 		sizeof(s.u.ts.target_spec) + sizeof(s.u.ts.target_params);
 | |
| 	strcpy(s.u.ts.target_spec.target_type, "tgt");
 | |
| 	strcpy(s.u.ts.target_params, "tparams");
 | |
| 	ioctl(-1, DM_TABLE_LOAD, &s);
 | |
| 	printf("ioctl(-1, DM_TABLE_LOAD, "
 | |
| 	       "{version=4.1.2, data_size=%u, data_start=%u, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
 | |
| 	       "target_count=1, flags=0, "
 | |
| # if VERBOSE
 | |
| 	       "{sector_start=16, length=32, target_type=\"tgt\", "
 | |
| 	       "string=\"tparams\"}"
 | |
| # else /* !VERBOSE */
 | |
| 	       "..."
 | |
| # endif /* VERBOSE */
 | |
| 	       "}) = -1 EBADF (%m)\n", s.ioc.data_size, s.ioc.data_start);
 | |
| 
 | |
| 	/* No targets */
 | |
| 	init_s(dm_arg, min_sizeof_dm_ioctl, min_sizeof_dm_ioctl);
 | |
| 	dm_arg->data_size = sizeof(*dm_arg);
 | |
| 	dm_arg->target_count = 0;
 | |
| 	ioctl(-1, DM_TABLE_LOAD, dm_arg);
 | |
| 	printf("ioctl(-1, DM_TABLE_LOAD, "
 | |
| 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
 | |
| 	       "target_count=0, flags=0}) = -1 EBADF (%m)\n",
 | |
| 	       sizeof(*dm_arg), min_sizeof_dm_ioctl);
 | |
| 
 | |
| 	/* Invalid data_start */
 | |
| 	init_s(dm_arg, min_sizeof_dm_ioctl, 0xfffffff8);
 | |
| 	dm_arg->data_size = sizeof(*dm_arg);
 | |
| 	dm_arg->target_count = 1234;
 | |
| 	ioctl(-1, DM_TABLE_LOAD, dm_arg);
 | |
| 	printf("ioctl(-1, DM_TABLE_LOAD, "
 | |
| 	       "{version=4.1.2, data_size=%zu, data_start=%u, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
 | |
| 	       "target_count=1234, flags=0, "
 | |
| # if VERBOSE
 | |
| 	       "??? /* misplaced struct dm_target_spec */"
 | |
| # else
 | |
| 	       "..."
 | |
| # endif /* VERBOSE */
 | |
| 	       "}) = -1 EBADF (%m)\n", sizeof(*dm_arg), 0xfffffff8);
 | |
| 
 | |
| 	/* Inaccessible pointer */
 | |
| 	init_s(&dm_arg_open1->ioc, offsetof(struct dm_table_open_test, target1),
 | |
| 	       offsetof(struct dm_table_open_test, target1));
 | |
| 	dm_arg_open1->ioc.data_size = sizeof(*dm_arg_open1);
 | |
| 	dm_arg_open1->ioc.target_count = 0xdeaddea1;
 | |
| 	ioctl(-1, DM_TABLE_LOAD, dm_arg_open1);
 | |
| 	printf("ioctl(-1, DM_TABLE_LOAD, "
 | |
| 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
 | |
| 	       "target_count=3735936673, flags=0, "
 | |
| # if VERBOSE
 | |
| 	       "%p"
 | |
| # else /* !VERBOSE */
 | |
| 	       "..."
 | |
| # endif /* VERBOSE */
 | |
| 	       "}) = -1 EBADF (%m)\n", sizeof(*dm_arg_open1),
 | |
| 	       offsetof(struct dm_table_open_test, target1)
 | |
| # if VERBOSE
 | |
| 	       , (char *) dm_arg_open1 +
 | |
| 	       offsetof(struct dm_table_open_test, target1)
 | |
| # endif /* VERBOSE */
 | |
| 	       );
 | |
| 
 | |
| 	/* Inaccessible string */
 | |
| 	init_s(&dm_arg_open2->ioc, offsetof(struct dm_table_open_test, param1),
 | |
| 	       offsetof(struct dm_table_open_test, target1));
 | |
| 	dm_arg_open2->ioc.data_size = sizeof(*dm_arg_open2);
 | |
| 	dm_arg_open2->ioc.target_count = 2;
 | |
| 	init_dm_target_spec(&dm_arg_open2->target1, 7);
 | |
| 	dm_arg_open2->target1.next =
 | |
| 		offsetof(struct dm_table_open_test, target3) -
 | |
| 		offsetof(struct dm_table_open_test, target1);
 | |
| 	rc = ioctl(-1, DM_TABLE_LOAD, dm_arg_open2);
 | |
| 	errstr = sprintrc(rc);
 | |
| 	printf("ioctl(-1, DM_TABLE_LOAD, "
 | |
| 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
 | |
| 	       "target_count=2, flags=0, ",
 | |
| 	       sizeof(*dm_arg_open2),
 | |
| 	       offsetof(struct dm_table_open_test, target1));
 | |
| # if VERBOSE
 | |
| 	print_dm_target_spec(&dm_arg_open2->target1, 7);
 | |
| 	printf("%p}, %p",
 | |
| 	       (char *) dm_arg_open2 +
 | |
| 	       offsetof(struct dm_table_open_test, param1),
 | |
| 	       (char *) dm_arg_open2 +
 | |
| 	       offsetof(struct dm_table_open_test, target3));
 | |
| # else /* !VERBOSE */
 | |
| 	printf("...");
 | |
| # endif /* VERBOSE */
 | |
| 	printf("}) = %s\n", errstr);
 | |
| 
 | |
| 	/* Incorrect next */
 | |
| 	init_s(&dm_arg_open3->ioc, offsetof(struct dm_table_open_test, target5),
 | |
| 	       offsetof(struct dm_table_open_test, target0));
 | |
| 	dm_arg_open3->ioc.target_count = 4;
 | |
| 
 | |
| 	init_dm_target_spec(&dm_arg_open3->target0, 9);
 | |
| 	dm_arg_open3->target0.next =
 | |
| 		offsetof(struct dm_table_open_test, target1) -
 | |
| 		offsetof(struct dm_table_open_test, target0);
 | |
| 	dm_arg_open3->param0[0] = '\0';
 | |
| 
 | |
| 	init_dm_target_spec(&dm_arg_open3->target1, 15);
 | |
| 	dm_arg_open3->target1.next =
 | |
| 		offsetof(struct dm_table_open_test, target3) -
 | |
| 		offsetof(struct dm_table_open_test, target1);
 | |
| 	dm_arg_open3->param1[0] = '\377';
 | |
| 	dm_arg_open3->param1[1] = '\0';
 | |
| 
 | |
| 	init_dm_target_spec(&dm_arg_open3->target3, 42);
 | |
| 	dm_arg_open3->target3.next = 0xdeadbeef;
 | |
| 	dm_arg_open3->param3[0] = '\1';
 | |
| 	dm_arg_open3->param3[1] = '\2';
 | |
| 	dm_arg_open3->param3[2] = '\0';
 | |
| 
 | |
| 	rc = ioctl(-1, DM_TABLE_LOAD, dm_arg_open3);
 | |
| 	errstr = sprintrc(rc);
 | |
| 	printf("ioctl(-1, DM_TABLE_LOAD, "
 | |
| 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
 | |
| 	       "target_count=4, flags=0, ",
 | |
| 	       offsetof(struct dm_table_open_test, target5),
 | |
| 	       offsetof(struct dm_table_open_test, target0));
 | |
| # if VERBOSE
 | |
| 	print_dm_target_spec(&dm_arg_open3->target0, 9);
 | |
| 	printf("\"\"}, ");
 | |
| 	print_dm_target_spec(&dm_arg_open3->target1, 15);
 | |
| 	printf("\"\\377\"}, ");
 | |
| 	print_dm_target_spec(&dm_arg_open3->target1, 42);
 | |
| 	printf("\"\\1\\2\"}, ??? /* misplaced struct dm_target_spec */");
 | |
| # else /* !VERBOSE */
 | |
| 	printf("...");
 | |
| # endif /* VERBOSE */
 | |
| 	printf("}) = %s\n", errstr);
 | |
| 
 | |
| 	#define FILL_DM_TARGET(id, id_next) \
 | |
| 		do { \
 | |
| 			init_dm_target_spec(&dm_arg_open3->target##id, id); \
 | |
| 			dm_arg_open3->target##id.next = \
 | |
| 				offsetof(struct dm_table_open_test, \
 | |
| 					 target##id_next) - \
 | |
| 				offsetof(struct dm_table_open_test, \
 | |
| 					 target##id); \
 | |
| 			memcpy(dm_arg_open3->param##id, str129 + id * 2, id); \
 | |
| 			dm_arg_open3->param##id[id] = '\0'; \
 | |
| 		} while (0)
 | |
| 	#define PRINT_DM_TARGET(id) \
 | |
| 		do { \
 | |
| 			print_dm_target_spec(&dm_arg_open3->target##id, id); \
 | |
| 			printf("\"%.*s\"}, ", id, str129 + id * 2); \
 | |
| 		} while (0)
 | |
| 
 | |
| 	/* max_strlen limit */
 | |
| 	init_s(&dm_arg_open3->ioc, offsetof(struct dm_table_open_test, target9),
 | |
| 	       offsetof(struct dm_table_open_test, target0));
 | |
| 	dm_arg_open3->ioc.data_size = sizeof(*dm_arg_open3);
 | |
| 	dm_arg_open3->ioc.target_count = 0xbadc0ded;
 | |
| 	FILL_DM_TARGET(0, 1);
 | |
| 	FILL_DM_TARGET(1, 2);
 | |
| 	FILL_DM_TARGET(2, 3);
 | |
| 	FILL_DM_TARGET(3, 4);
 | |
| 	FILL_DM_TARGET(4, 5);
 | |
| 	FILL_DM_TARGET(5, 6);
 | |
| 	FILL_DM_TARGET(6, 7);
 | |
| 	FILL_DM_TARGET(7, 8);
 | |
| 	FILL_DM_TARGET(8, 9);
 | |
| 	rc = ioctl(-1, DM_TABLE_LOAD, dm_arg_open3);
 | |
| 	errstr = sprintrc(rc);
 | |
| 	printf("ioctl(-1, DM_TABLE_LOAD, "
 | |
| 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
 | |
| 	       "target_count=3134983661, flags=0, ",
 | |
| 	       sizeof(*dm_arg_open3),
 | |
| 	       offsetof(struct dm_table_open_test, target0));
 | |
| # if VERBOSE
 | |
| 	PRINT_DM_TARGET(0);
 | |
| 	PRINT_DM_TARGET(1);
 | |
| 	PRINT_DM_TARGET(2);
 | |
| 	PRINT_DM_TARGET(3);
 | |
| 	PRINT_DM_TARGET(4);
 | |
| 	PRINT_DM_TARGET(5);
 | |
| 	PRINT_DM_TARGET(6);
 | |
| 	PRINT_DM_TARGET(7);
 | |
| 	PRINT_DM_TARGET(8);
 | |
| # endif /* VERBOSE */
 | |
| 	printf("...}) = %s\n", errstr);
 | |
| 
 | |
| 
 | |
| 	/* DM_TARGET_MSG */
 | |
| 	init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
 | |
| 	s.u.tm.target_msg.sector = 0x1234;
 | |
| 	strcpy(s.u.string + offsetof(struct dm_target_msg, message),
 | |
| 	       "long target msg");
 | |
| 	ioctl(-1, DM_TARGET_MSG, &s);
 | |
| 	printf("ioctl(-1, DM_TARGET_MSG, "
 | |
| 	       "{version=4.1.2, data_size=%u, data_start=%u, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, "
 | |
| # if VERBOSE
 | |
| 	       "{sector=4660, message=\"long targ\"...}"
 | |
| # else /* !VERBOSE */
 | |
| 	       "..."
 | |
| # endif /* VERBOSE */
 | |
| 	       "}) = -1 EBADF (%m)\n",
 | |
| 	       s.ioc.data_size, s.ioc.data_start);
 | |
| 
 | |
| 	/* Invalid data_start */
 | |
| 	init_s(dm_arg, min_sizeof_dm_ioctl, min_sizeof_dm_ioctl);
 | |
| 	dm_arg->data_size = sizeof(*dm_arg);
 | |
| 	ioctl(-1, DM_TARGET_MSG, dm_arg);
 | |
| 	printf("ioctl(-1, DM_TARGET_MSG, "
 | |
| 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, "
 | |
| # if VERBOSE
 | |
| 	       "??? /* misplaced struct dm_target_msg */"
 | |
| # else /* !VERBOSE */
 | |
| 	       "..."
 | |
| # endif /* VERBOSE */
 | |
| 	       "}) = -1 EBADF (%m)\n",
 | |
| 	       sizeof(*dm_arg), min_sizeof_dm_ioctl);
 | |
| 
 | |
| 	/* Invalid data_start */
 | |
| 	init_s(dm_arg, min_sizeof_dm_ioctl, 0xffffffff);
 | |
| 	dm_arg->data_size = sizeof(*dm_arg);
 | |
| 	ioctl(-1, DM_TARGET_MSG, dm_arg);
 | |
| 	printf("ioctl(-1, DM_TARGET_MSG, "
 | |
| 	       "{version=4.1.2, data_size=%zu, data_start=%u, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, "
 | |
| # if VERBOSE
 | |
| 	       "??? /* misplaced struct dm_target_msg */"
 | |
| # else /* !VERBOSE */
 | |
| 	       "..."
 | |
| # endif /* VERBOSE */
 | |
| 	       "}) = -1 EBADF (%m)\n",
 | |
| 	       sizeof(*dm_arg), 0xffffffff);
 | |
| 
 | |
| 	/* Inaccessible pointer */
 | |
| 	init_s(dm_arg, min_sizeof_dm_ioctl, 0);
 | |
| 	dm_arg->data_size = sizeof(*dm_arg) + sizeof(struct dm_target_msg);
 | |
| 	dm_arg->data_start = sizeof(*dm_arg);
 | |
| 	ioctl(-1, DM_TARGET_MSG, dm_arg);
 | |
| 	printf("ioctl(-1, DM_TARGET_MSG, "
 | |
| 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, "
 | |
| # if VERBOSE
 | |
| 	       "%p"
 | |
| # else /* !VERBOSE */
 | |
| 	       "..."
 | |
| # endif /* VERBOSE */
 | |
| 	       "}) = -1 EBADF (%m)\n",
 | |
| 	       sizeof(*dm_arg) + sizeof(struct dm_target_msg),
 | |
| 	       sizeof(*dm_arg)
 | |
| # if VERBOSE
 | |
| 	       , (char *) dm_arg + sizeof(*dm_arg)
 | |
| # endif /* VERBOSE */
 | |
| 	       );
 | |
| 
 | |
| 	/* Inaccessible string */
 | |
| 	init_s(&dm_arg_msg->ioc, sizeof(*dm_arg_msg),
 | |
| 	       offsetof(struct dm_target_msg_test, msg));
 | |
| 	dm_arg_msg->ioc.data_size = sizeof(*dm_arg_msg) + 1;
 | |
| 	dm_arg_msg->msg.sector = (__u64) 0xdeadbeeffacef157ULL;
 | |
| 	rc = ioctl(-1, DM_TARGET_MSG, dm_arg_msg);
 | |
| 	errstr = sprintrc(rc);
 | |
| 	printf("ioctl(-1, DM_TARGET_MSG, "
 | |
| 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, ",
 | |
| 	       sizeof(*dm_arg_msg) + 1,
 | |
| 	       offsetof(struct dm_target_msg_test, msg));
 | |
| # if VERBOSE
 | |
| 	printf("{sector=%" PRI__u64 ", message=%p}",
 | |
| 	       (__u64) 0xdeadbeeffacef157ULL,
 | |
| 	       (char *) dm_arg_msg +
 | |
| 	       offsetof(struct dm_target_msg_test, msg.message));
 | |
| # else /* !VERBOSE */
 | |
| 	printf("...");
 | |
| # endif /* VERBOSE */
 | |
| 	printf("}) = %s\n", errstr);
 | |
| 
 | |
| 	/* Zero-sied string */
 | |
| 	init_s(&dm_arg_msg->ioc, sizeof(*dm_arg_msg),
 | |
| 	       offsetof(struct dm_target_msg_test, msg));
 | |
| 	dm_arg_msg->msg.sector = (__u64) 0xdeadbeeffacef157ULL;
 | |
| 	rc = ioctl(-1, DM_TARGET_MSG, dm_arg_msg);
 | |
| 	errstr = sprintrc(rc);
 | |
| 	printf("ioctl(-1, DM_TARGET_MSG, "
 | |
| 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, ",
 | |
| 	       sizeof(*dm_arg_msg), offsetof(struct dm_target_msg_test, msg));
 | |
| # if VERBOSE
 | |
| 	printf("{sector=%" PRI__u64 ", message=\"\"}",
 | |
| 	       (__u64) 0xdeadbeeffacef157ULL);
 | |
| # else /* !VERBOSE */
 | |
| 	printf("...");
 | |
| # endif /* VERBOSE */
 | |
| 	printf("}) = %s\n", errstr);
 | |
| 
 | |
| 
 | |
| 	/* DM_DEV_SET_GEOMETRY */
 | |
| 	init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
 | |
| 	strcpy(s.u.string, "10 20 30 40");
 | |
| 	ioctl(-1, DM_DEV_SET_GEOMETRY, &s);
 | |
| 	printf("ioctl(-1, DM_DEV_SET_GEOMETRY, "
 | |
| 	       "{version=4.1.2, data_size=%u, data_start=%u, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", flags=0, "
 | |
| # if VERBOSE
 | |
| 	       "string=\"10 20 30 \"..."
 | |
| # else /* !VERBOSE */
 | |
| 	       "..."
 | |
| # endif /* VERBOSE */
 | |
| 	       "}) = -1 EBADF (%m)\n",
 | |
| 	       s.ioc.data_size, s.ioc.data_start);
 | |
| 
 | |
| 
 | |
| 	/* DM_DEV_RENAME */
 | |
| 	/* Inaccessible data */
 | |
| 	init_s(dm_arg, min_sizeof_dm_ioctl, min_sizeof_dm_ioctl);
 | |
| 	dm_arg->data_size = sizeof(*dm_arg);
 | |
| 	memcpy(unaligned_dm_arg, dm_arg, offsetof(struct dm_ioctl, data));
 | |
| 	ioctl(-1, DM_DEV_RENAME, unaligned_dm_arg);
 | |
| 	printf("ioctl(-1, DM_DEV_RENAME, "
 | |
| 	       "{version=4.1.2, data_size=%zu, data_start=%zu, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", event_nr=0, "
 | |
| 	       "flags=0, "
 | |
| # if VERBOSE
 | |
| 	       "string=%p"
 | |
| # else /* !VERBOSE */
 | |
| 	       "..."
 | |
| # endif /* VERBOSE */
 | |
| 	       "}) = -1 EBADF (%m)\n",
 | |
| 	       sizeof(*unaligned_dm_arg), min_sizeof_dm_ioctl
 | |
| # if VERBOSE
 | |
| 	       , (char *) unaligned_dm_arg + min_sizeof_dm_ioctl
 | |
| # endif /* VERBOSE */
 | |
| 	       );
 | |
| 
 | |
| 	/* Incorrect data_start data */
 | |
| 	init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
 | |
| 	s.ioc.data_start = 0xdeadbeef;
 | |
| 	ioctl(-1, DM_DEV_RENAME, &s);
 | |
| 	printf("ioctl(-1, DM_DEV_RENAME, "
 | |
| 	       "{version=4.1.2, data_size=%u, data_start=3735928559, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", event_nr=0, "
 | |
| 	       "flags=0, "
 | |
| # if VERBOSE
 | |
| 	       "??? /* misplaced string */"
 | |
| # else /* !VERBOSE */
 | |
| 	       "..."
 | |
| # endif /* VERBOSE */
 | |
| 	       "}) = -1 EBADF (%m)\n",
 | |
| 	       s.ioc.data_size);
 | |
| 
 | |
| 	/* Strange but still valid data_start */
 | |
| 	init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
 | |
| 	/* Curiously, this is a valid structure */
 | |
| 	s.ioc.data_start = offsetof(struct dm_ioctl, name) + 1;
 | |
| 	ioctl(-1, DM_DEV_RENAME, &s);
 | |
| 	printf("ioctl(-1, DM_DEV_RENAME, "
 | |
| 	       "{version=4.1.2, data_size=%u, data_start=%zu, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", event_nr=0, "
 | |
| 	       "flags=0, "
 | |
| # if VERBOSE
 | |
| 	       "string=\"nn\""
 | |
| # else /* !VERBOSE */
 | |
| 	       "..."
 | |
| # endif /* VERBOSE */
 | |
| 	       "}) = -1 EBADF (%m)\n",
 | |
| 	       s.ioc.data_size,
 | |
| 	       offsetof(struct dm_ioctl, name) + 1);
 | |
| 
 | |
| 	/* Correct data */
 | |
| 	init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
 | |
| 	strcpy(s.u.string, "new long name");
 | |
| 	ioctl(-1, DM_DEV_RENAME, &s);
 | |
| 	printf("ioctl(-1, DM_DEV_RENAME, "
 | |
| 	       "{version=4.1.2, data_size=%u, data_start=%u, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", event_nr=0, "
 | |
| 	       "flags=0, "
 | |
| # if VERBOSE
 | |
| 	       "string=\"new long \"..."
 | |
| # else /* !VERBOSE */
 | |
| 	       "..."
 | |
| # endif /* VERBOSE */
 | |
| 	       "}) = -1 EBADF (%m)\n",
 | |
| 	       s.ioc.data_size, s.ioc.data_start);
 | |
| 
 | |
| 
 | |
| 	/* DM_TABLE_LOAD */
 | |
| 	init_s(&s.ioc, sizeof(s), offsetof(struct s, u));
 | |
| 	s.ioc.target_count = -1U;
 | |
| 	ioctl(-1, DM_TABLE_LOAD, &s);
 | |
| 	printf("ioctl(-1, DM_TABLE_LOAD, "
 | |
| 	       "{version=4.1.2, data_size=%u, data_start=%u, "
 | |
| 	       "dev=makedev(18, 52), name=\"nnn\", uuid=\"uuu\", "
 | |
| 	       "target_count=4294967295, flags=0, "
 | |
| # if VERBOSE
 | |
| 	       "{sector_start=0, length=0, target_type=\"\", string=\"\"}"
 | |
| 	       ", ??? /* misplaced struct dm_target_spec */"
 | |
| # else
 | |
| 	       "..."
 | |
| # endif /* VERBOSE */
 | |
| 	       "}) = -1 EBADF (%m)\n",
 | |
| 	       s.ioc.data_size, s.ioc.data_start);
 | |
| 
 | |
| 	puts("+++ exited with 0 +++");
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| #else /* !HAVE_LINUX_DM_IOCTL_H */
 | |
| 
 | |
| SKIP_MAIN_UNDEFINED("HAVE_LINUX_DM_IOCTL_H")
 | |
| 
 | |
| #endif /* HAVE_LINUX_DM_IOCTL_H */
 |