2 * Check decoding of struct msghdr ancillary data.
4 * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
36 #include <sys/socket.h>
38 #include <netinet/in.h>
39 #include <arpa/inet.h>
49 # define SCM_SECURITY 3
53 # define UIO_MAXIOV 1024
56 #define MIN_SIZE_OF(type, member) \
57 (offsetof(type, member) + sizeof(((type *) 0)->member))
59 #define VAL_STR(val) val, #val
61 static struct cmsghdr *
62 get_cmsghdr(void *const page, const size_t len)
64 return page - CMSG_ALIGN(len);
67 #define DEFAULT_STRLEN 32
70 print_fds(const struct cmsghdr *const cmsg, const size_t cmsg_len)
72 size_t nfd = cmsg_len > CMSG_LEN(0)
73 ? (cmsg_len - CMSG_LEN(0)) / sizeof(int) : 0;
77 printf(", cmsg_data=[");
78 int *fdp = (int *) CMSG_DATA(cmsg);
80 for (i = 0; i < nfd; ++i) {
83 #ifndef VERBOSE_MSGHDR
84 if (i >= DEFAULT_STRLEN) {
95 test_scm_rights1(struct msghdr *const mh,
96 const size_t msg_controllen,
98 const void *const src,
99 const size_t cmsg_len)
101 const size_t aligned_cms_len =
102 cmsg_len > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len) : CMSG_LEN(0);
103 if (cmsg_len >= CMSG_LEN(0)
104 && aligned_cms_len + CMSG_LEN(0) <= msg_controllen)
107 struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen);
109 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_len))
110 cmsg->cmsg_len = cmsg_len;
111 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_level))
112 cmsg->cmsg_level = SOL_SOCKET;
113 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_type))
114 cmsg->cmsg_type = SCM_RIGHTS;
117 cmsg_len < msg_controllen ? cmsg_len : msg_controllen;
118 if (src_len > CMSG_LEN(0))
119 memcpy(CMSG_DATA(cmsg), src, src_len - CMSG_LEN(0));
121 mh->msg_control = cmsg;
122 mh->msg_controllen = msg_controllen;
124 int rc = sendmsg(-1, mh, 0);
125 int saved_errno = errno;
127 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
129 if (msg_controllen < CMSG_LEN(0)) {
131 printf(", msg_control=%p", cmsg);
133 printf(", msg_control=[{cmsg_len=%lu, cmsg_level=SOL_SOCKET"
134 ", cmsg_type=SCM_RIGHTS", (unsigned long) cmsg_len);
135 print_fds(cmsg, src_len);
137 if (aligned_cms_len < msg_controllen)
138 printf(", %p", (void *) cmsg + aligned_cms_len);
143 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
144 (unsigned long) msg_controllen, rc, errno2name());
148 test_scm_rights2(struct msghdr *const mh,
149 const size_t msg_controllen,
151 const int *const *const src,
152 const size_t *const cmsg_len)
154 const size_t aligned_cms_len[2] = {
155 cmsg_len[0] > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len[0]) : CMSG_LEN(0),
156 cmsg_len[1] > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len[1]) : CMSG_LEN(0)
158 if (cmsg_len[0] < CMSG_LEN(0)
159 || aligned_cms_len[0] + CMSG_LEN(0) > msg_controllen
160 || aligned_cms_len[0] + aligned_cms_len[1] + CMSG_LEN(0) <= msg_controllen)
163 struct cmsghdr *const cmsg[2] = {
164 get_cmsghdr(page, msg_controllen),
165 (void *) get_cmsghdr(page, msg_controllen) + aligned_cms_len[0]
167 cmsg[0]->cmsg_len = cmsg_len[0];
168 cmsg[0]->cmsg_level = SOL_SOCKET;
169 cmsg[0]->cmsg_type = SCM_RIGHTS;
170 if (cmsg_len[0] > CMSG_LEN(0))
171 memcpy(CMSG_DATA(cmsg[0]), src[0], cmsg_len[0] - CMSG_LEN(0));
173 const size_t msg_controllen1 = msg_controllen - aligned_cms_len[0];
174 if (msg_controllen1 >= MIN_SIZE_OF(struct cmsghdr, cmsg_len))
175 cmsg[1]->cmsg_len = cmsg_len[1];
176 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_level))
177 cmsg[1]->cmsg_level = SOL_SOCKET;
178 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_type))
179 cmsg[1]->cmsg_type = SCM_RIGHTS;
181 cmsg_len[1] < msg_controllen1 ? cmsg_len[1] : msg_controllen1;
182 if (src1_len > CMSG_LEN(0))
183 memcpy(CMSG_DATA(cmsg[1]), src[1], src1_len - CMSG_LEN(0));
185 mh->msg_control = cmsg[0];
186 mh->msg_controllen = msg_controllen;
188 int rc = sendmsg(-1, mh, 0);
189 int saved_errno = errno;
191 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
192 ", msg_iovlen=0, msg_control=[{cmsg_len=%lu"
193 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
194 (unsigned long) cmsg_len[0]);
195 print_fds(cmsg[0], cmsg_len[0]);
196 printf("}, {cmsg_len=%lu, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
197 (unsigned long) cmsg_len[1]);
198 print_fds(cmsg[1], src1_len);
200 if (aligned_cms_len[1] < msg_controllen1)
201 printf(", %p", (void *) cmsg[1] + aligned_cms_len[1]);
205 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
206 (unsigned long) msg_controllen, rc, errno2name());
210 test_scm_rights3(struct msghdr *const mh, void *const page, const size_t nfds)
212 const size_t len = CMSG_SPACE(sizeof(int) * nfds);
213 struct cmsghdr *cmsg = get_cmsghdr(page, len);
215 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * nfds);
216 cmsg->cmsg_level = SOL_SOCKET;
217 cmsg->cmsg_type = SCM_RIGHTS;
218 int *fdp = (int *) CMSG_DATA(cmsg);
220 for (i = 0; i < nfds; ++i)
223 mh->msg_control = cmsg;
224 mh->msg_controllen = len;
226 int rc = sendmsg(-1, mh, 0);
227 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
228 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
229 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
230 (unsigned) cmsg->cmsg_len);
231 print_fds(cmsg, cmsg->cmsg_len);
232 printf("}], msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
233 (unsigned long) len, rc, errno2name());
237 print_security(const struct cmsghdr *const cmsg, const size_t cmsg_len)
239 int n = cmsg_len > CMSG_LEN(0) ? cmsg_len - CMSG_LEN(0) : 0;
243 printf(", cmsg_data=\"%.*s\"", n, CMSG_DATA(cmsg));
247 test_scm_security(struct msghdr *const mh,
248 const size_t msg_controllen,
250 const void *const src,
251 const size_t cmsg_len,
252 const int cmsg_level,
253 const char *const cmsg_level_str)
255 const size_t aligned_cms_len =
256 cmsg_len > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len) : CMSG_LEN(0);
257 if (cmsg_len >= CMSG_LEN(0)
258 && aligned_cms_len + CMSG_LEN(0) <= msg_controllen)
261 struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen);
263 cmsg->cmsg_len = cmsg_len;
264 cmsg->cmsg_level = cmsg_level;
265 cmsg->cmsg_type = SCM_SECURITY;
268 cmsg_len < msg_controllen ? cmsg_len : msg_controllen;
269 if (src_len > CMSG_LEN(0))
270 memcpy(CMSG_DATA(cmsg), src, src_len - CMSG_LEN(0));
272 mh->msg_control = cmsg;
273 mh->msg_controllen = msg_controllen;
275 int rc = sendmsg(-1, mh, 0);
276 int saved_errno = errno;
278 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
279 ", msg_iovlen=0, msg_control=[{cmsg_len=%lu, cmsg_level=%s"
280 ", cmsg_type=SCM_SECURITY",
281 (unsigned long) cmsg_len, cmsg_level_str);
282 print_security(cmsg, src_len);
284 if (aligned_cms_len < msg_controllen)
285 printf(", %p", (void *) cmsg + aligned_cms_len);
289 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
290 (unsigned long) msg_controllen, rc, errno2name());
294 test_unknown_type(struct msghdr *const mh,
296 const int cmsg_level,
297 const char *const cmsg_level_str,
298 const char *const cmsg_type_str)
300 struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0));
302 cmsg->cmsg_len = CMSG_LEN(0);
303 cmsg->cmsg_level = cmsg_level;
304 cmsg->cmsg_type = 0xfacefeed;
306 mh->msg_control = cmsg;
307 mh->msg_controllen = cmsg->cmsg_len;
309 int rc = sendmsg(-1, mh, 0);
310 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
311 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=%s"
312 ", cmsg_type=%#x /* %s */}], msg_controllen=%u, msg_flags=0}"
313 ", 0) = %d %s (%m)\n",
314 (unsigned) cmsg->cmsg_len, cmsg_level_str, cmsg->cmsg_type,
315 cmsg_type_str, (unsigned) mh->msg_controllen, rc, errno2name());
319 test_sol_socket(struct msghdr *const mh, void *const page)
321 static const int fds0[] = { -10, -11, -12, -13 };
322 static const int fds1[] = { -15, -16, -17, -18 };
323 size_t msg_controllen, max_msg_controllen;
325 max_msg_controllen = CMSG_SPACE(sizeof(fds0)) + sizeof(*fds0) - 1;
326 for (msg_controllen = 0;
327 msg_controllen <= max_msg_controllen;
332 cmsg_len <= msg_controllen + CMSG_LEN(0);
334 test_scm_rights1(mh, msg_controllen,
335 page, fds0, cmsg_len);
340 CMSG_SPACE(sizeof(fds0)) + CMSG_SPACE(sizeof(fds1)) +
342 for (msg_controllen = CMSG_LEN(0) * 2;
343 msg_controllen <= max_msg_controllen;
345 static const int *const fdps[] = { fds0, fds1 };
348 for (cmsg_len[0] = CMSG_LEN(0);
349 CMSG_ALIGN(cmsg_len[0]) + CMSG_LEN(0) <= msg_controllen
350 && CMSG_ALIGN(cmsg_len[0]) <= CMSG_SPACE(sizeof(fds0));
352 const size_t msg_controllen1 =
353 msg_controllen - CMSG_ALIGN(cmsg_len[0]);
355 for (cmsg_len[1] = 0;
356 cmsg_len[1] <= msg_controllen1 + CMSG_LEN(0);
358 test_scm_rights2(mh, msg_controllen,
359 page, fdps, cmsg_len);
364 static const char text[16] = "0123456789abcdef";
365 max_msg_controllen = CMSG_SPACE(sizeof(text)) + CMSG_LEN(0) - 1;
366 for (msg_controllen = CMSG_LEN(0);
367 msg_controllen <= max_msg_controllen;
372 cmsg_len <= msg_controllen + CMSG_LEN(0)
373 && cmsg_len <= CMSG_LEN(sizeof(text));
375 test_scm_security(mh, msg_controllen,
376 page, text, cmsg_len,
377 VAL_STR(SOL_SOCKET));
381 test_scm_rights3(mh, page, DEFAULT_STRLEN - 1);
382 test_scm_rights3(mh, page, DEFAULT_STRLEN);
383 test_scm_rights3(mh, page, DEFAULT_STRLEN + 1);
385 test_unknown_type(mh, page, VAL_STR(SOL_SOCKET), "SCM_???");
389 test_ip_pktinfo(struct msghdr *const mh, void *const page,
390 const int cmsg_type, const char *const cmsg_type_str)
392 const unsigned int len = CMSG_SPACE(sizeof(struct in_pktinfo));
393 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
395 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
396 cmsg->cmsg_level = SOL_IP;
397 cmsg->cmsg_type = cmsg_type;
399 struct in_pktinfo *const info = (struct in_pktinfo *) CMSG_DATA(cmsg);
400 #ifdef HAVE_IF_INDEXTONAME
401 info->ipi_ifindex = if_nametoindex("lo");
403 info->ipi_ifindex = 1;
405 info->ipi_spec_dst.s_addr = inet_addr("1.2.3.4");
406 info->ipi_addr.s_addr = inet_addr("5.6.7.8");
408 mh->msg_control = cmsg;
409 mh->msg_controllen = len;
411 int rc = sendmsg(-1, mh, 0);
412 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
413 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
414 ", cmsg_type=%s, cmsg_data={ipi_ifindex=%s"
415 ", ipi_spec_dst=inet_addr(\"%s\")"
416 ", ipi_addr=inet_addr(\"%s\")}}]"
417 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
418 (unsigned) cmsg->cmsg_len, cmsg_type_str,
419 #ifdef HAVE_IF_INDEXTONAME
420 "if_nametoindex(\"lo\")",
424 "1.2.3.4", "5.6.7.8", len, rc, errno2name());
428 test_ip_uint(struct msghdr *const mh, void *const page,
429 const int cmsg_type, const char *const cmsg_type_str)
431 const unsigned int len = CMSG_SPACE(sizeof(int));
432 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
434 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
435 cmsg->cmsg_level = SOL_IP;
436 cmsg->cmsg_type = cmsg_type;
438 unsigned int *u = (void *) CMSG_DATA(cmsg);
441 mh->msg_control = cmsg;
442 mh->msg_controllen = len;
444 int rc = sendmsg(-1, mh, 0);
445 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
446 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
447 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%u]}]"
448 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
449 (unsigned) cmsg->cmsg_len, cmsg_type_str, *u, len,
454 test_ip_uint8_t(struct msghdr *const mh, void *const page,
455 const int cmsg_type, const char *const cmsg_type_str)
457 const unsigned int len = CMSG_SPACE(1);
458 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
460 cmsg->cmsg_len = CMSG_LEN(1);
461 cmsg->cmsg_level = SOL_IP;
462 cmsg->cmsg_type = cmsg_type;
463 *CMSG_DATA(cmsg) = 'A';
465 mh->msg_control = cmsg;
466 mh->msg_controllen = len;
468 int rc = sendmsg(-1, mh, 0);
469 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
470 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
471 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%#x]}]"
472 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
473 (unsigned) cmsg->cmsg_len, cmsg_type_str,
474 (unsigned) (uint8_t) 'A', len, rc, errno2name());
478 print_ip_opts(const void *const cmsg_data, const unsigned int data_len)
480 const unsigned char *const opts = cmsg_data;
482 for (i = 0; i < data_len; ++i) {
485 #ifndef VERBOSE_MSGHDR
486 if (i >= DEFAULT_STRLEN) {
491 printf("0x%02x", opts[i]);
496 test_ip_opts(struct msghdr *const mh, void *const page,
497 const int cmsg_type, const char *const cmsg_type_str,
498 const unsigned int opts_len)
500 unsigned int len = CMSG_SPACE(opts_len);
501 struct cmsghdr *cmsg = get_cmsghdr(page, len);
503 cmsg->cmsg_len = CMSG_LEN(opts_len);
504 cmsg->cmsg_level = SOL_IP;
505 cmsg->cmsg_type = cmsg_type;
507 for (i = 0; i < opts_len; ++i)
508 CMSG_DATA(cmsg)[i] = 'A' + i;
510 mh->msg_control = cmsg;
511 mh->msg_controllen = len;
513 int rc = sendmsg(-1, mh, 0);
514 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
515 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
516 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[",
517 (unsigned) cmsg->cmsg_len, cmsg_type_str);
518 print_ip_opts(CMSG_DATA(cmsg), opts_len);
519 printf("]}], msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
520 len, rc, errno2name());
532 struct sockaddr_in offender;
536 test_ip_recverr(struct msghdr *const mh, void *const page,
537 const int cmsg_type, const char *const cmsg_type_str)
539 const unsigned int len = CMSG_SPACE(sizeof(struct sock_ee));
540 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
542 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sock_ee));
543 cmsg->cmsg_level = SOL_IP;
544 cmsg->cmsg_type = cmsg_type;
546 struct sock_ee *const e = (struct sock_ee *) CMSG_DATA(cmsg);
547 e->ee_errno = 0xdeadbeef;
551 e->ee_info = 0xfacefeed;
552 e->ee_data = 0xbadc0ded;
553 e->offender.sin_family = AF_INET,
554 e->offender.sin_port = htons(12345),
555 e->offender.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
557 mh->msg_control = cmsg;
558 mh->msg_controllen = len;
560 int rc = sendmsg(-1, mh, 0);
561 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
562 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
563 ", cmsg_type=%s, cmsg_data={ee_errno=%u, ee_origin=%u"
564 ", ee_type=%u, ee_code=%u, ee_info=%u, ee_data=%u"
565 ", offender={sa_family=AF_INET, sin_port=htons(%hu)"
566 ", sin_addr=inet_addr(\"127.0.0.1\")}}}]"
567 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
568 (unsigned) cmsg->cmsg_len, cmsg_type_str,
569 e->ee_errno, e->ee_origin, e->ee_type,
570 e->ee_code, e->ee_info, e->ee_data,
571 ntohs(e->offender.sin_port),
572 len, rc, errno2name());
576 #ifdef IP_ORIGDSTADDR
578 test_ip_origdstaddr(struct msghdr *const mh, void *const page,
579 const int cmsg_type, const char *const cmsg_type_str)
581 const unsigned int len = CMSG_SPACE(sizeof(struct sockaddr_in));
582 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
584 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sockaddr_in));
585 cmsg->cmsg_level = SOL_IP;
586 cmsg->cmsg_type = cmsg_type;
588 struct sockaddr_in *const sin = (struct sockaddr_in *) CMSG_DATA(cmsg);
589 sin->sin_family = AF_INET,
590 sin->sin_port = htons(12345),
591 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
593 mh->msg_control = cmsg;
594 mh->msg_controllen = len;
596 int rc = sendmsg(-1, mh, 0);
597 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
598 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
599 ", cmsg_type=%s, cmsg_data={sa_family=AF_INET"
600 ", sin_port=htons(%hu), sin_addr=inet_addr(\"127.0.0.1\")}}]"
601 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
602 (unsigned) cmsg->cmsg_len, cmsg_type_str,
603 ntohs(sin->sin_port), len, rc, errno2name());
608 test_sol_ip(struct msghdr *const mh, void *const page)
610 test_ip_pktinfo(mh, page, VAL_STR(IP_PKTINFO));
611 test_ip_uint(mh, page, VAL_STR(IP_TTL));
612 test_ip_uint8_t(mh, page, VAL_STR(IP_TOS));
613 test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 1);
614 test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 2);
615 test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 3);
616 test_ip_opts(mh, page, VAL_STR(IP_RECVOPTS), 4);
617 test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 5);
618 test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 6);
619 test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 7);
620 test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), 8);
621 test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), DEFAULT_STRLEN - 1);
622 test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), DEFAULT_STRLEN);
623 test_ip_opts(mh, page, VAL_STR(IP_RETOPTS), DEFAULT_STRLEN + 1);
625 test_ip_recverr(mh, page, VAL_STR(IP_RECVERR));
627 #ifdef IP_ORIGDSTADDR
628 test_ip_origdstaddr(mh, page, VAL_STR(IP_ORIGDSTADDR));
631 test_ip_uint(mh, page, VAL_STR(IP_CHECKSUM));
633 test_scm_security(mh, CMSG_LEN(0), page, 0, CMSG_LEN(0),
635 test_unknown_type(mh, page, VAL_STR(SOL_IP), "IP_???");
639 test_unknown_level(struct msghdr *const mh, void *const page)
641 struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0));
643 cmsg->cmsg_len = CMSG_LEN(0);
644 cmsg->cmsg_level = SOL_TCP;
645 cmsg->cmsg_type = 0xdeadbeef;
647 mh->msg_control = cmsg;
648 mh->msg_controllen = cmsg->cmsg_len;
650 int rc = sendmsg(-1, mh, 0);
651 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
652 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=%s"
653 ", cmsg_type=%#x}], msg_controllen=%u, msg_flags=0}"
654 ", 0) = %d %s (%m)\n",
655 (unsigned) cmsg->cmsg_len, "SOL_TCP", cmsg->cmsg_type,
656 (unsigned) mh->msg_controllen, rc, errno2name());
660 test_big_len(struct msghdr *const mh)
664 if (read_int_from_file("/proc/sys/net/core/optmem_max", &optmem_max)
665 || optmem_max <= 0 || optmem_max > 0x100000)
666 optmem_max = sizeof(long long) * (2 * UIO_MAXIOV + 512);
667 optmem_max = (optmem_max + sizeof(long long) - 1)
668 & ~(sizeof(long long) - 1);
670 const size_t len = optmem_max * 2;
671 struct cmsghdr *const cmsg = tail_alloc(len);
672 cmsg->cmsg_len = len;
673 cmsg->cmsg_level = SOL_SOCKET;
674 cmsg->cmsg_type = SCM_RIGHTS;
676 mh->msg_control = cmsg;
677 mh->msg_controllen = len;
679 int rc = sendmsg(-1, mh, 0);
681 perror_msg_and_skip("sendmsg");
683 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
684 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
685 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
686 (unsigned) cmsg->cmsg_len);
687 print_fds(cmsg, optmem_max);
688 printf("}, ...], msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
689 (unsigned long) len, rc, errno2name());
692 int main(int ac, const char **av)
694 int rc = sendmsg(-1, 0, 0);
695 printf("sendmsg(-1, NULL, 0) = %d %s (%m)\n", rc, errno2name());
697 struct msghdr *mh = tail_alloc(sizeof(*mh));
698 memset(mh, 0, sizeof(*mh));
701 rc = sendmsg(-1, mh + 1, 0);
702 printf("sendmsg(-1, %p, 0) = %d %s (%m)\n",
703 mh + 1, rc, errno2name());
705 void *page = tail_alloc(1) + 1;
706 mh->msg_control = page;
707 mh->msg_controllen = CMSG_LEN(0);
708 rc = sendmsg(-1, mh, 0);
709 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
710 ", msg_iovlen=0, msg_control=%p, msg_controllen=%u"
711 ", msg_flags=0}, 0) = %d %s (%m)\n",
712 page, (unsigned) CMSG_LEN(0), rc, errno2name());
714 test_sol_socket(mh, page);
715 test_sol_ip(mh, page);
716 test_unknown_level(mh, page);
718 puts("+++ exited with 0 +++");