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.
37 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
50 # define SCM_SECURITY 3
53 #define MIN_SIZE_OF(type, member) \
54 (offsetof(type, member) + sizeof(((type *) 0)->member))
56 static struct cmsghdr *
57 get_cmsghdr(void *const page, const size_t len)
59 return page - CMSG_ALIGN(len);
62 #define DEFAULT_STRLEN 32
65 print_fds(const struct cmsghdr *const cmsg, const size_t cmsg_len)
67 size_t nfd = cmsg_len > CMSG_LEN(0)
68 ? (cmsg_len - CMSG_LEN(0)) / sizeof(int) : 0;
72 printf(", cmsg_data=[");
73 int *fdp = (int *) CMSG_DATA(cmsg);
75 for (i = 0; i < nfd; ++i) {
79 if (i >= DEFAULT_STRLEN) {
90 test_scm_rights1(struct msghdr *const mh,
91 const size_t msg_controllen,
93 const void *const src,
94 const size_t cmsg_len)
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)
102 struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen);
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;
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));
116 mh->msg_control = cmsg;
117 mh->msg_controllen = msg_controllen;
119 int rc = sendmsg(-1, mh, 0);
120 int saved_errno = errno;
122 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
124 if (msg_controllen < CMSG_LEN(0)) {
126 printf(", msg_control=%p", cmsg);
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);
132 if (aligned_cms_len < msg_controllen)
133 printf(", %p", (void *) cmsg + aligned_cms_len);
138 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
139 (unsigned long) msg_controllen, rc, errno2name());
143 test_scm_rights2(struct msghdr *const mh,
144 const size_t msg_controllen,
146 const int *const *const src,
147 const size_t *const cmsg_len)
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)
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)
158 struct cmsghdr *const cmsg[2] = {
159 get_cmsghdr(page, msg_controllen),
160 (void *) get_cmsghdr(page, msg_controllen) + aligned_cms_len[0]
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));
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;
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));
180 mh->msg_control = cmsg[0];
181 mh->msg_controllen = msg_controllen;
183 int rc = sendmsg(-1, mh, 0);
184 int saved_errno = errno;
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);
195 if (aligned_cms_len[1] < msg_controllen1)
196 printf(", %p", (void *) cmsg[1] + aligned_cms_len[1]);
200 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
201 (unsigned long) msg_controllen, rc, errno2name());
205 test_scm_rights3(struct msghdr *const mh, void *const page, const size_t nfds)
207 const size_t len = CMSG_SPACE(sizeof(int) * nfds);
208 struct cmsghdr *cmsg = get_cmsghdr(page, len);
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);
215 for (i = 0; i < nfds; ++i)
218 mh->msg_control = cmsg;
219 mh->msg_controllen = len;
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());
232 print_security(const struct cmsghdr *const cmsg, const size_t cmsg_len)
234 int n = cmsg_len > CMSG_LEN(0) ? cmsg_len - CMSG_LEN(0) : 0;
238 printf(", cmsg_data=\"%.*s\"", n, CMSG_DATA(cmsg));
242 test_scm_security(struct msghdr *const mh,
243 const size_t msg_controllen,
245 const void *const src,
246 const size_t cmsg_len,
247 const int cmsg_level,
248 const char *const cmsg_level_str)
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)
256 struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen);
258 cmsg->cmsg_len = cmsg_len;
259 cmsg->cmsg_level = cmsg_level;
260 cmsg->cmsg_type = SCM_SECURITY;
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));
267 mh->msg_control = cmsg;
268 mh->msg_controllen = msg_controllen;
270 int rc = sendmsg(-1, mh, 0);
271 int saved_errno = errno;
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);
279 if (aligned_cms_len < msg_controllen)
280 printf(", %p", (void *) cmsg + aligned_cms_len);
284 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
285 (unsigned long) msg_controllen, rc, errno2name());
289 test_unknown_type(struct msghdr *const mh,
291 const int cmsg_level,
292 const char *const cmsg_level_str,
293 const char *const cmsg_type_str)
295 struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0));
297 cmsg->cmsg_len = CMSG_LEN(0);
298 cmsg->cmsg_level = cmsg_level;
299 cmsg->cmsg_type = 0xfacefeed;
301 mh->msg_control = cmsg;
302 mh->msg_controllen = cmsg->cmsg_len;
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());
314 test_sol_socket(struct msghdr *const mh, void *const page)
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;
320 max_msg_controllen = CMSG_SPACE(sizeof(fds0)) + sizeof(*fds0) - 1;
321 for (msg_controllen = 0;
322 msg_controllen <= max_msg_controllen;
327 cmsg_len <= msg_controllen + CMSG_LEN(0);
329 test_scm_rights1(mh, msg_controllen,
330 page, fds0, cmsg_len);
335 CMSG_SPACE(sizeof(fds0)) + CMSG_SPACE(sizeof(fds1)) +
337 for (msg_controllen = CMSG_LEN(0) * 2;
338 msg_controllen <= max_msg_controllen;
340 static const int *const fdps[] = { fds0, fds1 };
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));
347 const size_t msg_controllen1 =
348 msg_controllen - CMSG_ALIGN(cmsg_len[0]);
350 for (cmsg_len[1] = 0;
351 cmsg_len[1] <= msg_controllen1 + CMSG_LEN(0);
353 test_scm_rights2(mh, msg_controllen,
354 page, fdps, cmsg_len);
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;
367 cmsg_len <= msg_controllen + CMSG_LEN(0)
368 && cmsg_len <= CMSG_LEN(sizeof(text));
370 test_scm_security(mh, msg_controllen,
371 page, text, cmsg_len,
372 ARG_STR(SOL_SOCKET));
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);
380 test_unknown_type(mh, page, ARG_STR(SOL_SOCKET), "SCM_???");
384 test_ip_pktinfo(struct msghdr *const mh, void *const page,
385 const int cmsg_type, const char *const cmsg_type_str)
387 const unsigned int len = CMSG_SPACE(sizeof(struct in_pktinfo));
388 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
390 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
391 cmsg->cmsg_level = SOL_IP;
392 cmsg->cmsg_type = cmsg_type;
394 struct in_pktinfo *const info = (struct in_pktinfo *) CMSG_DATA(cmsg);
395 #ifdef HAVE_IF_INDEXTONAME
396 info->ipi_ifindex = if_nametoindex("lo");
398 info->ipi_ifindex = 1;
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");
403 mh->msg_control = cmsg;
404 mh->msg_controllen = len;
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\")",
419 "1.2.3.4", "5.6.7.8", len, rc, errno2name());
423 test_ip_uint(struct msghdr *const mh, void *const page,
424 const int cmsg_type, const char *const cmsg_type_str)
426 const unsigned int len = CMSG_SPACE(sizeof(int));
427 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
429 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
430 cmsg->cmsg_level = SOL_IP;
431 cmsg->cmsg_type = cmsg_type;
433 unsigned int *u = (void *) CMSG_DATA(cmsg);
436 mh->msg_control = cmsg;
437 mh->msg_controllen = len;
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,
449 test_ip_uint8_t(struct msghdr *const mh, void *const page,
450 const int cmsg_type, const char *const cmsg_type_str)
452 const unsigned int len = CMSG_SPACE(1);
453 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
455 cmsg->cmsg_len = CMSG_LEN(1);
456 cmsg->cmsg_level = SOL_IP;
457 cmsg->cmsg_type = cmsg_type;
458 *CMSG_DATA(cmsg) = 'A';
460 mh->msg_control = cmsg;
461 mh->msg_controllen = len;
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());
473 print_ip_opts(const void *const cmsg_data, const unsigned int data_len)
475 const unsigned char *const opts = cmsg_data;
477 for (i = 0; i < data_len; ++i) {
481 if (i >= DEFAULT_STRLEN) {
486 printf("0x%02x", opts[i]);
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)
495 unsigned int len = CMSG_SPACE(opts_len);
496 struct cmsghdr *cmsg = get_cmsghdr(page, len);
498 cmsg->cmsg_len = CMSG_LEN(opts_len);
499 cmsg->cmsg_level = SOL_IP;
500 cmsg->cmsg_type = cmsg_type;
502 for (i = 0; i < opts_len; ++i)
503 CMSG_DATA(cmsg)[i] = 'A' + i;
505 mh->msg_control = cmsg;
506 mh->msg_controllen = len;
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());
527 struct sockaddr_in offender;
531 test_ip_recverr(struct msghdr *const mh, void *const page,
532 const int cmsg_type, const char *const cmsg_type_str)
534 const unsigned int len = CMSG_SPACE(sizeof(struct sock_ee));
535 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
537 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sock_ee));
538 cmsg->cmsg_level = SOL_IP;
539 cmsg->cmsg_type = cmsg_type;
541 struct sock_ee *const e = (struct sock_ee *) CMSG_DATA(cmsg);
542 e->ee_errno = 0xdeadbeef;
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);
552 mh->msg_control = cmsg;
553 mh->msg_controllen = len;
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());
571 #ifdef IP_ORIGDSTADDR
573 test_ip_origdstaddr(struct msghdr *const mh, void *const page,
574 const int cmsg_type, const char *const cmsg_type_str)
576 const unsigned int len = CMSG_SPACE(sizeof(struct sockaddr_in));
577 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
579 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sockaddr_in));
580 cmsg->cmsg_level = SOL_IP;
581 cmsg->cmsg_type = cmsg_type;
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);
588 mh->msg_control = cmsg;
589 mh->msg_controllen = len;
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());
603 test_sol_ip(struct msghdr *const mh, void *const page)
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);
620 test_ip_recverr(mh, page, ARG_STR(IP_RECVERR));
622 #ifdef IP_ORIGDSTADDR
623 test_ip_origdstaddr(mh, page, ARG_STR(IP_ORIGDSTADDR));
626 test_ip_uint(mh, page, ARG_STR(IP_CHECKSUM));
628 test_scm_security(mh, CMSG_LEN(0), page, 0, CMSG_LEN(0),
630 test_unknown_type(mh, page, ARG_STR(SOL_IP), "IP_???");
634 test_unknown_level(struct msghdr *const mh, void *const page)
636 struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0));
638 cmsg->cmsg_len = CMSG_LEN(0);
639 cmsg->cmsg_level = SOL_TCP;
640 cmsg->cmsg_type = 0xdeadbeef;
642 mh->msg_control = cmsg;
643 mh->msg_controllen = cmsg->cmsg_len;
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());
655 test_big_len(struct msghdr *const mh)
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);
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;
671 mh->msg_control = cmsg;
672 mh->msg_controllen = len;
674 int rc = sendmsg(-1, mh, 0);
676 perror_msg_and_skip("sendmsg");
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());
687 int main(int ac, const char **av)
689 int rc = sendmsg(-1, 0, 0);
690 printf("sendmsg(-1, NULL, 0) = %d %s (%m)\n", rc, errno2name());
692 struct msghdr *mh = tail_alloc(sizeof(*mh));
693 memset(mh, 0, sizeof(*mh));
696 rc = sendmsg(-1, mh + 1, 0);
697 printf("sendmsg(-1, %p, 0) = %d %s (%m)\n",
698 mh + 1, rc, errno2name());
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());
709 test_sol_socket(mh, page);
710 test_sol_ip(mh, page);
711 test_unknown_level(mh, page);
713 puts("+++ exited with 0 +++");