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