1 /* 2 * Check decoding of preadv2 and pwritev2 syscalls. 3 * 4 * Copyright (c) 2016 Dmitry V. Levin <ldv (at) altlinux.org> 5 * Copyright (c) 2016-2018 The strace developers. 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 #include <asm/unistd.h> 33 #include "scno.h" 34 35 #if defined __NR_preadv2 && defined __NR_pwritev2 36 37 # include <errno.h> 38 # include <fcntl.h> 39 # include <stdio.h> 40 # include <sys/uio.h> 41 # include <unistd.h> 42 43 static int 44 pr(const int fd, const struct iovec *const vec, 45 const unsigned long vlen, const unsigned long pos) 46 { 47 return syscall(__NR_preadv2, fd, vec, vlen, pos, 0L, 0L); 48 } 49 50 static int 51 pw(const int fd, const struct iovec *const vec, 52 const unsigned long vlen, const unsigned long pos) 53 { 54 return syscall(__NR_pwritev2, fd, vec, vlen, pos, 0L, 0L); 55 } 56 57 static void 58 dumpio(void) 59 { 60 static char tmp[] = "preadv2-pwritev2-tmpfile"; 61 if (open(tmp, O_CREAT|O_RDONLY|O_TRUNC, 0600) != 0) 62 perror_msg_and_fail("creat: %s", tmp); 63 if (open(tmp, O_WRONLY) != 1) 64 perror_msg_and_fail("open: %s", tmp); 65 if (unlink(tmp)) 66 perror_msg_and_fail("unlink: %s", tmp); 67 68 static const char w0_c[] = "012"; 69 const char *w0_d = hexdump_strdup(w0_c); 70 void *w0 = tail_memdup(w0_c, LENGTH_OF(w0_c)); 71 72 static const char w1_c[] = "34567"; 73 const char *w1_d = hexdump_strdup(w1_c); 74 void *w1 = tail_memdup(w1_c, LENGTH_OF(w1_c)); 75 76 static const char w2_c[] = "89abcde"; 77 const char *w2_d = hexdump_strdup(w2_c); 78 void *w2 = tail_memdup(w2_c, LENGTH_OF(w2_c)); 79 80 long rc; 81 82 static const char r0_c[] = "01234567"; 83 const char *r0_d = hexdump_strdup(r0_c); 84 static const char r1_c[] = "89abcde"; 85 const char *r1_d = hexdump_strdup(r1_c); 86 87 const struct iovec w_iov_[] = { 88 { 89 .iov_base = w0, 90 .iov_len = LENGTH_OF(w0_c) 91 }, { 92 .iov_base = w1, 93 .iov_len = LENGTH_OF(w1_c) 94 }, { 95 .iov_base = w2, 96 .iov_len = LENGTH_OF(w2_c) 97 } 98 }; 99 const struct iovec *w_iov = tail_memdup(w_iov_, sizeof(w_iov_)); 100 101 rc = pw(1, w_iov, 0, 0); 102 if (rc) 103 perror_msg_and_fail("pwritev2: expected 0, returned %ld", rc); 104 tprintf("pwritev2(1, [], 0, 0, 0) = 0\n"); 105 106 rc = pw(1, w_iov + ARRAY_SIZE(w_iov_) - 1, 2, 0); 107 tprintf("pwritev2(1, [{iov_base=\"%s\", iov_len=%u}, ... /* %p */], 2, 0, 0)" 108 " = %ld %s (%m)\n", 109 w2_c, LENGTH_OF(w2_c), w_iov + ARRAY_SIZE(w_iov_), 110 rc, errno2name()); 111 112 const unsigned int w_len = 113 LENGTH_OF(w0_c) + LENGTH_OF(w1_c) + LENGTH_OF(w2_c); 114 115 rc = pw(1, w_iov, ARRAY_SIZE(w_iov_), 0); 116 if (rc != (int) w_len) 117 perror_msg_and_fail("pwritev2: expected %u, returned %ld", 118 w_len, rc); 119 close(1); 120 tprintf("pwritev2(1, [{iov_base=\"%s\", iov_len=%u}" 121 ", {iov_base=\"%s\", iov_len=%u}" 122 ", {iov_base=\"%s\", iov_len=%u}], %u, 0, 0) = %u\n" 123 " * %u bytes in buffer 0\n" 124 " | 00000 %-49s %-16s |\n" 125 " * %u bytes in buffer 1\n" 126 " | 00000 %-49s %-16s |\n" 127 " * %u bytes in buffer 2\n" 128 " | 00000 %-49s %-16s |\n", 129 w0_c, LENGTH_OF(w0_c), w1_c, LENGTH_OF(w1_c), 130 w2_c, LENGTH_OF(w2_c), (unsigned int) ARRAY_SIZE(w_iov_), w_len, 131 LENGTH_OF(w0_c), w0_d, w0_c, 132 LENGTH_OF(w1_c), w1_d, w1_c, LENGTH_OF(w2_c), w2_d, w2_c); 133 134 const unsigned int r_len = (w_len + 1) / 2; 135 void *r0 = tail_alloc(r_len); 136 const struct iovec r0_iov_[] = { 137 { 138 .iov_base = r0, 139 .iov_len = r_len 140 } 141 }; 142 const struct iovec *r_iov = tail_memdup(r0_iov_, sizeof(r0_iov_)); 143 144 rc = pr(0, r_iov, ARRAY_SIZE(r0_iov_), 0); 145 if (rc != (int) r_len) 146 perror_msg_and_fail("preadv2: expected %u, returned %ld", 147 r_len, rc); 148 tprintf("preadv2(0, [{iov_base=\"%s\", iov_len=%u}], %u, 0, 0) = %u\n" 149 " * %u bytes in buffer 0\n" 150 " | 00000 %-49s %-16s |\n", 151 r0_c, r_len, (unsigned int) ARRAY_SIZE(r0_iov_), 152 r_len, r_len, r0_d, r0_c); 153 154 void *r1 = tail_alloc(r_len); 155 void *r2 = tail_alloc(w_len); 156 const struct iovec r1_iov_[] = { 157 { 158 .iov_base = r1, 159 .iov_len = r_len 160 }, 161 { 162 .iov_base = r2, 163 .iov_len = w_len 164 } 165 }; 166 r_iov = tail_memdup(r1_iov_, sizeof(r1_iov_)); 167 168 rc = pr(0, r_iov, ARRAY_SIZE(r1_iov_), r_len); 169 if (rc != (int) w_len - (int) r_len) 170 perror_msg_and_fail("preadv2: expected %d, returned %ld", 171 (int) w_len - r_len, rc); 172 tprintf("preadv2(0, [{iov_base=\"%s\", iov_len=%u}" 173 ", {iov_base=\"\", iov_len=%u}], %u, %u, 0) = %u\n" 174 " * %u bytes in buffer 0\n" 175 " | 00000 %-49s %-16s |\n", 176 r1_c, r_len, w_len, (unsigned int) ARRAY_SIZE(r1_iov_), 177 r_len, w_len - r_len, 178 w_len - r_len, r1_d, r1_c); 179 close(0); 180 } 181 182 int 183 main(void) 184 { 185 const kernel_ulong_t vlen = (kernel_ulong_t) 0xfac1fed2dad3bef4ULL; 186 const unsigned long long pos = 0x7ac5fed6dad7bef8; 187 const kernel_ulong_t pos_l = (kernel_ulong_t) pos; 188 long rc; 189 int test_dumpio; 190 191 tprintf("%s", ""); 192 193 #if defined __x86_64__ && defined __ILP32__ 194 /* 195 * x32 is the only architecture where preadv2 takes 5 arguments, 196 * see preadv64v2 in kernel sources. 197 */ 198 rc = syscall(__NR_preadv2, -1, NULL, vlen, pos_l, 1); 199 #else 200 const kernel_ulong_t pos_h = 201 (sizeof(pos_l) == sizeof(pos)) ? 202 (kernel_ulong_t) 0xbadc0deddeadbeefULL : 203 (kernel_ulong_t) (pos >> 32); 204 rc = syscall(__NR_preadv2, -1, NULL, vlen, pos_l, pos_h, 1); 205 #endif 206 if (rc != -1 || (ENOSYS != errno && EBADF != errno)) 207 perror_msg_and_fail("preadv2"); 208 test_dumpio = EBADF == errno; 209 tprintf("preadv2(-1, NULL, %lu, %lld, RWF_HIPRI) = %s\n", 210 (unsigned long) vlen, pos, sprintrc(rc)); 211 212 #if defined __x86_64__ && defined __ILP32__ 213 /* 214 * x32 is the only architecture where pwritev2 takes 5 arguments, 215 * see pwritev64v2 in kernel sources. 216 */ 217 rc = syscall(__NR_pwritev2, -1, NULL, vlen, pos_l, 1); 218 #else 219 rc = syscall(__NR_pwritev2, -1, NULL, vlen, pos_l, pos_h, 1); 220 #endif 221 if (rc != -1 || (ENOSYS != errno && EBADF != errno)) 222 perror_msg_and_fail("pwritev2"); 223 tprintf("pwritev2(-1, NULL, %lu, %lld, RWF_HIPRI) = %s\n", 224 (unsigned long) vlen, pos, sprintrc(rc)); 225 226 if (test_dumpio) 227 dumpio(); 228 229 tprintf("%s\n", "+++ exited with 0 +++"); 230 return 0; 231 } 232 233 #else 234 235 SKIP_MAIN_UNDEFINED("__NR_preadv2 && __NR_pwritev2") 236 237 #endif 238