1 /* 2 * Check decoding of struct msghdr ancillary data. 3 * 4 * Copyright (c) 2016 Dmitry V. Levin <ldv (at) altlinux.org> 5 * Copyright (c) 2016-2017 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 <errno.h> 33 #include <limits.h> 34 #include <stddef.h> 35 #include <stdio.h> 36 #include <string.h> 37 #include <unistd.h> 38 #include <sys/socket.h> 39 #include <net/if.h> 40 #include <netinet/in.h> 41 #include <arpa/inet.h> 42 43 #include "xlat.h" 44 #include "xlat/scmvals.h" 45 46 #ifndef SOL_IP 47 # define SOL_IP 0 48 #endif 49 #ifndef SOL_TCP 50 # define SOL_TCP 6 51 #endif 52 53 #ifndef SCM_SECURITY 54 # define SCM_SECURITY 3 55 #endif 56 57 #define MIN_SIZE_OF(type, member) \ 58 (offsetof(type, member) + sizeof(((type *) 0)->member)) 59 60 static struct cmsghdr * 61 get_cmsghdr(void *const page, const size_t len) 62 { 63 return page - CMSG_ALIGN(len); 64 } 65 66 static void 67 print_fds(const struct cmsghdr *const cmsg, const size_t cmsg_len) 68 { 69 size_t nfd = cmsg_len > CMSG_LEN(0) 70 ? (cmsg_len - CMSG_LEN(0)) / sizeof(int) : 0; 71 if (!nfd) 72 return; 73 74 printf(", cmsg_data=["); 75 int *fdp = (int *) CMSG_DATA(cmsg); 76 size_t i; 77 for (i = 0; i < nfd; ++i) { 78 if (i) 79 printf(", "); 80 #if !VERBOSE 81 if (i >= DEFAULT_STRLEN) { 82 printf("..."); 83 break; 84 } 85 #endif 86 printf("%d", fdp[i]); 87 } 88 printf("]"); 89 } 90 91 static void 92 test_scm_rights1(struct msghdr *const mh, 93 const size_t msg_controllen, 94 void *const page, 95 const void *const src, 96 const size_t cmsg_len) 97 { 98 const size_t aligned_cms_len = 99 cmsg_len > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len) : CMSG_LEN(0); 100 if (cmsg_len >= CMSG_LEN(0) 101 && aligned_cms_len + CMSG_LEN(0) <= msg_controllen) 102 return; 103 104 struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen); 105 106 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_len)) 107 cmsg->cmsg_len = cmsg_len; 108 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_level)) 109 cmsg->cmsg_level = SOL_SOCKET; 110 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_type)) 111 cmsg->cmsg_type = SCM_RIGHTS; 112 113 size_t src_len = 114 cmsg_len < msg_controllen ? cmsg_len : msg_controllen; 115 if (src_len > CMSG_LEN(0)) 116 memcpy(CMSG_DATA(cmsg), src, src_len - CMSG_LEN(0)); 117 118 mh->msg_control = cmsg; 119 mh->msg_controllen = msg_controllen; 120 121 int rc = sendmsg(-1, mh, 0); 122 int saved_errno = errno; 123 124 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 125 ", msg_iovlen=0"); 126 if (msg_controllen < CMSG_LEN(0)) { 127 if (msg_controllen) 128 printf(", msg_control=%p", cmsg); 129 } else { 130 printf(", msg_control=[{cmsg_len=%lu, cmsg_level=SOL_SOCKET" 131 ", cmsg_type=SCM_RIGHTS", (unsigned long) cmsg_len); 132 print_fds(cmsg, src_len); 133 printf("}"); 134 if (aligned_cms_len < msg_controllen) 135 printf(", %p", (void *) cmsg + aligned_cms_len); 136 printf("]"); 137 } 138 139 errno = saved_errno; 140 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n", 141 (unsigned long) msg_controllen, rc, errno2name()); 142 } 143 144 static void 145 test_scm_rights2(struct msghdr *const mh, 146 const size_t msg_controllen, 147 void *const page, 148 const int *const *const src, 149 const size_t *const cmsg_len) 150 { 151 const size_t aligned_cms_len[2] = { 152 cmsg_len[0] > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len[0]) : CMSG_LEN(0), 153 cmsg_len[1] > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len[1]) : CMSG_LEN(0) 154 }; 155 if (cmsg_len[0] < CMSG_LEN(0) 156 || aligned_cms_len[0] + CMSG_LEN(0) > msg_controllen 157 || aligned_cms_len[0] + aligned_cms_len[1] + CMSG_LEN(0) <= msg_controllen) 158 return; 159 160 struct cmsghdr *const cmsg[2] = { 161 get_cmsghdr(page, msg_controllen), 162 (void *) get_cmsghdr(page, msg_controllen) + aligned_cms_len[0] 163 }; 164 cmsg[0]->cmsg_len = cmsg_len[0]; 165 cmsg[0]->cmsg_level = SOL_SOCKET; 166 cmsg[0]->cmsg_type = SCM_RIGHTS; 167 if (cmsg_len[0] > CMSG_LEN(0)) 168 memcpy(CMSG_DATA(cmsg[0]), src[0], cmsg_len[0] - CMSG_LEN(0)); 169 170 const size_t msg_controllen1 = msg_controllen - aligned_cms_len[0]; 171 if (msg_controllen1 >= MIN_SIZE_OF(struct cmsghdr, cmsg_len)) 172 cmsg[1]->cmsg_len = cmsg_len[1]; 173 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_level)) 174 cmsg[1]->cmsg_level = SOL_SOCKET; 175 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_type)) 176 cmsg[1]->cmsg_type = SCM_RIGHTS; 177 size_t src1_len = 178 cmsg_len[1] < msg_controllen1 ? cmsg_len[1] : msg_controllen1; 179 if (src1_len > CMSG_LEN(0)) 180 memcpy(CMSG_DATA(cmsg[1]), src[1], src1_len - CMSG_LEN(0)); 181 182 mh->msg_control = cmsg[0]; 183 mh->msg_controllen = msg_controllen; 184 185 int rc = sendmsg(-1, mh, 0); 186 int saved_errno = errno; 187 188 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 189 ", msg_iovlen=0, msg_control=[{cmsg_len=%lu" 190 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS", 191 (unsigned long) cmsg_len[0]); 192 print_fds(cmsg[0], cmsg_len[0]); 193 printf("}, {cmsg_len=%lu, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS", 194 (unsigned long) cmsg_len[1]); 195 print_fds(cmsg[1], src1_len); 196 printf("}"); 197 if (aligned_cms_len[1] < msg_controllen1) 198 printf(", %p", (void *) cmsg[1] + aligned_cms_len[1]); 199 printf("]"); 200 201 errno = saved_errno; 202 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n", 203 (unsigned long) msg_controllen, rc, errno2name()); 204 } 205 206 static void 207 test_scm_rights3(struct msghdr *const mh, void *const page, const size_t nfds) 208 { 209 const size_t len = CMSG_SPACE(sizeof(int) * nfds); 210 struct cmsghdr *cmsg = get_cmsghdr(page, len); 211 212 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * nfds); 213 cmsg->cmsg_level = SOL_SOCKET; 214 cmsg->cmsg_type = SCM_RIGHTS; 215 int *fdp = (int *) CMSG_DATA(cmsg); 216 size_t i; 217 for (i = 0; i < nfds; ++i) 218 fdp[i] = i; 219 220 mh->msg_control = cmsg; 221 mh->msg_controllen = len; 222 223 int rc = sendmsg(-1, mh, 0); 224 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 225 ", msg_iovlen=0, msg_control=[{cmsg_len=%u" 226 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS", 227 (unsigned) cmsg->cmsg_len); 228 print_fds(cmsg, cmsg->cmsg_len); 229 printf("}], msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n", 230 (unsigned long) len, rc, errno2name()); 231 } 232 233 static void 234 test_scm_timestamp(struct msghdr *const mh, void *const page) 235 { 236 size_t len = CMSG_SPACE(sizeof(struct timeval)); 237 struct cmsghdr *cmsg = get_cmsghdr(page, len); 238 239 cmsg->cmsg_len = CMSG_LEN(sizeof(struct timeval)); 240 cmsg->cmsg_level = SOL_SOCKET; 241 cmsg->cmsg_type = SCM_TIMESTAMP; 242 struct timeval *tv = (struct timeval *) CMSG_DATA(cmsg); 243 tv->tv_sec = 123456789; 244 tv->tv_usec = 987654; 245 246 mh->msg_control = cmsg; 247 mh->msg_controllen = len; 248 249 int rc = sendmsg(-1, mh, 0); 250 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 251 ", msg_iovlen=0, msg_control=[{cmsg_len=%u" 252 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMP" 253 ", cmsg_data={tv_sec=%lld, tv_usec=%llu}}]" 254 ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n", 255 (unsigned) cmsg->cmsg_len, 256 (long long) tv->tv_sec, zero_extend_signed_to_ull(tv->tv_usec), 257 (unsigned long) len, rc, errno2name()); 258 259 len = CMSG_SPACE(sizeof(struct timeval) - sizeof(long)); 260 cmsg = get_cmsghdr(page, len); 261 262 cmsg->cmsg_len = CMSG_LEN(sizeof(struct timeval) - sizeof(long)); 263 cmsg->cmsg_level = SOL_SOCKET; 264 cmsg->cmsg_type = SCM_TIMESTAMP; 265 266 mh->msg_control = cmsg; 267 mh->msg_controllen = len; 268 269 rc = sendmsg(-1, mh, 0); 270 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 271 ", msg_iovlen=0, msg_control=[{cmsg_len=%u" 272 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMP, cmsg_data=?}]" 273 ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n", 274 (unsigned) cmsg->cmsg_len, 275 (unsigned long) len, rc, errno2name()); 276 } 277 278 static void 279 test_scm_timestampns(struct msghdr *const mh, void *const page) 280 { 281 size_t len = CMSG_SPACE(sizeof(struct timespec)); 282 struct cmsghdr *cmsg = get_cmsghdr(page, len); 283 284 cmsg->cmsg_len = CMSG_LEN(sizeof(struct timespec)); 285 cmsg->cmsg_level = SOL_SOCKET; 286 cmsg->cmsg_type = SCM_TIMESTAMPNS; 287 struct timespec *ts = (struct timespec *) CMSG_DATA(cmsg); 288 ts->tv_sec = 123456789; 289 ts->tv_nsec = 987654321; 290 291 mh->msg_control = cmsg; 292 mh->msg_controllen = len; 293 294 int rc = sendmsg(-1, mh, 0); 295 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 296 ", msg_iovlen=0, msg_control=[{cmsg_len=%u" 297 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMPNS" 298 ", cmsg_data={tv_sec=%lld, tv_nsec=%llu}}]" 299 ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n", 300 (unsigned) cmsg->cmsg_len, 301 (long long) ts->tv_sec, zero_extend_signed_to_ull(ts->tv_nsec), 302 (unsigned long) len, rc, errno2name()); 303 304 len = CMSG_SPACE(sizeof(struct timespec) - sizeof(long)); 305 cmsg = get_cmsghdr(page, len); 306 307 cmsg->cmsg_len = CMSG_LEN(sizeof(struct timespec) - sizeof(long)); 308 cmsg->cmsg_level = SOL_SOCKET; 309 cmsg->cmsg_type = SCM_TIMESTAMPNS; 310 311 mh->msg_control = cmsg; 312 mh->msg_controllen = len; 313 314 rc = sendmsg(-1, mh, 0); 315 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 316 ", msg_iovlen=0, msg_control=[{cmsg_len=%u" 317 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMPNS" 318 ", cmsg_data=?}]" 319 ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n", 320 (unsigned) cmsg->cmsg_len, 321 (unsigned long) len, rc, errno2name()); 322 } 323 324 static void 325 test_scm_timestamping(struct msghdr *const mh, void *const page) 326 { 327 size_t len = CMSG_SPACE(3 * sizeof(struct timespec)); 328 struct cmsghdr *cmsg = get_cmsghdr(page, len); 329 330 cmsg->cmsg_len = CMSG_LEN(3 * sizeof(struct timespec)); 331 cmsg->cmsg_level = SOL_SOCKET; 332 cmsg->cmsg_type = SCM_TIMESTAMPING; 333 struct timespec *ts = (struct timespec *) CMSG_DATA(cmsg); 334 ts[0].tv_sec = 123456789; 335 ts[0].tv_nsec = 987654321; 336 ts[1].tv_sec = 123456790; 337 ts[1].tv_nsec = 987654320; 338 ts[2].tv_sec = 123456791; 339 ts[2].tv_nsec = 987654319; 340 341 mh->msg_control = cmsg; 342 mh->msg_controllen = len; 343 344 int rc = sendmsg(-1, mh, 0); 345 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 346 ", msg_iovlen=0, msg_control=[{cmsg_len=%u" 347 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMPING" 348 ", cmsg_data=[{tv_sec=%lld, tv_nsec=%llu}" 349 ", {tv_sec=%lld, tv_nsec=%llu}, {tv_sec=%lld, tv_nsec=%llu}]}]" 350 ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n", 351 (unsigned) cmsg->cmsg_len, (long long) ts[0].tv_sec, 352 zero_extend_signed_to_ull(ts[0].tv_nsec), 353 (long long) ts[1].tv_sec, 354 zero_extend_signed_to_ull(ts[1].tv_nsec), 355 (long long) ts[2].tv_sec, 356 zero_extend_signed_to_ull(ts[2].tv_nsec), 357 (unsigned long) len, rc, errno2name()); 358 359 len = CMSG_SPACE(3 * sizeof(struct timespec) - sizeof(long)); 360 cmsg = get_cmsghdr(page, len); 361 362 cmsg->cmsg_len = CMSG_LEN(3 * sizeof(struct timespec) - sizeof(long)); 363 cmsg->cmsg_level = SOL_SOCKET; 364 cmsg->cmsg_type = SCM_TIMESTAMPING; 365 366 mh->msg_control = cmsg; 367 mh->msg_controllen = len; 368 369 rc = sendmsg(-1, mh, 0); 370 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 371 ", msg_iovlen=0, msg_control=[{cmsg_len=%u" 372 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMPING" 373 ", cmsg_data=?}]" 374 ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n", 375 (unsigned) cmsg->cmsg_len, 376 (unsigned long) len, rc, errno2name()); 377 } 378 379 static void 380 print_security(const struct cmsghdr *const cmsg, const size_t cmsg_len) 381 { 382 int n = cmsg_len > CMSG_LEN(0) ? cmsg_len - CMSG_LEN(0) : 0; 383 if (!n) 384 return; 385 386 printf(", cmsg_data=\"%.*s\"", n, CMSG_DATA(cmsg)); 387 } 388 389 static void 390 test_scm_security(struct msghdr *const mh, 391 const size_t msg_controllen, 392 void *const page, 393 const void *const src, 394 const size_t cmsg_len, 395 const int cmsg_level, 396 const char *const cmsg_level_str) 397 { 398 const size_t aligned_cms_len = 399 cmsg_len > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len) : CMSG_LEN(0); 400 if (cmsg_len >= CMSG_LEN(0) 401 && aligned_cms_len + CMSG_LEN(0) <= msg_controllen) 402 return; 403 404 struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen); 405 406 cmsg->cmsg_len = cmsg_len; 407 cmsg->cmsg_level = cmsg_level; 408 cmsg->cmsg_type = SCM_SECURITY; 409 410 size_t src_len = 411 cmsg_len < msg_controllen ? cmsg_len : msg_controllen; 412 if (src_len > CMSG_LEN(0)) 413 memcpy(CMSG_DATA(cmsg), src, src_len - CMSG_LEN(0)); 414 415 mh->msg_control = cmsg; 416 mh->msg_controllen = msg_controllen; 417 418 int rc = sendmsg(-1, mh, 0); 419 int saved_errno = errno; 420 421 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 422 ", msg_iovlen=0, msg_control=[{cmsg_len=%lu, cmsg_level=%s" 423 ", cmsg_type=SCM_SECURITY", 424 (unsigned long) cmsg_len, cmsg_level_str); 425 print_security(cmsg, src_len); 426 printf("}"); 427 if (aligned_cms_len < msg_controllen) 428 printf(", %p", (void *) cmsg + aligned_cms_len); 429 printf("]"); 430 431 errno = saved_errno; 432 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n", 433 (unsigned long) msg_controllen, rc, errno2name()); 434 } 435 436 static void 437 test_unknown_type(struct msghdr *const mh, 438 void *const page, 439 const int cmsg_level, 440 const char *const cmsg_level_str, 441 const char *const cmsg_type_str) 442 { 443 struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0)); 444 445 cmsg->cmsg_len = CMSG_LEN(0); 446 cmsg->cmsg_level = cmsg_level; 447 cmsg->cmsg_type = 0xfacefeed; 448 449 mh->msg_control = cmsg; 450 mh->msg_controllen = cmsg->cmsg_len; 451 452 int rc = sendmsg(-1, mh, 0); 453 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 454 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=%s" 455 ", cmsg_type=%#x /* %s */}], msg_controllen=%u, msg_flags=0}" 456 ", 0) = %d %s (%m)\n", 457 (unsigned) cmsg->cmsg_len, cmsg_level_str, cmsg->cmsg_type, 458 cmsg_type_str, (unsigned) mh->msg_controllen, rc, errno2name()); 459 } 460 461 static void 462 test_sol_socket(struct msghdr *const mh, void *const page) 463 { 464 static const int fds0[] = { -10, -11, -12, -13 }; 465 static const int fds1[] = { -15, -16, -17, -18 }; 466 size_t msg_controllen, max_msg_controllen; 467 468 max_msg_controllen = CMSG_SPACE(sizeof(fds0)) + sizeof(*fds0) - 1; 469 for (msg_controllen = 0; 470 msg_controllen <= max_msg_controllen; 471 msg_controllen++) { 472 size_t cmsg_len; 473 474 for (cmsg_len = 0; 475 cmsg_len <= msg_controllen + CMSG_LEN(0); 476 cmsg_len++) { 477 test_scm_rights1(mh, msg_controllen, 478 page, fds0, cmsg_len); 479 } 480 } 481 482 max_msg_controllen = 483 CMSG_SPACE(sizeof(fds0)) + CMSG_SPACE(sizeof(fds1)) + 484 sizeof(*fds0) - 1; 485 for (msg_controllen = CMSG_LEN(0) * 2; 486 msg_controllen <= max_msg_controllen; 487 msg_controllen++) { 488 static const int *const fdps[] = { fds0, fds1 }; 489 size_t cmsg_len[2]; 490 491 for (cmsg_len[0] = CMSG_LEN(0); 492 CMSG_ALIGN(cmsg_len[0]) + CMSG_LEN(0) <= msg_controllen 493 && CMSG_ALIGN(cmsg_len[0]) <= CMSG_SPACE(sizeof(fds0)); 494 cmsg_len[0]++) { 495 const size_t msg_controllen1 = 496 msg_controllen - CMSG_ALIGN(cmsg_len[0]); 497 498 for (cmsg_len[1] = 0; 499 cmsg_len[1] <= msg_controllen1 + CMSG_LEN(0); 500 cmsg_len[1]++) { 501 test_scm_rights2(mh, msg_controllen, 502 page, fdps, cmsg_len); 503 } 504 } 505 } 506 507 static const char text[16] = "0123456789abcdef"; 508 max_msg_controllen = CMSG_SPACE(sizeof(text)) + CMSG_LEN(0) - 1; 509 for (msg_controllen = CMSG_LEN(0); 510 msg_controllen <= max_msg_controllen; 511 msg_controllen++) { 512 size_t cmsg_len; 513 514 for (cmsg_len = 0; 515 cmsg_len <= msg_controllen + CMSG_LEN(0) 516 && cmsg_len <= CMSG_LEN(sizeof(text)); 517 cmsg_len++) { 518 test_scm_security(mh, msg_controllen, 519 page, text, cmsg_len, 520 ARG_STR(SOL_SOCKET)); 521 } 522 } 523 524 test_scm_rights3(mh, page, DEFAULT_STRLEN - 1); 525 test_scm_rights3(mh, page, DEFAULT_STRLEN); 526 test_scm_rights3(mh, page, DEFAULT_STRLEN + 1); 527 528 test_scm_timestamp(mh, page); 529 test_scm_timestampns(mh, page); 530 test_scm_timestamping(mh, page); 531 532 test_unknown_type(mh, page, ARG_STR(SOL_SOCKET), "SCM_???"); 533 } 534 535 static void 536 test_ip_pktinfo(struct msghdr *const mh, void *const page, 537 const int cmsg_type, const char *const cmsg_type_str) 538 { 539 const unsigned int len = CMSG_SPACE(sizeof(struct in_pktinfo)); 540 struct cmsghdr *const cmsg = get_cmsghdr(page, len); 541 542 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); 543 cmsg->cmsg_level = SOL_IP; 544 cmsg->cmsg_type = cmsg_type; 545 546 struct in_pktinfo *const info = (struct in_pktinfo *) CMSG_DATA(cmsg); 547 #ifdef HAVE_IF_INDEXTONAME 548 info->ipi_ifindex = if_nametoindex("lo"); 549 #else 550 info->ipi_ifindex = 1; 551 #endif 552 info->ipi_spec_dst.s_addr = inet_addr("1.2.3.4"); 553 info->ipi_addr.s_addr = inet_addr("5.6.7.8"); 554 555 mh->msg_control = cmsg; 556 mh->msg_controllen = len; 557 558 int rc = sendmsg(-1, mh, 0); 559 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 560 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP" 561 ", cmsg_type=%s, cmsg_data={ipi_ifindex=%s" 562 ", ipi_spec_dst=inet_addr(\"%s\")" 563 ", ipi_addr=inet_addr(\"%s\")}}]" 564 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n", 565 (unsigned) cmsg->cmsg_len, cmsg_type_str, 566 #ifdef HAVE_IF_INDEXTONAME 567 "if_nametoindex(\"lo\")", 568 #else 569 "1", 570 #endif 571 "1.2.3.4", "5.6.7.8", len, rc, errno2name()); 572 } 573 574 static void 575 test_ip_uint(struct msghdr *const mh, void *const page, 576 const int cmsg_type, const char *const cmsg_type_str) 577 { 578 const unsigned int len = CMSG_SPACE(sizeof(int)); 579 struct cmsghdr *const cmsg = get_cmsghdr(page, len); 580 581 cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 582 cmsg->cmsg_level = SOL_IP; 583 cmsg->cmsg_type = cmsg_type; 584 585 unsigned int *u = (void *) CMSG_DATA(cmsg); 586 *u = 0xfacefeed; 587 588 mh->msg_control = cmsg; 589 mh->msg_controllen = len; 590 591 int rc = sendmsg(-1, mh, 0); 592 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 593 ", msg_iovlen=0, msg_control=[{cmsg_len=%u" 594 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%u]}]" 595 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n", 596 (unsigned) cmsg->cmsg_len, cmsg_type_str, *u, len, 597 rc, errno2name()); 598 } 599 600 static void 601 test_ip_uint8_t(struct msghdr *const mh, void *const page, 602 const int cmsg_type, const char *const cmsg_type_str) 603 { 604 const unsigned int len = CMSG_SPACE(1); 605 struct cmsghdr *const cmsg = get_cmsghdr(page, len); 606 607 cmsg->cmsg_len = CMSG_LEN(1); 608 cmsg->cmsg_level = SOL_IP; 609 cmsg->cmsg_type = cmsg_type; 610 *CMSG_DATA(cmsg) = 'A'; 611 612 mh->msg_control = cmsg; 613 mh->msg_controllen = len; 614 615 int rc = sendmsg(-1, mh, 0); 616 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 617 ", msg_iovlen=0, msg_control=[{cmsg_len=%u" 618 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%#x]}]" 619 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n", 620 (unsigned) cmsg->cmsg_len, cmsg_type_str, 621 (unsigned) (uint8_t) 'A', len, rc, errno2name()); 622 } 623 624 static void 625 print_ip_opts(const void *const cmsg_data, const unsigned int data_len) 626 { 627 const unsigned char *const opts = cmsg_data; 628 unsigned int i; 629 for (i = 0; i < data_len; ++i) { 630 if (i) 631 printf(", "); 632 #if !VERBOSE 633 if (i >= DEFAULT_STRLEN) { 634 printf("..."); 635 break; 636 } 637 #endif 638 printf("0x%02x", opts[i]); 639 } 640 } 641 642 static void 643 test_ip_opts(struct msghdr *const mh, void *const page, 644 const int cmsg_type, const char *const cmsg_type_str, 645 const unsigned int opts_len) 646 { 647 unsigned int len = CMSG_SPACE(opts_len); 648 struct cmsghdr *cmsg = get_cmsghdr(page, len); 649 650 cmsg->cmsg_len = CMSG_LEN(opts_len); 651 cmsg->cmsg_level = SOL_IP; 652 cmsg->cmsg_type = cmsg_type; 653 unsigned int i; 654 for (i = 0; i < opts_len; ++i) 655 CMSG_DATA(cmsg)[i] = 'A' + i; 656 657 mh->msg_control = cmsg; 658 mh->msg_controllen = len; 659 660 int rc = sendmsg(-1, mh, 0); 661 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 662 ", msg_iovlen=0, msg_control=[{cmsg_len=%u" 663 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[", 664 (unsigned) cmsg->cmsg_len, cmsg_type_str); 665 print_ip_opts(CMSG_DATA(cmsg), opts_len); 666 printf("]}], msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n", 667 len, rc, errno2name()); 668 } 669 670 #ifdef IP_CHECKSUM 671 struct sock_ee { 672 uint32_t ee_errno; 673 uint8_t ee_origin; 674 uint8_t ee_type; 675 uint8_t ee_code; 676 uint8_t ee_pad; 677 uint32_t ee_info; 678 uint32_t ee_data; 679 struct sockaddr_in offender; 680 }; 681 682 static void 683 test_ip_recverr(struct msghdr *const mh, void *const page, 684 const int cmsg_type, const char *const cmsg_type_str) 685 { 686 const unsigned int len = CMSG_SPACE(sizeof(struct sock_ee)); 687 struct cmsghdr *const cmsg = get_cmsghdr(page, len); 688 689 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sock_ee)); 690 cmsg->cmsg_level = SOL_IP; 691 cmsg->cmsg_type = cmsg_type; 692 693 struct sock_ee *const e = (struct sock_ee *) CMSG_DATA(cmsg); 694 e->ee_errno = 0xdeadbeef; 695 e->ee_origin = 2; 696 e->ee_type = 3; 697 e->ee_code = 4; 698 e->ee_info = 0xfacefeed; 699 e->ee_data = 0xbadc0ded; 700 e->offender.sin_family = AF_INET, 701 e->offender.sin_port = htons(12345), 702 e->offender.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 703 704 mh->msg_control = cmsg; 705 mh->msg_controllen = len; 706 707 int rc = sendmsg(-1, mh, 0); 708 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 709 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP" 710 ", cmsg_type=%s, cmsg_data={ee_errno=%u, ee_origin=%u" 711 ", ee_type=%u, ee_code=%u, ee_info=%u, ee_data=%u" 712 ", offender={sa_family=AF_INET, sin_port=htons(%hu)" 713 ", sin_addr=inet_addr(\"127.0.0.1\")}}}]" 714 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n", 715 (unsigned) cmsg->cmsg_len, cmsg_type_str, 716 e->ee_errno, e->ee_origin, e->ee_type, 717 e->ee_code, e->ee_info, e->ee_data, 718 ntohs(e->offender.sin_port), 719 len, rc, errno2name()); 720 } 721 #endif 722 723 #ifdef IP_ORIGDSTADDR 724 static void 725 test_ip_origdstaddr(struct msghdr *const mh, void *const page, 726 const int cmsg_type, const char *const cmsg_type_str) 727 { 728 const unsigned int len = CMSG_SPACE(sizeof(struct sockaddr_in)); 729 struct cmsghdr *const cmsg = get_cmsghdr(page, len); 730 731 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sockaddr_in)); 732 cmsg->cmsg_level = SOL_IP; 733 cmsg->cmsg_type = cmsg_type; 734 735 struct sockaddr_in *const sin = (struct sockaddr_in *) CMSG_DATA(cmsg); 736 sin->sin_family = AF_INET, 737 sin->sin_port = htons(12345), 738 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 739 740 mh->msg_control = cmsg; 741 mh->msg_controllen = len; 742 743 int rc = sendmsg(-1, mh, 0); 744 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 745 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP" 746 ", cmsg_type=%s, cmsg_data={sa_family=AF_INET" 747 ", sin_port=htons(%hu), sin_addr=inet_addr(\"127.0.0.1\")}}]" 748 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n", 749 (unsigned) cmsg->cmsg_len, cmsg_type_str, 750 ntohs(sin->sin_port), len, rc, errno2name()); 751 } 752 #endif 753 754 static void 755 test_sol_ip(struct msghdr *const mh, void *const page) 756 { 757 test_ip_pktinfo(mh, page, ARG_STR(IP_PKTINFO)); 758 test_ip_uint(mh, page, ARG_STR(IP_TTL)); 759 test_ip_uint8_t(mh, page, ARG_STR(IP_TOS)); 760 test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 1); 761 test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 2); 762 test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 3); 763 test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 4); 764 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 5); 765 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 6); 766 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 7); 767 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 8); 768 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), DEFAULT_STRLEN - 1); 769 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), DEFAULT_STRLEN); 770 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), DEFAULT_STRLEN + 1); 771 #ifdef IP_CHECKSUM 772 test_ip_recverr(mh, page, ARG_STR(IP_RECVERR)); 773 #endif 774 #ifdef IP_ORIGDSTADDR 775 test_ip_origdstaddr(mh, page, ARG_STR(IP_ORIGDSTADDR)); 776 #endif 777 #ifdef IP_CHECKSUM 778 test_ip_uint(mh, page, ARG_STR(IP_CHECKSUM)); 779 #endif 780 test_scm_security(mh, CMSG_LEN(0), page, 0, CMSG_LEN(0), 781 ARG_STR(SOL_IP)); 782 test_unknown_type(mh, page, ARG_STR(SOL_IP), "IP_???"); 783 } 784 785 static void 786 test_unknown_level(struct msghdr *const mh, void *const page) 787 { 788 struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0)); 789 790 cmsg->cmsg_len = CMSG_LEN(0); 791 cmsg->cmsg_level = SOL_TCP; 792 cmsg->cmsg_type = 0xdeadbeef; 793 794 mh->msg_control = cmsg; 795 mh->msg_controllen = cmsg->cmsg_len; 796 797 int rc = sendmsg(-1, mh, 0); 798 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 799 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=%s" 800 ", cmsg_type=%#x}], msg_controllen=%u, msg_flags=0}" 801 ", 0) = %d %s (%m)\n", 802 (unsigned) cmsg->cmsg_len, "SOL_TCP", cmsg->cmsg_type, 803 (unsigned) mh->msg_controllen, rc, errno2name()); 804 } 805 806 static void 807 test_big_len(struct msghdr *const mh) 808 { 809 int optmem_max; 810 811 if (read_int_from_file("/proc/sys/net/core/optmem_max", &optmem_max) 812 || optmem_max <= 0 || optmem_max > 0x100000) 813 optmem_max = sizeof(long long) * (2 * IOV_MAX + 512); 814 optmem_max = (optmem_max + sizeof(long long) - 1) 815 & ~(sizeof(long long) - 1); 816 817 const size_t len = optmem_max * 2; 818 struct cmsghdr *const cmsg = tail_alloc(len); 819 cmsg->cmsg_len = len; 820 cmsg->cmsg_level = SOL_SOCKET; 821 cmsg->cmsg_type = SCM_RIGHTS; 822 823 mh->msg_control = cmsg; 824 mh->msg_controllen = len; 825 826 int rc = sendmsg(-1, mh, 0); 827 if (EBADF != errno) 828 perror_msg_and_skip("sendmsg"); 829 830 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 831 ", msg_iovlen=0, msg_control=[{cmsg_len=%u" 832 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS", 833 (unsigned) cmsg->cmsg_len); 834 print_fds(cmsg, optmem_max); 835 printf("}, ...], msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n", 836 (unsigned long) len, rc, errno2name()); 837 } 838 839 int main(int ac, const char **av) 840 { 841 int rc = sendmsg(-1, 0, 0); 842 printf("sendmsg(-1, NULL, 0) = %d %s (%m)\n", rc, errno2name()); 843 844 TAIL_ALLOC_OBJECT_CONST_PTR(struct msghdr, mh); 845 memset(mh, 0, sizeof(*mh)); 846 test_big_len(mh); 847 848 rc = sendmsg(-1, mh + 1, 0); 849 printf("sendmsg(-1, %p, 0) = %d %s (%m)\n", 850 mh + 1, rc, errno2name()); 851 852 void *page = tail_alloc(1) + 1; 853 mh->msg_control = page; 854 mh->msg_controllen = CMSG_LEN(0); 855 rc = sendmsg(-1, mh, 0); 856 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 857 ", msg_iovlen=0, msg_control=%p, msg_controllen=%u" 858 ", msg_flags=0}, 0) = %d %s (%m)\n", 859 page, (unsigned) CMSG_LEN(0), rc, errno2name()); 860 861 test_sol_socket(mh, page); 862 test_sol_ip(mh, page); 863 test_unknown_level(mh, page); 864 865 puts("+++ exited with 0 +++"); 866 return 0; 867 } 868