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