| /* |
| * Check decoding of DM_* commands of ioctl syscall. |
| * |
| * Copyright (c) 2016 Mikulas Patocka <[email protected]> |
| * Copyright (c) 2016 Eugene Syromyatnikov <[email protected]> |
| * 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 */ |