1 /* 2 * Check decoding of struct msghdr ancillary data. 3 * 4 * Copyright (c) 2016 Dmitry V. Levin <ldv (at) altlinux.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "tests.h" 31 #include <errno.h> 32 #include <limits.h> 33 #include <stddef.h> 34 #include <stdio.h> 35 #include <string.h> 36 #include <unistd.h> 37 #include <sys/socket.h> 38 #include <net/if.h> 39 #include <netinet/in.h> 40 #include <arpa/inet.h> 41 42 #ifndef SOL_IP 43 # define SOL_IP 0 44 #endif 45 #ifndef SOL_TCP 46 # define SOL_TCP 6 47 #endif 48 49 #ifndef SCM_SECURITY 50 # define SCM_SECURITY 3 51 #endif 52 53 #define MIN_SIZE_OF(type, member) \ 54 (offsetof(type, member) + sizeof(((type *) 0)->member)) 55 56 static struct cmsghdr * 57 get_cmsghdr(void *const page, const size_t len) 58 { 59 return page - CMSG_ALIGN(len); 60 } 61 62 #define DEFAULT_STRLEN 32 63 64 static void 65 print_fds(const struct cmsghdr *const cmsg, const size_t cmsg_len) 66 { 67 size_t nfd = cmsg_len > CMSG_LEN(0) 68 ? (cmsg_len - CMSG_LEN(0)) / sizeof(int) : 0; 69 if (!nfd) 70 return; 71 72 printf(", cmsg_data=["); 73 int *fdp = (int *) CMSG_DATA(cmsg); 74 size_t i; 75 for (i = 0; i < nfd; ++i) { 76 if (i) 77 printf(", "); 78 #if !VERBOSE 79 if (i >= DEFAULT_STRLEN) { 80 printf("..."); 81 break; 82 } 83 #endif 84 printf("%d", fdp[i]); 85 } 86 printf("]"); 87 } 88 89 static void 90 test_scm_rights1(struct msghdr *const mh, 91 const size_t msg_controllen, 92 void *const page, 93 const void *const src, 94 const size_t cmsg_len) 95 { 96 const size_t aligned_cms_len = 97 cmsg_len > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len) : CMSG_LEN(0); 98 if (cmsg_len >= CMSG_LEN(0) 99 && aligned_cms_len + CMSG_LEN(0) <= msg_controllen) 100 return; 101 102 struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen); 103 104 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_len)) 105 cmsg->cmsg_len = cmsg_len; 106 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_level)) 107 cmsg->cmsg_level = SOL_SOCKET; 108 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_type)) 109 cmsg->cmsg_type = SCM_RIGHTS; 110 111 size_t src_len = 112 cmsg_len < msg_controllen ? cmsg_len : msg_controllen; 113 if (src_len > CMSG_LEN(0)) 114 memcpy(CMSG_DATA(cmsg), src, src_len - CMSG_LEN(0)); 115 116 mh->msg_control = cmsg; 117 mh->msg_controllen = msg_controllen; 118 119 int rc = sendmsg(-1, mh, 0); 120 int saved_errno = errno; 121 122 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 123 ", msg_iovlen=0"); 124 if (msg_controllen < CMSG_LEN(0)) { 125 if (msg_controllen) 126 printf(", msg_control=%p", cmsg); 127 } else { 128 printf(", msg_control=[{cmsg_len=%lu, cmsg_level=SOL_SOCKET" 129 ", cmsg_type=SCM_RIGHTS", (unsigned long) cmsg_len); 130 print_fds(cmsg, src_len); 131 printf("}"); 132 if (aligned_cms_len < msg_controllen) 133 printf(", %p", (void *) cmsg + aligned_cms_len); 134 printf("]"); 135 } 136 137 errno = saved_errno; 138 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n", 139 (unsigned long) msg_controllen, rc, errno2name()); 140 } 141 142 static void 143 test_scm_rights2(struct msghdr *const mh, 144 const size_t msg_controllen, 145 void *const page, 146 const int *const *const src, 147 const size_t *const cmsg_len) 148 { 149 const size_t aligned_cms_len[2] = { 150 cmsg_len[0] > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len[0]) : CMSG_LEN(0), 151 cmsg_len[1] > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len[1]) : CMSG_LEN(0) 152 }; 153 if (cmsg_len[0] < CMSG_LEN(0) 154 || aligned_cms_len[0] + CMSG_LEN(0) > msg_controllen 155 || aligned_cms_len[0] + aligned_cms_len[1] + CMSG_LEN(0) <= msg_controllen) 156 return; 157 158 struct cmsghdr *const cmsg[2] = { 159 get_cmsghdr(page, msg_controllen), 160 (void *) get_cmsghdr(page, msg_controllen) + aligned_cms_len[0] 161 }; 162 cmsg[0]->cmsg_len = cmsg_len[0]; 163 cmsg[0]->cmsg_level = SOL_SOCKET; 164 cmsg[0]->cmsg_type = SCM_RIGHTS; 165 if (cmsg_len[0] > CMSG_LEN(0)) 166 memcpy(CMSG_DATA(cmsg[0]), src[0], cmsg_len[0] - CMSG_LEN(0)); 167 168 const size_t msg_controllen1 = msg_controllen - aligned_cms_len[0]; 169 if (msg_controllen1 >= MIN_SIZE_OF(struct cmsghdr, cmsg_len)) 170 cmsg[1]->cmsg_len = cmsg_len[1]; 171 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_level)) 172 cmsg[1]->cmsg_level = SOL_SOCKET; 173 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_type)) 174 cmsg[1]->cmsg_type = SCM_RIGHTS; 175 size_t src1_len = 176 cmsg_len[1] < msg_controllen1 ? cmsg_len[1] : msg_controllen1; 177 if (src1_len > CMSG_LEN(0)) 178 memcpy(CMSG_DATA(cmsg[1]), src[1], src1_len - CMSG_LEN(0)); 179 180 mh->msg_control = cmsg[0]; 181 mh->msg_controllen = msg_controllen; 182 183 int rc = sendmsg(-1, mh, 0); 184 int saved_errno = errno; 185 186 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 187 ", msg_iovlen=0, msg_control=[{cmsg_len=%lu" 188 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS", 189 (unsigned long) cmsg_len[0]); 190 print_fds(cmsg[0], cmsg_len[0]); 191 printf("}, {cmsg_len=%lu, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS", 192 (unsigned long) cmsg_len[1]); 193 print_fds(cmsg[1], src1_len); 194 printf("}"); 195 if (aligned_cms_len[1] < msg_controllen1) 196 printf(", %p", (void *) cmsg[1] + aligned_cms_len[1]); 197 printf("]"); 198 199 errno = saved_errno; 200 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n", 201 (unsigned long) msg_controllen, rc, errno2name()); 202 } 203 204 static void 205 test_scm_rights3(struct msghdr *const mh, void *const page, const size_t nfds) 206 { 207 const size_t len = CMSG_SPACE(sizeof(int) * nfds); 208 struct cmsghdr *cmsg = get_cmsghdr(page, len); 209 210 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * nfds); 211 cmsg->cmsg_level = SOL_SOCKET; 212 cmsg->cmsg_type = SCM_RIGHTS; 213 int *fdp = (int *) CMSG_DATA(cmsg); 214 size_t i; 215 for (i = 0; i < nfds; ++i) 216 fdp[i] = i; 217 218 mh->msg_control = cmsg; 219 mh->msg_controllen = len; 220 221 int rc = sendmsg(-1, mh, 0); 222 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 223 ", msg_iovlen=0, msg_control=[{cmsg_len=%u" 224 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS", 225 (unsigned) cmsg->cmsg_len); 226 print_fds(cmsg, cmsg->cmsg_len); 227 printf("}], msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n", 228 (unsigned long) len, rc, errno2name()); 229 } 230 231 static void 232 print_security(const struct cmsghdr *const cmsg, const size_t cmsg_len) 233 { 234 int n = cmsg_len > CMSG_LEN(0) ? cmsg_len - CMSG_LEN(0) : 0; 235 if (!n) 236 return; 237 238 printf(", cmsg_data=\"%.*s\"", n, CMSG_DATA(cmsg)); 239 } 240 241 static void 242 test_scm_security(struct msghdr *const mh, 243 const size_t msg_controllen, 244 void *const page, 245 const void *const src, 246 const size_t cmsg_len, 247 const int cmsg_level, 248 const char *const cmsg_level_str) 249 { 250 const size_t aligned_cms_len = 251 cmsg_len > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len) : CMSG_LEN(0); 252 if (cmsg_len >= CMSG_LEN(0) 253 && aligned_cms_len + CMSG_LEN(0) <= msg_controllen) 254 return; 255 256 struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen); 257 258 cmsg->cmsg_len = cmsg_len; 259 cmsg->cmsg_level = cmsg_level; 260 cmsg->cmsg_type = SCM_SECURITY; 261 262 size_t src_len = 263 cmsg_len < msg_controllen ? cmsg_len : msg_controllen; 264 if (src_len > CMSG_LEN(0)) 265 memcpy(CMSG_DATA(cmsg), src, src_len - CMSG_LEN(0)); 266 267 mh->msg_control = cmsg; 268 mh->msg_controllen = msg_controllen; 269 270 int rc = sendmsg(-1, mh, 0); 271 int saved_errno = errno; 272 273 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 274 ", msg_iovlen=0, msg_control=[{cmsg_len=%lu, cmsg_level=%s" 275 ", cmsg_type=SCM_SECURITY", 276 (unsigned long) cmsg_len, cmsg_level_str); 277 print_security(cmsg, src_len); 278 printf("}"); 279 if (aligned_cms_len < msg_controllen) 280 printf(", %p", (void *) cmsg + aligned_cms_len); 281 printf("]"); 282 283 errno = saved_errno; 284 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n", 285 (unsigned long) msg_controllen, rc, errno2name()); 286 } 287 288 static void 289 test_unknown_type(struct msghdr *const mh, 290 void *const page, 291 const int cmsg_level, 292 const char *const cmsg_level_str, 293 const char *const cmsg_type_str) 294 { 295 struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0)); 296 297 cmsg->cmsg_len = CMSG_LEN(0); 298 cmsg->cmsg_level = cmsg_level; 299 cmsg->cmsg_type = 0xfacefeed; 300 301 mh->msg_control = cmsg; 302 mh->msg_controllen = cmsg->cmsg_len; 303 304 int rc = sendmsg(-1, mh, 0); 305 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 306 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=%s" 307 ", cmsg_type=%#x /* %s */}], msg_controllen=%u, msg_flags=0}" 308 ", 0) = %d %s (%m)\n", 309 (unsigned) cmsg->cmsg_len, cmsg_level_str, cmsg->cmsg_type, 310 cmsg_type_str, (unsigned) mh->msg_controllen, rc, errno2name()); 311 } 312 313 static void 314 test_sol_socket(struct msghdr *const mh, void *const page) 315 { 316 static const int fds0[] = { -10, -11, -12, -13 }; 317 static const int fds1[] = { -15, -16, -17, -18 }; 318 size_t msg_controllen, max_msg_controllen; 319 320 max_msg_controllen = CMSG_SPACE(sizeof(fds0)) + sizeof(*fds0) - 1; 321 for (msg_controllen = 0; 322 msg_controllen <= max_msg_controllen; 323 msg_controllen++) { 324 size_t cmsg_len; 325 326 for (cmsg_len = 0; 327 cmsg_len <= msg_controllen + CMSG_LEN(0); 328 cmsg_len++) { 329 test_scm_rights1(mh, msg_controllen, 330 page, fds0, cmsg_len); 331 } 332 } 333 334 max_msg_controllen = 335 CMSG_SPACE(sizeof(fds0)) + CMSG_SPACE(sizeof(fds1)) + 336 sizeof(*fds0) - 1; 337 for (msg_controllen = CMSG_LEN(0) * 2; 338 msg_controllen <= max_msg_controllen; 339 msg_controllen++) { 340 static const int *const fdps[] = { fds0, fds1 }; 341 size_t cmsg_len[2]; 342 343 for (cmsg_len[0] = CMSG_LEN(0); 344 CMSG_ALIGN(cmsg_len[0]) + CMSG_LEN(0) <= msg_controllen 345 && CMSG_ALIGN(cmsg_len[0]) <= CMSG_SPACE(sizeof(fds0)); 346 cmsg_len[0]++) { 347 const size_t msg_controllen1 = 348 msg_controllen - CMSG_ALIGN(cmsg_len[0]); 349 350 for (cmsg_len[1] = 0; 351 cmsg_len[1] <= msg_controllen1 + CMSG_LEN(0); 352 cmsg_len[1]++) { 353 test_scm_rights2(mh, msg_controllen, 354 page, fdps, cmsg_len); 355 } 356 } 357 } 358 359 static const char text[16] = "0123456789abcdef"; 360 max_msg_controllen = CMSG_SPACE(sizeof(text)) + CMSG_LEN(0) - 1; 361 for (msg_controllen = CMSG_LEN(0); 362 msg_controllen <= max_msg_controllen; 363 msg_controllen++) { 364 size_t cmsg_len; 365 366 for (cmsg_len = 0; 367 cmsg_len <= msg_controllen + CMSG_LEN(0) 368 && cmsg_len <= CMSG_LEN(sizeof(text)); 369 cmsg_len++) { 370 test_scm_security(mh, msg_controllen, 371 page, text, cmsg_len, 372 ARG_STR(SOL_SOCKET)); 373 } 374 } 375 376 test_scm_rights3(mh, page, DEFAULT_STRLEN - 1); 377 test_scm_rights3(mh, page, DEFAULT_STRLEN); 378 test_scm_rights3(mh, page, DEFAULT_STRLEN + 1); 379 380 test_unknown_type(mh, page, ARG_STR(SOL_SOCKET), "SCM_???"); 381 } 382 383 static void 384 test_ip_pktinfo(struct msghdr *const mh, void *const page, 385 const int cmsg_type, const char *const cmsg_type_str) 386 { 387 const unsigned int len = CMSG_SPACE(sizeof(struct in_pktinfo)); 388 struct cmsghdr *const cmsg = get_cmsghdr(page, len); 389 390 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); 391 cmsg->cmsg_level = SOL_IP; 392 cmsg->cmsg_type = cmsg_type; 393 394 struct in_pktinfo *const info = (struct in_pktinfo *) CMSG_DATA(cmsg); 395 #ifdef HAVE_IF_INDEXTONAME 396 info->ipi_ifindex = if_nametoindex("lo"); 397 #else 398 info->ipi_ifindex = 1; 399 #endif 400 info->ipi_spec_dst.s_addr = inet_addr("1.2.3.4"); 401 info->ipi_addr.s_addr = inet_addr("5.6.7.8"); 402 403 mh->msg_control = cmsg; 404 mh->msg_controllen = len; 405 406 int rc = sendmsg(-1, mh, 0); 407 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 408 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP" 409 ", cmsg_type=%s, cmsg_data={ipi_ifindex=%s" 410 ", ipi_spec_dst=inet_addr(\"%s\")" 411 ", ipi_addr=inet_addr(\"%s\")}}]" 412 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n", 413 (unsigned) cmsg->cmsg_len, cmsg_type_str, 414 #ifdef HAVE_IF_INDEXTONAME 415 "if_nametoindex(\"lo\")", 416 #else 417 "1", 418 #endif 419 "1.2.3.4", "5.6.7.8", len, rc, errno2name()); 420 } 421 422 static void 423 test_ip_uint(struct msghdr *const mh, void *const page, 424 const int cmsg_type, const char *const cmsg_type_str) 425 { 426 const unsigned int len = CMSG_SPACE(sizeof(int)); 427 struct cmsghdr *const cmsg = get_cmsghdr(page, len); 428 429 cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 430 cmsg->cmsg_level = SOL_IP; 431 cmsg->cmsg_type = cmsg_type; 432 433 unsigned int *u = (void *) CMSG_DATA(cmsg); 434 *u = 0xfacefeed; 435 436 mh->msg_control = cmsg; 437 mh->msg_controllen = len; 438 439 int rc = sendmsg(-1, mh, 0); 440 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 441 ", msg_iovlen=0, msg_control=[{cmsg_len=%u" 442 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%u]}]" 443 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n", 444 (unsigned) cmsg->cmsg_len, cmsg_type_str, *u, len, 445 rc, errno2name()); 446 } 447 448 static void 449 test_ip_uint8_t(struct msghdr *const mh, void *const page, 450 const int cmsg_type, const char *const cmsg_type_str) 451 { 452 const unsigned int len = CMSG_SPACE(1); 453 struct cmsghdr *const cmsg = get_cmsghdr(page, len); 454 455 cmsg->cmsg_len = CMSG_LEN(1); 456 cmsg->cmsg_level = SOL_IP; 457 cmsg->cmsg_type = cmsg_type; 458 *CMSG_DATA(cmsg) = 'A'; 459 460 mh->msg_control = cmsg; 461 mh->msg_controllen = len; 462 463 int rc = sendmsg(-1, mh, 0); 464 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 465 ", msg_iovlen=0, msg_control=[{cmsg_len=%u" 466 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%#x]}]" 467 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n", 468 (unsigned) cmsg->cmsg_len, cmsg_type_str, 469 (unsigned) (uint8_t) 'A', len, rc, errno2name()); 470 } 471 472 static void 473 print_ip_opts(const void *const cmsg_data, const unsigned int data_len) 474 { 475 const unsigned char *const opts = cmsg_data; 476 unsigned int i; 477 for (i = 0; i < data_len; ++i) { 478 if (i) 479 printf(", "); 480 #if !VERBOSE 481 if (i >= DEFAULT_STRLEN) { 482 printf("..."); 483 break; 484 } 485 #endif 486 printf("0x%02x", opts[i]); 487 } 488 } 489 490 static void 491 test_ip_opts(struct msghdr *const mh, void *const page, 492 const int cmsg_type, const char *const cmsg_type_str, 493 const unsigned int opts_len) 494 { 495 unsigned int len = CMSG_SPACE(opts_len); 496 struct cmsghdr *cmsg = get_cmsghdr(page, len); 497 498 cmsg->cmsg_len = CMSG_LEN(opts_len); 499 cmsg->cmsg_level = SOL_IP; 500 cmsg->cmsg_type = cmsg_type; 501 unsigned int i; 502 for (i = 0; i < opts_len; ++i) 503 CMSG_DATA(cmsg)[i] = 'A' + i; 504 505 mh->msg_control = cmsg; 506 mh->msg_controllen = len; 507 508 int rc = sendmsg(-1, mh, 0); 509 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 510 ", msg_iovlen=0, msg_control=[{cmsg_len=%u" 511 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[", 512 (unsigned) cmsg->cmsg_len, cmsg_type_str); 513 print_ip_opts(CMSG_DATA(cmsg), opts_len); 514 printf("]}], msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n", 515 len, rc, errno2name()); 516 } 517 518 #ifdef IP_CHECKSUM 519 struct sock_ee { 520 uint32_t ee_errno; 521 uint8_t ee_origin; 522 uint8_t ee_type; 523 uint8_t ee_code; 524 uint8_t ee_pad; 525 uint32_t ee_info; 526 uint32_t ee_data; 527 struct sockaddr_in offender; 528 }; 529 530 static void 531 test_ip_recverr(struct msghdr *const mh, void *const page, 532 const int cmsg_type, const char *const cmsg_type_str) 533 { 534 const unsigned int len = CMSG_SPACE(sizeof(struct sock_ee)); 535 struct cmsghdr *const cmsg = get_cmsghdr(page, len); 536 537 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sock_ee)); 538 cmsg->cmsg_level = SOL_IP; 539 cmsg->cmsg_type = cmsg_type; 540 541 struct sock_ee *const e = (struct sock_ee *) CMSG_DATA(cmsg); 542 e->ee_errno = 0xdeadbeef; 543 e->ee_origin = 2; 544 e->ee_type = 3; 545 e->ee_code = 4; 546 e->ee_info = 0xfacefeed; 547 e->ee_data = 0xbadc0ded; 548 e->offender.sin_family = AF_INET, 549 e->offender.sin_port = htons(12345), 550 e->offender.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 551 552 mh->msg_control = cmsg; 553 mh->msg_controllen = len; 554 555 int rc = sendmsg(-1, mh, 0); 556 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 557 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP" 558 ", cmsg_type=%s, cmsg_data={ee_errno=%u, ee_origin=%u" 559 ", ee_type=%u, ee_code=%u, ee_info=%u, ee_data=%u" 560 ", offender={sa_family=AF_INET, sin_port=htons(%hu)" 561 ", sin_addr=inet_addr(\"127.0.0.1\")}}}]" 562 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n", 563 (unsigned) cmsg->cmsg_len, cmsg_type_str, 564 e->ee_errno, e->ee_origin, e->ee_type, 565 e->ee_code, e->ee_info, e->ee_data, 566 ntohs(e->offender.sin_port), 567 len, rc, errno2name()); 568 } 569 #endif 570 571 #ifdef IP_ORIGDSTADDR 572 static void 573 test_ip_origdstaddr(struct msghdr *const mh, void *const page, 574 const int cmsg_type, const char *const cmsg_type_str) 575 { 576 const unsigned int len = CMSG_SPACE(sizeof(struct sockaddr_in)); 577 struct cmsghdr *const cmsg = get_cmsghdr(page, len); 578 579 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sockaddr_in)); 580 cmsg->cmsg_level = SOL_IP; 581 cmsg->cmsg_type = cmsg_type; 582 583 struct sockaddr_in *const sin = (struct sockaddr_in *) CMSG_DATA(cmsg); 584 sin->sin_family = AF_INET, 585 sin->sin_port = htons(12345), 586 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 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, cmsg_level=SOL_IP" 594 ", cmsg_type=%s, cmsg_data={sa_family=AF_INET" 595 ", sin_port=htons(%hu), sin_addr=inet_addr(\"127.0.0.1\")}}]" 596 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n", 597 (unsigned) cmsg->cmsg_len, cmsg_type_str, 598 ntohs(sin->sin_port), len, rc, errno2name()); 599 } 600 #endif 601 602 static void 603 test_sol_ip(struct msghdr *const mh, void *const page) 604 { 605 test_ip_pktinfo(mh, page, ARG_STR(IP_PKTINFO)); 606 test_ip_uint(mh, page, ARG_STR(IP_TTL)); 607 test_ip_uint8_t(mh, page, ARG_STR(IP_TOS)); 608 test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 1); 609 test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 2); 610 test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 3); 611 test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 4); 612 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 5); 613 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 6); 614 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 7); 615 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 8); 616 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), DEFAULT_STRLEN - 1); 617 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), DEFAULT_STRLEN); 618 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), DEFAULT_STRLEN + 1); 619 #ifdef IP_CHECKSUM 620 test_ip_recverr(mh, page, ARG_STR(IP_RECVERR)); 621 #endif 622 #ifdef IP_ORIGDSTADDR 623 test_ip_origdstaddr(mh, page, ARG_STR(IP_ORIGDSTADDR)); 624 #endif 625 #ifdef IP_CHECKSUM 626 test_ip_uint(mh, page, ARG_STR(IP_CHECKSUM)); 627 #endif 628 test_scm_security(mh, CMSG_LEN(0), page, 0, CMSG_LEN(0), 629 ARG_STR(SOL_IP)); 630 test_unknown_type(mh, page, ARG_STR(SOL_IP), "IP_???"); 631 } 632 633 static void 634 test_unknown_level(struct msghdr *const mh, void *const page) 635 { 636 struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0)); 637 638 cmsg->cmsg_len = CMSG_LEN(0); 639 cmsg->cmsg_level = SOL_TCP; 640 cmsg->cmsg_type = 0xdeadbeef; 641 642 mh->msg_control = cmsg; 643 mh->msg_controllen = cmsg->cmsg_len; 644 645 int rc = sendmsg(-1, mh, 0); 646 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 647 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=%s" 648 ", cmsg_type=%#x}], msg_controllen=%u, msg_flags=0}" 649 ", 0) = %d %s (%m)\n", 650 (unsigned) cmsg->cmsg_len, "SOL_TCP", cmsg->cmsg_type, 651 (unsigned) mh->msg_controllen, rc, errno2name()); 652 } 653 654 static void 655 test_big_len(struct msghdr *const mh) 656 { 657 int optmem_max; 658 659 if (read_int_from_file("/proc/sys/net/core/optmem_max", &optmem_max) 660 || optmem_max <= 0 || optmem_max > 0x100000) 661 optmem_max = sizeof(long long) * (2 * IOV_MAX + 512); 662 optmem_max = (optmem_max + sizeof(long long) - 1) 663 & ~(sizeof(long long) - 1); 664 665 const size_t len = optmem_max * 2; 666 struct cmsghdr *const cmsg = tail_alloc(len); 667 cmsg->cmsg_len = len; 668 cmsg->cmsg_level = SOL_SOCKET; 669 cmsg->cmsg_type = SCM_RIGHTS; 670 671 mh->msg_control = cmsg; 672 mh->msg_controllen = len; 673 674 int rc = sendmsg(-1, mh, 0); 675 if (EBADF != errno) 676 perror_msg_and_skip("sendmsg"); 677 678 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 679 ", msg_iovlen=0, msg_control=[{cmsg_len=%u" 680 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS", 681 (unsigned) cmsg->cmsg_len); 682 print_fds(cmsg, optmem_max); 683 printf("}, ...], msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n", 684 (unsigned long) len, rc, errno2name()); 685 } 686 687 int main(int ac, const char **av) 688 { 689 int rc = sendmsg(-1, 0, 0); 690 printf("sendmsg(-1, NULL, 0) = %d %s (%m)\n", rc, errno2name()); 691 692 struct msghdr *mh = tail_alloc(sizeof(*mh)); 693 memset(mh, 0, sizeof(*mh)); 694 test_big_len(mh); 695 696 rc = sendmsg(-1, mh + 1, 0); 697 printf("sendmsg(-1, %p, 0) = %d %s (%m)\n", 698 mh + 1, rc, errno2name()); 699 700 void *page = tail_alloc(1) + 1; 701 mh->msg_control = page; 702 mh->msg_controllen = CMSG_LEN(0); 703 rc = sendmsg(-1, mh, 0); 704 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL" 705 ", msg_iovlen=0, msg_control=%p, msg_controllen=%u" 706 ", msg_flags=0}, 0) = %d %s (%m)\n", 707 page, (unsigned) CMSG_LEN(0), rc, errno2name()); 708 709 test_sol_socket(mh, page); 710 test_sol_ip(mh, page); 711 test_unknown_level(mh, page); 712 713 puts("+++ exited with 0 +++"); 714 return 0; 715 } 716