]> granicus.if.org Git - strace/blob - tests/msg_control.c
tests: check decoding of incomplete SCM_TIMESTAMP* control messages
[strace] / tests / msg_control.c
1 /*
2  * Check decoding of struct msghdr ancillary data.
3  *
4  * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
5  * Copyright (c) 2016-2017 The strace developers.
6  * 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 #include "xlat.h"
44 #include "xlat/scmvals.h"
45
46 #ifndef SOL_IP
47 # define SOL_IP 0
48 #endif
49 #ifndef SOL_TCP
50 # define SOL_TCP 6
51 #endif
52
53 #ifndef SCM_SECURITY
54 # define SCM_SECURITY 3
55 #endif
56
57 #define MIN_SIZE_OF(type, member) \
58         (offsetof(type, member) + sizeof(((type *) 0)->member))
59
60 static struct cmsghdr *
61 get_cmsghdr(void *const page, const size_t len)
62 {
63         return page - CMSG_ALIGN(len);
64 }
65
66 #define DEFAULT_STRLEN 32
67
68 static void
69 print_fds(const struct cmsghdr *const cmsg, const size_t cmsg_len)
70 {
71         size_t nfd = cmsg_len > CMSG_LEN(0)
72                      ? (cmsg_len - CMSG_LEN(0)) / sizeof(int) : 0;
73         if (!nfd)
74                 return;
75
76         printf(", cmsg_data=[");
77         int *fdp = (int *) CMSG_DATA(cmsg);
78         size_t i;
79         for (i = 0; i < nfd; ++i) {
80                 if (i)
81                         printf(", ");
82 #if !VERBOSE
83                 if (i >= DEFAULT_STRLEN) {
84                         printf("...");
85                         break;
86                 }
87 #endif
88                 printf("%d", fdp[i]);
89         }
90         printf("]");
91 }
92
93 static void
94 test_scm_rights1(struct msghdr *const mh,
95                  const size_t msg_controllen,
96                  void *const page,
97                  const void *const src,
98                  const size_t cmsg_len)
99 {
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)
104                 return;
105
106         struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen);
107
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;
114
115         size_t src_len =
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));
119
120         mh->msg_control = cmsg;
121         mh->msg_controllen = msg_controllen;
122
123         int rc = sendmsg(-1, mh, 0);
124         int saved_errno = errno;
125
126         printf("sendmsg(-1, {msg_name=NULL, msg_namelen=0, msg_iov=NULL"
127                ", msg_iovlen=0");
128         if (msg_controllen < CMSG_LEN(0)) {
129                 if (msg_controllen)
130                         printf(", msg_control=%p", cmsg);
131         } else {
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);
135                 printf("}");
136                 if (aligned_cms_len < msg_controllen)
137                         printf(", %p", (void *) cmsg + aligned_cms_len);
138                 printf("]");
139         }
140
141         errno = saved_errno;
142         printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
143                (unsigned long) msg_controllen, rc, errno2name());
144 }
145
146 static void
147 test_scm_rights2(struct msghdr *const mh,
148                  const size_t msg_controllen,
149                  void *const page,
150                  const int *const *const src,
151                  const size_t *const cmsg_len)
152 {
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)
156         };
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)
160                 return;
161
162         struct cmsghdr *const cmsg[2] = {
163                 get_cmsghdr(page, msg_controllen),
164                 (void *) get_cmsghdr(page, msg_controllen) + aligned_cms_len[0]
165         };
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));
171
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;
179         size_t src1_len =
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));
183
184         mh->msg_control = cmsg[0];
185         mh->msg_controllen = msg_controllen;
186
187         int rc = sendmsg(-1, mh, 0);
188         int saved_errno = errno;
189
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);
198         printf("}");
199         if (aligned_cms_len[1] < msg_controllen1)
200                 printf(", %p", (void *) cmsg[1] + aligned_cms_len[1]);
201         printf("]");
202
203         errno = saved_errno;
204         printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
205                (unsigned long) msg_controllen, rc, errno2name());
206 }
207
208 static void
209 test_scm_rights3(struct msghdr *const mh, void *const page, const size_t nfds)
210 {
211         const size_t len = CMSG_SPACE(sizeof(int) * nfds);
212         struct cmsghdr *cmsg = get_cmsghdr(page, len);
213
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);
218         size_t i;
219         for (i = 0; i < nfds; ++i)
220                 fdp[i] = i;
221
222         mh->msg_control = cmsg;
223         mh->msg_controllen = len;
224
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());
233 }
234
235 static void
236 test_scm_timestamp(struct msghdr *const mh, void *const page)
237 {
238         size_t len = CMSG_SPACE(sizeof(struct timeval));
239         struct cmsghdr *cmsg = get_cmsghdr(page, len);
240
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;
247
248         mh->msg_control = cmsg;
249         mh->msg_controllen = len;
250
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());
260
261         len = CMSG_SPACE(sizeof(struct timeval) - sizeof(long));
262         cmsg = get_cmsghdr(page, len);
263
264         cmsg->cmsg_len = CMSG_LEN(sizeof(struct timeval) - sizeof(long));
265         cmsg->cmsg_level = SOL_SOCKET;
266         cmsg->cmsg_type = SCM_TIMESTAMP;
267
268         mh->msg_control = cmsg;
269         mh->msg_controllen = len;
270
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());
278 }
279
280 static void
281 test_scm_timestampns(struct msghdr *const mh, void *const page)
282 {
283         size_t len = CMSG_SPACE(sizeof(struct timespec));
284         struct cmsghdr *cmsg = get_cmsghdr(page, len);
285
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;
292
293         mh->msg_control = cmsg;
294         mh->msg_controllen = len;
295
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());
305
306         len = CMSG_SPACE(sizeof(struct timespec) - sizeof(long));
307         cmsg = get_cmsghdr(page, len);
308
309         cmsg->cmsg_len = CMSG_LEN(sizeof(struct timespec) - sizeof(long));
310         cmsg->cmsg_level = SOL_SOCKET;
311         cmsg->cmsg_type = SCM_TIMESTAMPNS;
312
313         mh->msg_control = cmsg;
314         mh->msg_controllen = len;
315
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"
320                ", cmsg_data=?}]"
321                ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
322                (unsigned) cmsg->cmsg_len,
323                (unsigned long) len, rc, errno2name());
324 }
325
326 static void
327 test_scm_timestamping(struct msghdr *const mh, void *const page)
328 {
329         size_t len = CMSG_SPACE(3 * sizeof(struct timespec));
330         struct cmsghdr *cmsg = get_cmsghdr(page, len);
331
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;
342
343         mh->msg_control = cmsg;
344         mh->msg_controllen = len;
345
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());
360
361         len = CMSG_SPACE(3 * sizeof(struct timespec) - sizeof(long));
362         cmsg = get_cmsghdr(page, len);
363
364         cmsg->cmsg_len = CMSG_LEN(3 * sizeof(struct timespec) - sizeof(long));
365         cmsg->cmsg_level = SOL_SOCKET;
366         cmsg->cmsg_type = SCM_TIMESTAMPING;
367
368         mh->msg_control = cmsg;
369         mh->msg_controllen = len;
370
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"
375                ", cmsg_data=?}]"
376                ", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
377                (unsigned) cmsg->cmsg_len,
378                (unsigned long) len, rc, errno2name());
379 }
380
381 static void
382 print_security(const struct cmsghdr *const cmsg, const size_t cmsg_len)
383 {
384         int n = cmsg_len > CMSG_LEN(0) ? cmsg_len - CMSG_LEN(0) : 0;
385         if (!n)
386                 return;
387
388         printf(", cmsg_data=\"%.*s\"", n, CMSG_DATA(cmsg));
389 }
390
391 static void
392 test_scm_security(struct msghdr *const mh,
393                   const size_t msg_controllen,
394                   void *const page,
395                   const void *const src,
396                   const size_t cmsg_len,
397                   const int cmsg_level,
398                   const char *const cmsg_level_str)
399 {
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)
404                 return;
405
406         struct cmsghdr *cmsg = get_cmsghdr(page, msg_controllen);
407
408         cmsg->cmsg_len = cmsg_len;
409         cmsg->cmsg_level = cmsg_level;
410         cmsg->cmsg_type = SCM_SECURITY;
411
412         size_t src_len =
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));
416
417         mh->msg_control = cmsg;
418         mh->msg_controllen = msg_controllen;
419
420         int rc = sendmsg(-1, mh, 0);
421         int saved_errno = errno;
422
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);
428         printf("}");
429         if (aligned_cms_len < msg_controllen)
430                 printf(", %p", (void *) cmsg + aligned_cms_len);
431         printf("]");
432
433         errno = saved_errno;
434         printf(", msg_controllen=%lu, msg_flags=0}, 0) = %d %s (%m)\n",
435                (unsigned long) msg_controllen, rc, errno2name());
436 }
437
438 static void
439 test_unknown_type(struct msghdr *const mh,
440                   void *const page,
441                   const int cmsg_level,
442                   const char *const cmsg_level_str,
443                   const char *const cmsg_type_str)
444 {
445         struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0));
446
447         cmsg->cmsg_len = CMSG_LEN(0);
448         cmsg->cmsg_level = cmsg_level;
449         cmsg->cmsg_type = 0xfacefeed;
450
451         mh->msg_control = cmsg;
452         mh->msg_controllen = cmsg->cmsg_len;
453
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());
461 }
462
463 static void
464 test_sol_socket(struct msghdr *const mh, void *const page)
465 {
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;
469
470         max_msg_controllen = CMSG_SPACE(sizeof(fds0)) + sizeof(*fds0) - 1;
471         for (msg_controllen = 0;
472              msg_controllen <= max_msg_controllen;
473              msg_controllen++) {
474                 size_t cmsg_len;
475
476                 for (cmsg_len = 0;
477                      cmsg_len <= msg_controllen + CMSG_LEN(0);
478                      cmsg_len++) {
479                         test_scm_rights1(mh, msg_controllen,
480                                          page, fds0, cmsg_len);
481                 }
482         }
483
484         max_msg_controllen =
485                 CMSG_SPACE(sizeof(fds0)) + CMSG_SPACE(sizeof(fds1)) +
486                 sizeof(*fds0) - 1;
487         for (msg_controllen = CMSG_LEN(0) * 2;
488              msg_controllen <= max_msg_controllen;
489              msg_controllen++) {
490                 static const int *const fdps[] = { fds0, fds1 };
491                 size_t cmsg_len[2];
492
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));
496                      cmsg_len[0]++) {
497                         const size_t msg_controllen1 =
498                                 msg_controllen - CMSG_ALIGN(cmsg_len[0]);
499
500                         for (cmsg_len[1] = 0;
501                              cmsg_len[1] <= msg_controllen1 + CMSG_LEN(0);
502                              cmsg_len[1]++) {
503                                 test_scm_rights2(mh, msg_controllen,
504                                                  page, fdps, cmsg_len);
505                         }
506                 }
507         }
508
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;
513              msg_controllen++) {
514                 size_t cmsg_len;
515
516                 for (cmsg_len = 0;
517                      cmsg_len <= msg_controllen + CMSG_LEN(0)
518                      && cmsg_len <= CMSG_LEN(sizeof(text));
519                      cmsg_len++) {
520                         test_scm_security(mh, msg_controllen,
521                                           page, text, cmsg_len,
522                                           ARG_STR(SOL_SOCKET));
523                 }
524         }
525
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);
529
530         test_scm_timestamp(mh, page);
531         test_scm_timestampns(mh, page);
532         test_scm_timestamping(mh, page);
533
534         test_unknown_type(mh, page, ARG_STR(SOL_SOCKET), "SCM_???");
535 }
536
537 static void
538 test_ip_pktinfo(struct msghdr *const mh, void *const page,
539                 const int cmsg_type, const char *const cmsg_type_str)
540 {
541         const unsigned int len = CMSG_SPACE(sizeof(struct in_pktinfo));
542         struct cmsghdr *const cmsg = get_cmsghdr(page, len);
543
544         cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
545         cmsg->cmsg_level = SOL_IP;
546         cmsg->cmsg_type = cmsg_type;
547
548         struct in_pktinfo *const info = (struct in_pktinfo *) CMSG_DATA(cmsg);
549 #ifdef HAVE_IF_INDEXTONAME
550         info->ipi_ifindex = if_nametoindex("lo");
551 #else
552         info->ipi_ifindex = 1;
553 #endif
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");
556
557         mh->msg_control = cmsg;
558         mh->msg_controllen = len;
559
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\")",
570 #else
571                "1",
572 #endif
573                "1.2.3.4", "5.6.7.8", len, rc, errno2name());
574 }
575
576 static void
577 test_ip_uint(struct msghdr *const mh, void *const page,
578              const int cmsg_type, const char *const cmsg_type_str)
579 {
580         const unsigned int len = CMSG_SPACE(sizeof(int));
581         struct cmsghdr *const cmsg = get_cmsghdr(page, len);
582
583         cmsg->cmsg_len = CMSG_LEN(sizeof(int));
584         cmsg->cmsg_level = SOL_IP;
585         cmsg->cmsg_type = cmsg_type;
586
587         unsigned int *u = (void *) CMSG_DATA(cmsg);
588         *u = 0xfacefeed;
589
590         mh->msg_control = cmsg;
591         mh->msg_controllen = len;
592
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,
599                rc, errno2name());
600 }
601
602 static void
603 test_ip_uint8_t(struct msghdr *const mh, void *const page,
604                 const int cmsg_type, const char *const cmsg_type_str)
605 {
606         const unsigned int len = CMSG_SPACE(1);
607         struct cmsghdr *const cmsg = get_cmsghdr(page, len);
608
609         cmsg->cmsg_len = CMSG_LEN(1);
610         cmsg->cmsg_level = SOL_IP;
611         cmsg->cmsg_type = cmsg_type;
612         *CMSG_DATA(cmsg) = 'A';
613
614         mh->msg_control = cmsg;
615         mh->msg_controllen = len;
616
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());
624 }
625
626 static void
627 print_ip_opts(const void *const cmsg_data, const unsigned int data_len)
628 {
629         const unsigned char *const opts = cmsg_data;
630         unsigned int i;
631         for (i = 0; i < data_len; ++i) {
632                 if (i)
633                         printf(", ");
634 #if !VERBOSE
635                 if (i >= DEFAULT_STRLEN) {
636                         printf("...");
637                         break;
638                 }
639 #endif
640                 printf("0x%02x", opts[i]);
641         }
642 }
643
644 static void
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)
648 {
649         unsigned int len = CMSG_SPACE(opts_len);
650         struct cmsghdr *cmsg = get_cmsghdr(page, len);
651
652         cmsg->cmsg_len = CMSG_LEN(opts_len);
653         cmsg->cmsg_level = SOL_IP;
654         cmsg->cmsg_type = cmsg_type;
655         unsigned int i;
656         for (i = 0; i < opts_len; ++i)
657                 CMSG_DATA(cmsg)[i] = 'A' + i;
658
659         mh->msg_control = cmsg;
660         mh->msg_controllen = len;
661
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());
670 }
671
672 #ifdef IP_CHECKSUM
673 struct sock_ee {
674         uint32_t ee_errno;
675         uint8_t  ee_origin;
676         uint8_t  ee_type;
677         uint8_t  ee_code;
678         uint8_t  ee_pad;
679         uint32_t ee_info;
680         uint32_t ee_data;
681         struct sockaddr_in offender;
682 };
683
684 static void
685 test_ip_recverr(struct msghdr *const mh, void *const page,
686                 const int cmsg_type, const char *const cmsg_type_str)
687 {
688         const unsigned int len = CMSG_SPACE(sizeof(struct sock_ee));
689         struct cmsghdr *const cmsg = get_cmsghdr(page, len);
690
691         cmsg->cmsg_len = CMSG_LEN(sizeof(struct sock_ee));
692         cmsg->cmsg_level = SOL_IP;
693         cmsg->cmsg_type = cmsg_type;
694
695         struct sock_ee *const e = (struct sock_ee *) CMSG_DATA(cmsg);
696         e->ee_errno = 0xdeadbeef;
697         e->ee_origin = 2;
698         e->ee_type = 3;
699         e->ee_code = 4;
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);
705
706         mh->msg_control = cmsg;
707         mh->msg_controllen = len;
708
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());
722 }
723 #endif
724
725 #ifdef IP_ORIGDSTADDR
726 static void
727 test_ip_origdstaddr(struct msghdr *const mh, void *const page,
728                     const int cmsg_type, const char *const cmsg_type_str)
729 {
730         const unsigned int len = CMSG_SPACE(sizeof(struct sockaddr_in));
731         struct cmsghdr *const cmsg = get_cmsghdr(page, len);
732
733         cmsg->cmsg_len = CMSG_LEN(sizeof(struct sockaddr_in));
734         cmsg->cmsg_level = SOL_IP;
735         cmsg->cmsg_type = cmsg_type;
736
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);
741
742         mh->msg_control = cmsg;
743         mh->msg_controllen = len;
744
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());
753 }
754 #endif
755
756 static void
757 test_sol_ip(struct msghdr *const mh, void *const page)
758 {
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);
773 #ifdef IP_CHECKSUM
774         test_ip_recverr(mh, page, ARG_STR(IP_RECVERR));
775 #endif
776 #ifdef IP_ORIGDSTADDR
777         test_ip_origdstaddr(mh, page, ARG_STR(IP_ORIGDSTADDR));
778 #endif
779 #ifdef IP_CHECKSUM
780         test_ip_uint(mh, page, ARG_STR(IP_CHECKSUM));
781 #endif
782         test_scm_security(mh, CMSG_LEN(0), page, 0, CMSG_LEN(0),
783                           ARG_STR(SOL_IP));
784         test_unknown_type(mh, page, ARG_STR(SOL_IP), "IP_???");
785 }
786
787 static void
788 test_unknown_level(struct msghdr *const mh, void *const page)
789 {
790         struct cmsghdr *cmsg = get_cmsghdr(page, CMSG_LEN(0));
791
792         cmsg->cmsg_len = CMSG_LEN(0);
793         cmsg->cmsg_level = SOL_TCP;
794         cmsg->cmsg_type = 0xdeadbeef;
795
796         mh->msg_control = cmsg;
797         mh->msg_controllen = cmsg->cmsg_len;
798
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());
806 }
807
808 static void
809 test_big_len(struct msghdr *const mh)
810 {
811         int optmem_max;
812
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);
818
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;
824
825         mh->msg_control = cmsg;
826         mh->msg_controllen = len;
827
828         int rc = sendmsg(-1, mh, 0);
829         if (EBADF != errno)
830                 perror_msg_and_skip("sendmsg");
831
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());
839 }
840
841 int main(int ac, const char **av)
842 {
843         int rc = sendmsg(-1, 0, 0);
844         printf("sendmsg(-1, NULL, 0) = %d %s (%m)\n", rc, errno2name());
845
846         TAIL_ALLOC_OBJECT_CONST_PTR(struct msghdr, mh);
847         memset(mh, 0, sizeof(*mh));
848         test_big_len(mh);
849
850         rc = sendmsg(-1, mh + 1, 0);
851         printf("sendmsg(-1, %p, 0) = %d %s (%m)\n",
852                mh + 1, rc, errno2name());
853
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());
862
863         test_sol_socket(mh, page);
864         test_sol_ip(mh, page);
865         test_unknown_level(mh, page);
866
867         puts("+++ exited with 0 +++");
868         return 0;
869 }