2 * Check decoding of struct msghdr ancillary data.
4 * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
5 * Copyright (c) 2016-2017 The strace developers.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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.
38 #include <sys/socket.h>
40 #include <netinet/in.h>
41 #include <arpa/inet.h>
44 #include "xlat/scmvals.h"
54 # define SCM_SECURITY 3
57 #define MIN_SIZE_OF(type, member) \
58 (offsetof(type, member) + sizeof(((type *) 0)->member))
60 static struct cmsghdr *
61 get_cmsghdr(void *const page, const size_t len)
63 return page - CMSG_ALIGN(len);
66 #define DEFAULT_STRLEN 32
69 print_fds(const struct cmsghdr *const cmsg, const size_t cmsg_len)
71 size_t nfd = cmsg_len > CMSG_LEN(0)
72 ? (cmsg_len - CMSG_LEN(0)) / sizeof(int) : 0;
76 printf(", cmsg_data=[");
77 int *fdp = (int *) CMSG_DATA(cmsg);
79 for (i = 0; i < nfd; ++i) {
83 if (i >= DEFAULT_STRLEN) {
94 test_scm_rights1(struct msghdr *const mh,
95 const size_t msg_controllen,
97 const void *const src,
98 const size_t cmsg_len)
100 const size_t aligned_cms_len =
101 cmsg_len > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len) : CMSG_LEN(0);
102 if (cmsg_len >= CMSG_LEN(0)
103 && aligned_cms_len + CMSG_LEN(0) <= msg_controllen)
106 struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen);
108 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_len))
109 cmsg->cmsg_len = cmsg_len;
110 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_level))
111 cmsg->cmsg_level = SOL_SOCKET;
112 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_type))
113 cmsg->cmsg_type = SCM_RIGHTS;
116 cmsg_len < msg_controllen ? cmsg_len : msg_controllen;
117 if (src_len > CMSG_LEN(0))
118 memcpy(CMSG_DATA(cmsg), src, src_len - CMSG_LEN(0));
120 mh->msg_control = cmsg;
121 mh->msg_controllen = msg_controllen;
123 int rc = sendmsg(-1, mh, 0);
124 int saved_errno = errno;
126 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
128 if (msg_controllen < CMSG_LEN(0)) {
130 printf(", msg_control=%p", cmsg);
132 printf(", msg_control=[{cmsg_len=%lu, cmsg_level=SOL_SOCKET"
133 ", cmsg_type=SCM_RIGHTS", (unsigned long) cmsg_len);
134 print_fds(cmsg, src_len);
136 if (aligned_cms_len < msg_controllen)
137 printf(", %p", (void *) cmsg + aligned_cms_len);
142 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
143 (unsigned long) msg_controllen, rc, errno2name());
147 test_scm_rights2(struct msghdr *const mh,
148 const size_t msg_controllen,
150 const int *const *const src,
151 const size_t *const cmsg_len)
153 const size_t aligned_cms_len[2] = {
154 cmsg_len[0] > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len[0]) : CMSG_LEN(0),
155 cmsg_len[1] > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len[1]) : CMSG_LEN(0)
157 if (cmsg_len[0] < CMSG_LEN(0)
158 || aligned_cms_len[0] + CMSG_LEN(0) > msg_controllen
159 || aligned_cms_len[0] + aligned_cms_len[1] + CMSG_LEN(0) <= msg_controllen)
162 struct cmsghdr *const cmsg[2] = {
163 get_cmsghdr(page, msg_controllen),
164 (void *) get_cmsghdr(page, msg_controllen) + aligned_cms_len[0]
166 cmsg[0]->cmsg_len = cmsg_len[0];
167 cmsg[0]->cmsg_level = SOL_SOCKET;
168 cmsg[0]->cmsg_type = SCM_RIGHTS;
169 if (cmsg_len[0] > CMSG_LEN(0))
170 memcpy(CMSG_DATA(cmsg[0]), src[0], cmsg_len[0] - CMSG_LEN(0));
172 const size_t msg_controllen1 = msg_controllen - aligned_cms_len[0];
173 if (msg_controllen1 >= MIN_SIZE_OF(struct cmsghdr, cmsg_len))
174 cmsg[1]->cmsg_len = cmsg_len[1];
175 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_level))
176 cmsg[1]->cmsg_level = SOL_SOCKET;
177 if (msg_controllen >= MIN_SIZE_OF(struct cmsghdr, cmsg_type))
178 cmsg[1]->cmsg_type = SCM_RIGHTS;
180 cmsg_len[1] < msg_controllen1 ? cmsg_len[1] : msg_controllen1;
181 if (src1_len > CMSG_LEN(0))
182 memcpy(CMSG_DATA(cmsg[1]), src[1], src1_len - CMSG_LEN(0));
184 mh->msg_control = cmsg[0];
185 mh->msg_controllen = msg_controllen;
187 int rc = sendmsg(-1, mh, 0);
188 int saved_errno = errno;
190 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
191 ", msg_iovlen=0, msg_control=[{cmsg_len=%lu"
192 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
193 (unsigned long) cmsg_len[0]);
194 print_fds(cmsg[0], cmsg_len[0]);
195 printf("}, {cmsg_len=%lu, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
196 (unsigned long) cmsg_len[1]);
197 print_fds(cmsg[1], src1_len);
199 if (aligned_cms_len[1] < msg_controllen1)
200 printf(", %p", (void *) cmsg[1] + aligned_cms_len[1]);
204 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
205 (unsigned long) msg_controllen, rc, errno2name());
209 test_scm_rights3(struct msghdr *const mh, void *const page, const size_t nfds)
211 const size_t len = CMSG_SPACE(sizeof(int) * nfds);
212 struct cmsghdr *cmsg = get_cmsghdr(page, len);
214 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * nfds);
215 cmsg->cmsg_level = SOL_SOCKET;
216 cmsg->cmsg_type = SCM_RIGHTS;
217 int *fdp = (int *) CMSG_DATA(cmsg);
219 for (i = 0; i < nfds; ++i)
222 mh->msg_control = cmsg;
223 mh->msg_controllen = len;
225 int rc = sendmsg(-1, mh, 0);
226 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
227 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
228 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
229 (unsigned) cmsg->cmsg_len);
230 print_fds(cmsg, cmsg->cmsg_len);
231 printf("}], msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
232 (unsigned long) len, rc, errno2name());
236 test_scm_timestamp(struct msghdr *const mh, void *const page)
238 size_t len = CMSG_SPACE(sizeof(struct timeval));
239 struct cmsghdr *cmsg = get_cmsghdr(page, len);
241 cmsg->cmsg_len = CMSG_LEN(sizeof(struct timeval));
242 cmsg->cmsg_level = SOL_SOCKET;
243 cmsg->cmsg_type = SCM_TIMESTAMP;
244 struct timeval *tv = (struct timeval *) CMSG_DATA(cmsg);
245 tv->tv_sec = 123456789;
246 tv->tv_usec = 987654;
248 mh->msg_control = cmsg;
249 mh->msg_controllen = len;
251 int rc = sendmsg(-1, mh, 0);
252 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
253 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
254 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMP"
255 ", cmsg_data={tv_sec=%lld, tv_usec=%llu}}]"
256 ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
257 (unsigned) cmsg->cmsg_len,
258 (long long) tv->tv_sec, zero_extend_signed_to_ull(tv->tv_usec),
259 (unsigned long) len, rc, errno2name());
261 len = CMSG_SPACE(sizeof(struct timeval) - sizeof(long));
262 cmsg = get_cmsghdr(page, len);
264 cmsg->cmsg_len = CMSG_LEN(sizeof(struct timeval) - sizeof(long));
265 cmsg->cmsg_level = SOL_SOCKET;
266 cmsg->cmsg_type = SCM_TIMESTAMP;
268 mh->msg_control = cmsg;
269 mh->msg_controllen = len;
271 rc = sendmsg(-1, mh, 0);
272 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
273 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
274 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMP, cmsg_data=?}]"
275 ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
276 (unsigned) cmsg->cmsg_len,
277 (unsigned long) len, rc, errno2name());
281 test_scm_timestampns(struct msghdr *const mh, void *const page)
283 size_t len = CMSG_SPACE(sizeof(struct timespec));
284 struct cmsghdr *cmsg = get_cmsghdr(page, len);
286 cmsg->cmsg_len = CMSG_LEN(sizeof(struct timespec));
287 cmsg->cmsg_level = SOL_SOCKET;
288 cmsg->cmsg_type = SCM_TIMESTAMPNS;
289 struct timespec *ts = (struct timespec *) CMSG_DATA(cmsg);
290 ts->tv_sec = 123456789;
291 ts->tv_nsec = 987654321;
293 mh->msg_control = cmsg;
294 mh->msg_controllen = len;
296 int rc = sendmsg(-1, mh, 0);
297 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
298 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
299 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMPNS"
300 ", cmsg_data={tv_sec=%lld, tv_nsec=%llu}}]"
301 ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
302 (unsigned) cmsg->cmsg_len,
303 (long long) ts->tv_sec, zero_extend_signed_to_ull(ts->tv_nsec),
304 (unsigned long) len, rc, errno2name());
306 len = CMSG_SPACE(sizeof(struct timespec) - sizeof(long));
307 cmsg = get_cmsghdr(page, len);
309 cmsg->cmsg_len = CMSG_LEN(sizeof(struct timespec) - sizeof(long));
310 cmsg->cmsg_level = SOL_SOCKET;
311 cmsg->cmsg_type = SCM_TIMESTAMPNS;
313 mh->msg_control = cmsg;
314 mh->msg_controllen = len;
316 rc = sendmsg(-1, mh, 0);
317 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
318 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
319 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMPNS"
321 ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
322 (unsigned) cmsg->cmsg_len,
323 (unsigned long) len, rc, errno2name());
327 test_scm_timestamping(struct msghdr *const mh, void *const page)
329 size_t len = CMSG_SPACE(3 * sizeof(struct timespec));
330 struct cmsghdr *cmsg = get_cmsghdr(page, len);
332 cmsg->cmsg_len = CMSG_LEN(3 * sizeof(struct timespec));
333 cmsg->cmsg_level = SOL_SOCKET;
334 cmsg->cmsg_type = SCM_TIMESTAMPING;
335 struct timespec *ts = (struct timespec *) CMSG_DATA(cmsg);
336 ts[0].tv_sec = 123456789;
337 ts[0].tv_nsec = 987654321;
338 ts[1].tv_sec = 123456790;
339 ts[1].tv_nsec = 987654320;
340 ts[2].tv_sec = 123456791;
341 ts[2].tv_nsec = 987654319;
343 mh->msg_control = cmsg;
344 mh->msg_controllen = len;
346 int rc = sendmsg(-1, mh, 0);
347 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
348 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
349 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMPING"
350 ", cmsg_data=[{tv_sec=%lld, tv_nsec=%llu}"
351 ", {tv_sec=%lld, tv_nsec=%llu}, {tv_sec=%lld, tv_nsec=%llu}]}]"
352 ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
353 (unsigned) cmsg->cmsg_len, (long long) ts[0].tv_sec,
354 zero_extend_signed_to_ull(ts[0].tv_nsec),
355 (long long) ts[1].tv_sec,
356 zero_extend_signed_to_ull(ts[1].tv_nsec),
357 (long long) ts[2].tv_sec,
358 zero_extend_signed_to_ull(ts[2].tv_nsec),
359 (unsigned long) len, rc, errno2name());
361 len = CMSG_SPACE(3 * sizeof(struct timespec) - sizeof(long));
362 cmsg = get_cmsghdr(page, len);
364 cmsg->cmsg_len = CMSG_LEN(3 * sizeof(struct timespec) - sizeof(long));
365 cmsg->cmsg_level = SOL_SOCKET;
366 cmsg->cmsg_type = SCM_TIMESTAMPING;
368 mh->msg_control = cmsg;
369 mh->msg_controllen = len;
371 rc = sendmsg(-1, mh, 0);
372 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
373 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
374 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_TIMESTAMPING"
376 ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
377 (unsigned) cmsg->cmsg_len,
378 (unsigned long) len, rc, errno2name());
382 print_security(const struct cmsghdr *const cmsg, const size_t cmsg_len)
384 int n = cmsg_len > CMSG_LEN(0) ? cmsg_len - CMSG_LEN(0) : 0;
388 printf(", cmsg_data=\"%.*s\"", n, CMSG_DATA(cmsg));
392 test_scm_security(struct msghdr *const mh,
393 const size_t msg_controllen,
395 const void *const src,
396 const size_t cmsg_len,
397 const int cmsg_level,
398 const char *const cmsg_level_str)
400 const size_t aligned_cms_len =
401 cmsg_len > CMSG_LEN(0) ? CMSG_ALIGN(cmsg_len) : CMSG_LEN(0);
402 if (cmsg_len >= CMSG_LEN(0)
403 && aligned_cms_len + CMSG_LEN(0) <= msg_controllen)
406 struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen);
408 cmsg->cmsg_len = cmsg_len;
409 cmsg->cmsg_level = cmsg_level;
410 cmsg->cmsg_type = SCM_SECURITY;
413 cmsg_len < msg_controllen ? cmsg_len : msg_controllen;
414 if (src_len > CMSG_LEN(0))
415 memcpy(CMSG_DATA(cmsg), src, src_len - CMSG_LEN(0));
417 mh->msg_control = cmsg;
418 mh->msg_controllen = msg_controllen;
420 int rc = sendmsg(-1, mh, 0);
421 int saved_errno = errno;
423 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
424 ", msg_iovlen=0, msg_control=[{cmsg_len=%lu, cmsg_level=%s"
425 ", cmsg_type=SCM_SECURITY",
426 (unsigned long) cmsg_len, cmsg_level_str);
427 print_security(cmsg, src_len);
429 if (aligned_cms_len < msg_controllen)
430 printf(", %p", (void *) cmsg + aligned_cms_len);
434 printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
435 (unsigned long) msg_controllen, rc, errno2name());
439 test_unknown_type(struct msghdr *const mh,
441 const int cmsg_level,
442 const char *const cmsg_level_str,
443 const char *const cmsg_type_str)
445 struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0));
447 cmsg->cmsg_len = CMSG_LEN(0);
448 cmsg->cmsg_level = cmsg_level;
449 cmsg->cmsg_type = 0xfacefeed;
451 mh->msg_control = cmsg;
452 mh->msg_controllen = cmsg->cmsg_len;
454 int rc = sendmsg(-1, mh, 0);
455 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
456 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=%s"
457 ", cmsg_type=%#x /* %s */}], msg_controllen=%u, msg_flags=0}"
458 ", 0) = %d %s (%m)\n",
459 (unsigned) cmsg->cmsg_len, cmsg_level_str, cmsg->cmsg_type,
460 cmsg_type_str, (unsigned) mh->msg_controllen, rc, errno2name());
464 test_sol_socket(struct msghdr *const mh, void *const page)
466 static const int fds0[] = { -10, -11, -12, -13 };
467 static const int fds1[] = { -15, -16, -17, -18 };
468 size_t msg_controllen, max_msg_controllen;
470 max_msg_controllen = CMSG_SPACE(sizeof(fds0)) + sizeof(*fds0) - 1;
471 for (msg_controllen = 0;
472 msg_controllen <= max_msg_controllen;
477 cmsg_len <= msg_controllen + CMSG_LEN(0);
479 test_scm_rights1(mh, msg_controllen,
480 page, fds0, cmsg_len);
485 CMSG_SPACE(sizeof(fds0)) + CMSG_SPACE(sizeof(fds1)) +
487 for (msg_controllen = CMSG_LEN(0) * 2;
488 msg_controllen <= max_msg_controllen;
490 static const int *const fdps[] = { fds0, fds1 };
493 for (cmsg_len[0] = CMSG_LEN(0);
494 CMSG_ALIGN(cmsg_len[0]) + CMSG_LEN(0) <= msg_controllen
495 && CMSG_ALIGN(cmsg_len[0]) <= CMSG_SPACE(sizeof(fds0));
497 const size_t msg_controllen1 =
498 msg_controllen - CMSG_ALIGN(cmsg_len[0]);
500 for (cmsg_len[1] = 0;
501 cmsg_len[1] <= msg_controllen1 + CMSG_LEN(0);
503 test_scm_rights2(mh, msg_controllen,
504 page, fdps, cmsg_len);
509 static const char text[16] = "0123456789abcdef";
510 max_msg_controllen = CMSG_SPACE(sizeof(text)) + CMSG_LEN(0) - 1;
511 for (msg_controllen = CMSG_LEN(0);
512 msg_controllen <= max_msg_controllen;
517 cmsg_len <= msg_controllen + CMSG_LEN(0)
518 && cmsg_len <= CMSG_LEN(sizeof(text));
520 test_scm_security(mh, msg_controllen,
521 page, text, cmsg_len,
522 ARG_STR(SOL_SOCKET));
526 test_scm_rights3(mh, page, DEFAULT_STRLEN - 1);
527 test_scm_rights3(mh, page, DEFAULT_STRLEN);
528 test_scm_rights3(mh, page, DEFAULT_STRLEN + 1);
530 test_scm_timestamp(mh, page);
531 test_scm_timestampns(mh, page);
532 test_scm_timestamping(mh, page);
534 test_unknown_type(mh, page, ARG_STR(SOL_SOCKET), "SCM_???");
538 test_ip_pktinfo(struct msghdr *const mh, void *const page,
539 const int cmsg_type, const char *const cmsg_type_str)
541 const unsigned int len = CMSG_SPACE(sizeof(struct in_pktinfo));
542 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
544 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
545 cmsg->cmsg_level = SOL_IP;
546 cmsg->cmsg_type = cmsg_type;
548 struct in_pktinfo *const info = (struct in_pktinfo *) CMSG_DATA(cmsg);
549 #ifdef HAVE_IF_INDEXTONAME
550 info->ipi_ifindex = if_nametoindex("lo");
552 info->ipi_ifindex = 1;
554 info->ipi_spec_dst.s_addr = inet_addr("1.2.3.4");
555 info->ipi_addr.s_addr = inet_addr("5.6.7.8");
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={ipi_ifindex=%s"
564 ", ipi_spec_dst=inet_addr(\"%s\")"
565 ", ipi_addr=inet_addr(\"%s\")}}]"
566 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
567 (unsigned) cmsg->cmsg_len, cmsg_type_str,
568 #ifdef HAVE_IF_INDEXTONAME
569 "if_nametoindex(\"lo\")",
573 "1.2.3.4", "5.6.7.8", len, rc, errno2name());
577 test_ip_uint(struct msghdr *const mh, void *const page,
578 const int cmsg_type, const char *const cmsg_type_str)
580 const unsigned int len = CMSG_SPACE(sizeof(int));
581 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
583 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
584 cmsg->cmsg_level = SOL_IP;
585 cmsg->cmsg_type = cmsg_type;
587 unsigned int *u = (void *) CMSG_DATA(cmsg);
590 mh->msg_control = cmsg;
591 mh->msg_controllen = len;
593 int rc = sendmsg(-1, mh, 0);
594 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
595 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
596 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%u]}]"
597 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
598 (unsigned) cmsg->cmsg_len, cmsg_type_str, *u, len,
603 test_ip_uint8_t(struct msghdr *const mh, void *const page,
604 const int cmsg_type, const char *const cmsg_type_str)
606 const unsigned int len = CMSG_SPACE(1);
607 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
609 cmsg->cmsg_len = CMSG_LEN(1);
610 cmsg->cmsg_level = SOL_IP;
611 cmsg->cmsg_type = cmsg_type;
612 *CMSG_DATA(cmsg) = 'A';
614 mh->msg_control = cmsg;
615 mh->msg_controllen = len;
617 int rc = sendmsg(-1, mh, 0);
618 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
619 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
620 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[%#x]}]"
621 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
622 (unsigned) cmsg->cmsg_len, cmsg_type_str,
623 (unsigned) (uint8_t) 'A', len, rc, errno2name());
627 print_ip_opts(const void *const cmsg_data, const unsigned int data_len)
629 const unsigned char *const opts = cmsg_data;
631 for (i = 0; i < data_len; ++i) {
635 if (i >= DEFAULT_STRLEN) {
640 printf("0x%02x", opts[i]);
645 test_ip_opts(struct msghdr *const mh, void *const page,
646 const int cmsg_type, const char *const cmsg_type_str,
647 const unsigned int opts_len)
649 unsigned int len = CMSG_SPACE(opts_len);
650 struct cmsghdr *cmsg = get_cmsghdr(page, len);
652 cmsg->cmsg_len = CMSG_LEN(opts_len);
653 cmsg->cmsg_level = SOL_IP;
654 cmsg->cmsg_type = cmsg_type;
656 for (i = 0; i < opts_len; ++i)
657 CMSG_DATA(cmsg)[i] = 'A' + i;
659 mh->msg_control = cmsg;
660 mh->msg_controllen = len;
662 int rc = sendmsg(-1, mh, 0);
663 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
664 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
665 ", cmsg_level=SOL_IP, cmsg_type=%s, cmsg_data=[",
666 (unsigned) cmsg->cmsg_len, cmsg_type_str);
667 print_ip_opts(CMSG_DATA(cmsg), opts_len);
668 printf("]}], msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
669 len, rc, errno2name());
681 struct sockaddr_in offender;
685 test_ip_recverr(struct msghdr *const mh, void *const page,
686 const int cmsg_type, const char *const cmsg_type_str)
688 const unsigned int len = CMSG_SPACE(sizeof(struct sock_ee));
689 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
691 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sock_ee));
692 cmsg->cmsg_level = SOL_IP;
693 cmsg->cmsg_type = cmsg_type;
695 struct sock_ee *const e = (struct sock_ee *) CMSG_DATA(cmsg);
696 e->ee_errno = 0xdeadbeef;
700 e->ee_info = 0xfacefeed;
701 e->ee_data = 0xbadc0ded;
702 e->offender.sin_family = AF_INET,
703 e->offender.sin_port = htons(12345),
704 e->offender.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
706 mh->msg_control = cmsg;
707 mh->msg_controllen = len;
709 int rc = sendmsg(-1, mh, 0);
710 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
711 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
712 ", cmsg_type=%s, cmsg_data={ee_errno=%u, ee_origin=%u"
713 ", ee_type=%u, ee_code=%u, ee_info=%u, ee_data=%u"
714 ", offender={sa_family=AF_INET, sin_port=htons(%hu)"
715 ", sin_addr=inet_addr(\"127.0.0.1\")}}}]"
716 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
717 (unsigned) cmsg->cmsg_len, cmsg_type_str,
718 e->ee_errno, e->ee_origin, e->ee_type,
719 e->ee_code, e->ee_info, e->ee_data,
720 ntohs(e->offender.sin_port),
721 len, rc, errno2name());
725 #ifdef IP_ORIGDSTADDR
727 test_ip_origdstaddr(struct msghdr *const mh, void *const page,
728 const int cmsg_type, const char *const cmsg_type_str)
730 const unsigned int len = CMSG_SPACE(sizeof(struct sockaddr_in));
731 struct cmsghdr *const cmsg = get_cmsghdr(page, len);
733 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sockaddr_in));
734 cmsg->cmsg_level = SOL_IP;
735 cmsg->cmsg_type = cmsg_type;
737 struct sockaddr_in *const sin = (struct sockaddr_in *) CMSG_DATA(cmsg);
738 sin->sin_family = AF_INET,
739 sin->sin_port = htons(12345),
740 sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
742 mh->msg_control = cmsg;
743 mh->msg_controllen = len;
745 int rc = sendmsg(-1, mh, 0);
746 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
747 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=SOL_IP"
748 ", cmsg_type=%s, cmsg_data={sa_family=AF_INET"
749 ", sin_port=htons(%hu), sin_addr=inet_addr(\"127.0.0.1\")}}]"
750 ", msg_controllen=%u, msg_flags=0}, 0) = %d %s (%m)\n",
751 (unsigned) cmsg->cmsg_len, cmsg_type_str,
752 ntohs(sin->sin_port), len, rc, errno2name());
757 test_sol_ip(struct msghdr *const mh, void *const page)
759 test_ip_pktinfo(mh, page, ARG_STR(IP_PKTINFO));
760 test_ip_uint(mh, page, ARG_STR(IP_TTL));
761 test_ip_uint8_t(mh, page, ARG_STR(IP_TOS));
762 test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 1);
763 test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 2);
764 test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 3);
765 test_ip_opts(mh, page, ARG_STR(IP_RECVOPTS), 4);
766 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 5);
767 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 6);
768 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 7);
769 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), 8);
770 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), DEFAULT_STRLEN - 1);
771 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), DEFAULT_STRLEN);
772 test_ip_opts(mh, page, ARG_STR(IP_RETOPTS), DEFAULT_STRLEN + 1);
774 test_ip_recverr(mh, page, ARG_STR(IP_RECVERR));
776 #ifdef IP_ORIGDSTADDR
777 test_ip_origdstaddr(mh, page, ARG_STR(IP_ORIGDSTADDR));
780 test_ip_uint(mh, page, ARG_STR(IP_CHECKSUM));
782 test_scm_security(mh, CMSG_LEN(0), page, 0, CMSG_LEN(0),
784 test_unknown_type(mh, page, ARG_STR(SOL_IP), "IP_???");
788 test_unknown_level(struct msghdr *const mh, void *const page)
790 struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0));
792 cmsg->cmsg_len = CMSG_LEN(0);
793 cmsg->cmsg_level = SOL_TCP;
794 cmsg->cmsg_type = 0xdeadbeef;
796 mh->msg_control = cmsg;
797 mh->msg_controllen = cmsg->cmsg_len;
799 int rc = sendmsg(-1, mh, 0);
800 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
801 ", msg_iovlen=0, msg_control=[{cmsg_len=%u, cmsg_level=%s"
802 ", cmsg_type=%#x}], msg_controllen=%u, msg_flags=0}"
803 ", 0) = %d %s (%m)\n",
804 (unsigned) cmsg->cmsg_len, "SOL_TCP", cmsg->cmsg_type,
805 (unsigned) mh->msg_controllen, rc, errno2name());
809 test_big_len(struct msghdr *const mh)
813 if (read_int_from_file("/proc/sys/net/core/optmem_max", &optmem_max)
814 || optmem_max <= 0 || optmem_max > 0x100000)
815 optmem_max = sizeof(long long) * (2 * IOV_MAX + 512);
816 optmem_max = (optmem_max + sizeof(long long) - 1)
817 & ~(sizeof(long long) - 1);
819 const size_t len = optmem_max * 2;
820 struct cmsghdr *const cmsg = tail_alloc(len);
821 cmsg->cmsg_len = len;
822 cmsg->cmsg_level = SOL_SOCKET;
823 cmsg->cmsg_type = SCM_RIGHTS;
825 mh->msg_control = cmsg;
826 mh->msg_controllen = len;
828 int rc = sendmsg(-1, mh, 0);
830 perror_msg_and_skip("sendmsg");
832 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
833 ", msg_iovlen=0, msg_control=[{cmsg_len=%u"
834 ", cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS",
835 (unsigned) cmsg->cmsg_len);
836 print_fds(cmsg, optmem_max);
837 printf("}, ...], msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
838 (unsigned long) len, rc, errno2name());
841 int main(int ac, const char **av)
843 int rc = sendmsg(-1, 0, 0);
844 printf("sendmsg(-1, NULL, 0) = %d %s (%m)\n", rc, errno2name());
846 TAIL_ALLOC_OBJECT_CONST_PTR(struct msghdr, mh);
847 memset(mh, 0, sizeof(*mh));
850 rc = sendmsg(-1, mh + 1, 0);
851 printf("sendmsg(-1, %p, 0) = %d %s (%m)\n",
852 mh + 1, rc, errno2name());
854 void *page = tail_alloc(1) + 1;
855 mh->msg_control = page;
856 mh->msg_controllen = CMSG_LEN(0);
857 rc = sendmsg(-1, mh, 0);
858 printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
859 ", msg_iovlen=0, msg_control=%p, msg_controllen=%u"
860 ", msg_flags=0}, 0) = %d %s (%m)\n",
861 page, (unsigned) CMSG_LEN(0), rc, errno2name());
863 test_sol_socket(mh, page);
864 test_sol_ip(mh, page);
865 test_unknown_level(mh, page);
867 puts("+++ exited with 0 +++");