xref: /linux/tools/testing/selftests/net/getsockopt_iter.c (revision 24e4aff8983fe663a85b5b157476f87ae0819e2c)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Quick test for getsockopt{_iter} tests.
4  *
5  * Each fixture targets one converted protocol and pins down the
6  * returned-length / errno semantics across buffer-size variations,
7  * an unknown optname and a bogus level.
8  *
9  * - netlink: NETLINK_PKTINFO covers the flag-style int path; the
10  *   NETLINK_LIST_MEMBERSHIPS cases cover the size-discovery path
11  *   that always reports the required buffer length back via optlen,
12  *   even when the user buffer is too small to receive any group bits.
13  * - vsock:   SO_VM_SOCKETS_BUFFER_SIZE covers the u64 path.
14  * - raw:     ICMP_FILTER covers a fixed-size struct payload that clamps
15  *            the length down on a short buffer instead of failing.
16  *
17  * Author: Breno Leitao <leitao@debian.org>
18  */
19 
20 #include <errno.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <linux/netlink.h>
26 #include <linux/rtnetlink.h>
27 #include <linux/time_types.h>
28 #include <linux/vm_sockets.h>
29 #include <linux/icmp.h>
30 #include <netinet/in.h>
31 #include <netinet/tcp.h>
32 #include <arpa/inet.h>
33 #include <sys/socket.h>
34 #include <linux/tls.h>
35 #include "kselftest_harness.h"
36 
37 #ifndef AF_VSOCK
38 #define AF_VSOCK 40
39 #endif
40 #ifndef SOL_RAW
41 #define SOL_RAW 255
42 #endif
43 #ifndef ICMP_FILTER
44 #define ICMP_FILTER 1
45 #endif
46 #ifndef IPV6_HDRINCL
47 #define IPV6_HDRINCL 36
48 #endif
49 #ifndef IPV6_CHECKSUM
50 #define IPV6_CHECKSUM 7
51 #endif
52 #ifndef SOL_TLS
53 #define SOL_TLS 282
54 #endif
55 #ifndef TCP_ULP
56 #define TCP_ULP 31
57 #endif
58 
59 /* ---------- netlink ---------- */
60 
61 FIXTURE(netlink)
62 {
63 	int fd;
64 };
65 
66 FIXTURE_SETUP(netlink)
67 {
68 	int group = RTNLGRP_LINK;
69 
70 	self->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
71 	if (self->fd < 0)
72 		SKIP(return, "AF_NETLINK socket: %s", strerror(errno));
73 
74 	/* Joining a multicast group grows nlk->ngroups so the
75 	 * NETLINK_LIST_MEMBERSHIPS path has a non-zero size to report.
76 	 */
77 	if (setsockopt(self->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
78 		       &group, sizeof(group)) < 0)
79 		SKIP(return, "NETLINK_ADD_MEMBERSHIP: %s", strerror(errno));
80 }
81 
82 FIXTURE_TEARDOWN(netlink)
83 {
84 	if (self->fd >= 0)
85 		close(self->fd);
86 }
87 
88 TEST_F(netlink, pktinfo_exact)
89 {
90 	socklen_t optlen;
91 	int val = -1;
92 
93 	optlen = sizeof(val);
94 
95 	ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK, NETLINK_PKTINFO,
96 				&val, &optlen));
97 	ASSERT_EQ(sizeof(int), optlen);
98 	ASSERT_TRUE(val == 0 || val == 1);
99 }
100 
101 TEST_F(netlink, pktinfo_oversize_clamped)
102 {
103 	char buf[16] = {};
104 	socklen_t optlen;
105 
106 	optlen = sizeof(buf);
107 
108 	ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK, NETLINK_PKTINFO,
109 				buf, &optlen));
110 	ASSERT_EQ(sizeof(int), optlen);
111 }
112 
113 TEST_F(netlink, pktinfo_undersize)
114 {
115 	char buf[2] = {};
116 	socklen_t optlen;
117 
118 	optlen = sizeof(buf);
119 
120 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_NETLINK, NETLINK_PKTINFO,
121 				 buf, &optlen));
122 	ASSERT_EQ(EINVAL, errno);
123 	ASSERT_EQ(sizeof(buf), optlen);
124 }
125 
126 TEST_F(netlink, list_memberships_size_discovery)
127 {
128 	socklen_t optlen = 0;
129 	char dummy;
130 
131 	ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK,
132 				NETLINK_LIST_MEMBERSHIPS,
133 				&dummy, &optlen));
134 	ASSERT_GT(optlen, 0);
135 	ASSERT_EQ(0, optlen % sizeof(__u32));
136 }
137 
138 TEST_F(netlink, list_memberships_full_read)
139 {
140 	__u32 buf[64] = {};
141 	socklen_t optlen;
142 
143 	optlen = sizeof(buf);
144 
145 	ASSERT_EQ(0, getsockopt(self->fd, SOL_NETLINK,
146 				NETLINK_LIST_MEMBERSHIPS,
147 				buf, &optlen));
148 	ASSERT_GT(optlen, 0);
149 	ASSERT_LE(optlen, sizeof(buf));
150 	ASSERT_EQ(0, optlen % sizeof(__u32));
151 }
152 
153 TEST_F(netlink, bad_level)
154 {
155 	socklen_t optlen;
156 	int val;
157 
158 	optlen = sizeof(val);
159 
160 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_SOCKET + 1, NETLINK_PKTINFO,
161 				 &val, &optlen));
162 	ASSERT_EQ(ENOPROTOOPT, errno);
163 	ASSERT_EQ(sizeof(val), optlen);
164 }
165 
166 TEST_F(netlink, bad_optname)
167 {
168 	socklen_t optlen;
169 	int val;
170 
171 	optlen = sizeof(val);
172 
173 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_NETLINK, 0x7fff,
174 				 &val, &optlen));
175 	ASSERT_EQ(ENOPROTOOPT, errno);
176 	ASSERT_EQ(sizeof(val), optlen);
177 }
178 
179 /* ---------- vsock ---------- */
180 
181 FIXTURE(vsock)
182 {
183 	int fd;
184 };
185 
186 FIXTURE_SETUP(vsock)
187 {
188 	self->fd = socket(AF_VSOCK, SOCK_STREAM, 0);
189 	if (self->fd < 0)
190 		SKIP(return, "AF_VSOCK socket: %s", strerror(errno));
191 }
192 
193 FIXTURE_TEARDOWN(vsock)
194 {
195 	if (self->fd >= 0)
196 		close(self->fd);
197 }
198 
199 TEST_F(vsock, buffer_size_exact)
200 {
201 	socklen_t optlen;
202 	uint64_t val = 0;
203 
204 	optlen = sizeof(val);
205 
206 	ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK,
207 				SO_VM_SOCKETS_BUFFER_SIZE,
208 				&val, &optlen));
209 	ASSERT_EQ(sizeof(uint64_t), optlen);
210 	ASSERT_GT(val, 0);
211 }
212 
213 TEST_F(vsock, buffer_size_oversize_clamped)
214 {
215 	char buf[16] = {};
216 	socklen_t optlen;
217 
218 	optlen = sizeof(buf);
219 
220 	ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK,
221 				SO_VM_SOCKETS_BUFFER_SIZE,
222 				buf, &optlen));
223 	ASSERT_EQ(sizeof(uint64_t), optlen);
224 }
225 
226 TEST_F(vsock, buffer_size_undersize)
227 {
228 	char buf[4] = {};
229 	socklen_t optlen;
230 
231 	optlen = sizeof(buf);
232 
233 	ASSERT_EQ(-1, getsockopt(self->fd, AF_VSOCK,
234 				 SO_VM_SOCKETS_BUFFER_SIZE,
235 				 buf, &optlen));
236 	ASSERT_EQ(EINVAL, errno);
237 	ASSERT_EQ(sizeof(buf), optlen);
238 }
239 
240 TEST_F(vsock, bad_level)
241 {
242 	socklen_t optlen;
243 	uint64_t val;
244 
245 	optlen = sizeof(val);
246 
247 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_SOCKET + 1,
248 				 SO_VM_SOCKETS_BUFFER_SIZE,
249 				 &val, &optlen));
250 	ASSERT_EQ(ENOPROTOOPT, errno);
251 	ASSERT_EQ(sizeof(val), optlen);
252 }
253 
254 TEST_F(vsock, bad_optname)
255 {
256 	socklen_t optlen;
257 	uint64_t val;
258 
259 	optlen = sizeof(val);
260 
261 	ASSERT_EQ(-1, getsockopt(self->fd, AF_VSOCK, 0x7fff,
262 				 &val, &optlen));
263 	ASSERT_EQ(ENOPROTOOPT, errno);
264 	ASSERT_EQ(sizeof(val), optlen);
265 }
266 
267 /* SO_VM_SOCKETS_CONNECT_TIMEOUT_{NEW,OLD} return a sock_timeval-shaped
268  * payload, which is wider than u64 on 64-bit. They exercise the path
269  * where the protocol's reported lv (16 bytes) is larger than the
270  * common 8-byte u64 case covered above.
271  */
272 TEST_F(vsock, connect_timeout_new_exact)
273 {
274 	struct __kernel_sock_timeval tv = {};
275 	socklen_t optlen;
276 
277 	optlen = sizeof(tv);
278 
279 	ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK,
280 				SO_VM_SOCKETS_CONNECT_TIMEOUT_NEW,
281 				&tv, &optlen));
282 	ASSERT_EQ(sizeof(tv), optlen);
283 }
284 
285 TEST_F(vsock, connect_timeout_new_oversize_clamped)
286 {
287 	char buf[sizeof(struct __kernel_sock_timeval) * 2] = {};
288 	socklen_t optlen;
289 
290 	optlen = sizeof(buf);
291 
292 	ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK,
293 				SO_VM_SOCKETS_CONNECT_TIMEOUT_NEW,
294 				buf, &optlen));
295 	ASSERT_EQ(sizeof(struct __kernel_sock_timeval), optlen);
296 }
297 
298 TEST_F(vsock, connect_timeout_new_undersize)
299 {
300 	socklen_t optlen;
301 	uint64_t val;
302 
303 	optlen = sizeof(val);
304 
305 	ASSERT_EQ(-1, getsockopt(self->fd, AF_VSOCK,
306 				 SO_VM_SOCKETS_CONNECT_TIMEOUT_NEW,
307 				 &val, &optlen));
308 	ASSERT_EQ(EINVAL, errno);
309 	ASSERT_EQ(sizeof(val), optlen);
310 }
311 
312 TEST_F(vsock, connect_timeout_old_exact)
313 {
314 	struct __kernel_old_timeval tv = {};
315 	socklen_t optlen;
316 
317 	optlen = sizeof(tv);
318 
319 	ASSERT_EQ(0, getsockopt(self->fd, AF_VSOCK,
320 				SO_VM_SOCKETS_CONNECT_TIMEOUT_OLD,
321 				&tv, &optlen));
322 	ASSERT_EQ(sizeof(tv), optlen);
323 }
324 
325 /* ---------- raw (ipv4) ---------- */
326 
327 FIXTURE(raw)
328 {
329 	int fd;
330 };
331 
332 FIXTURE_SETUP(raw)
333 {
334 	struct icmp_filter filt = { .data = 0xdeadbeef };
335 
336 	self->fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
337 	if (self->fd < 0)
338 		SKIP(return, "SOCK_RAW/ICMP socket: %s", strerror(errno));
339 
340 	if (setsockopt(self->fd, SOL_RAW, ICMP_FILTER, &filt, sizeof(filt)) < 0)
341 		SKIP(return, "set ICMP_FILTER: %s", strerror(errno));
342 }
343 
344 FIXTURE_TEARDOWN(raw)
345 {
346 	if (self->fd >= 0)
347 		close(self->fd);
348 }
349 
350 TEST_F(raw, icmpfilter_exact)
351 {
352 	struct icmp_filter filt = {};
353 	socklen_t optlen = sizeof(filt);
354 
355 	ASSERT_EQ(0, getsockopt(self->fd, SOL_RAW, ICMP_FILTER,
356 				&filt, &optlen));
357 	ASSERT_EQ(sizeof(filt), optlen);
358 	ASSERT_EQ(0xdeadbeef, filt.data);
359 }
360 
361 TEST_F(raw, icmpfilter_oversize_clamped)
362 {
363 	char buf[16] = {};
364 	socklen_t optlen = sizeof(buf);
365 
366 	ASSERT_EQ(0, getsockopt(self->fd, SOL_RAW, ICMP_FILTER,
367 				buf, &optlen));
368 	ASSERT_EQ(sizeof(struct icmp_filter), optlen);
369 }
370 
371 /* Unlike the int/u64 options above, ICMP_FILTER clamps the length down
372  * to the user buffer instead of returning EINVAL: a short buffer
373  * succeeds and reports the truncated length back via optlen.
374  */
375 TEST_F(raw, icmpfilter_undersize_clamped)
376 {
377 	char buf[2] = {};
378 	socklen_t optlen = sizeof(buf);
379 
380 	ASSERT_EQ(0, getsockopt(self->fd, SOL_RAW, ICMP_FILTER,
381 				buf, &optlen));
382 	ASSERT_EQ(sizeof(buf), optlen);
383 }
384 
385 TEST_F(raw, icmpfilter_wrong_proto)
386 {
387 	struct icmp_filter filt;
388 	socklen_t optlen = sizeof(filt);
389 	int fd;
390 
391 	fd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
392 	if (fd < 0)
393 		SKIP(return, "SOCK_RAW/UDP socket: %s", strerror(errno));
394 
395 	ASSERT_EQ(-1, getsockopt(fd, SOL_RAW, ICMP_FILTER, &filt, &optlen));
396 	ASSERT_EQ(EOPNOTSUPP, errno);
397 	close(fd);
398 }
399 
400 TEST_F(raw, bad_optname)
401 {
402 	socklen_t optlen;
403 	int val;
404 
405 	optlen = sizeof(val);
406 
407 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_RAW, 0x7fff, &val, &optlen));
408 	ASSERT_EQ(ENOPROTOOPT, errno);
409 	ASSERT_EQ(sizeof(val), optlen);
410 }
411 
412 /* ---------- raw (ipv6) ---------- */
413 
414 FIXTURE(rawv6)
415 {
416 	int fd;
417 };
418 
419 FIXTURE_SETUP(rawv6)
420 {
421 	self->fd = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP);
422 	if (self->fd < 0)
423 		SKIP(return, "SOCK_RAW/IPv6 socket: %s", strerror(errno));
424 }
425 
426 FIXTURE_TEARDOWN(rawv6)
427 {
428 	if (self->fd >= 0)
429 		close(self->fd);
430 }
431 
432 TEST_F(rawv6, hdrincl_exact)
433 {
434 	socklen_t optlen;
435 	int val = -1;
436 
437 	optlen = sizeof(val);
438 
439 	ASSERT_EQ(0, getsockopt(self->fd, IPPROTO_IPV6, IPV6_HDRINCL,
440 				&val, &optlen));
441 	ASSERT_EQ(sizeof(int), optlen);
442 	ASSERT_TRUE(val == 0 || val == 1);
443 }
444 
445 TEST_F(rawv6, hdrincl_oversize_clamped)
446 {
447 	char buf[16] = {};
448 	socklen_t optlen = sizeof(buf);
449 
450 	ASSERT_EQ(0, getsockopt(self->fd, IPPROTO_IPV6, IPV6_HDRINCL,
451 				buf, &optlen));
452 	ASSERT_EQ(sizeof(int), optlen);
453 }
454 
455 /* Raw int options clamp the reported length down to the user buffer
456  * instead of returning EINVAL on a short buffer.
457  */
458 TEST_F(rawv6, hdrincl_undersize_clamped)
459 {
460 	socklen_t optlen = 2;
461 	int val = 0;
462 
463 	ASSERT_EQ(0, getsockopt(self->fd, IPPROTO_IPV6, IPV6_HDRINCL,
464 				&val, &optlen));
465 	ASSERT_EQ(2, optlen);
466 }
467 
468 TEST_F(rawv6, checksum_default)
469 {
470 	socklen_t optlen;
471 	int val = 0;
472 
473 	optlen = sizeof(val);
474 
475 	/* A non-ICMPv6 raw socket has the checksum disabled, reported as -1. */
476 	ASSERT_EQ(0, getsockopt(self->fd, IPPROTO_IPV6, IPV6_CHECKSUM,
477 				&val, &optlen));
478 	ASSERT_EQ(sizeof(int), optlen);
479 	ASSERT_EQ(-1, val);
480 }
481 
482 TEST_F(rawv6, bad_optname)
483 {
484 	socklen_t optlen;
485 	int val;
486 
487 	optlen = sizeof(val);
488 
489 	/* SOL_RAW reaches do_rawv6_getsockopt() directly. */
490 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_RAW, 0x7fff, &val, &optlen));
491 	ASSERT_EQ(ENOPROTOOPT, errno);
492 	ASSERT_EQ(sizeof(val), optlen);
493 }
494 
495 /* ---------- tls ---------- */
496 
497 FIXTURE(tls)
498 {
499 	int fd;
500 	int sfd;
501 };
502 
503 FIXTURE_SETUP(tls)
504 {
505 	struct sockaddr_in a = {
506 		.sin_family = AF_INET,
507 		.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
508 	};
509 	socklen_t alen = sizeof(a);
510 	int lfd;
511 
512 	self->fd = -1;
513 	self->sfd = -1;
514 
515 	lfd = socket(AF_INET, SOCK_STREAM, 0);
516 	if (lfd < 0)
517 		SKIP(return, "TCP socket: %s", strerror(errno));
518 	if (bind(lfd, (struct sockaddr *)&a, sizeof(a)) || listen(lfd, 1) ||
519 	    getsockname(lfd, (struct sockaddr *)&a, &alen)) {
520 		close(lfd);
521 		SKIP(return, "listener setup: %s", strerror(errno));
522 	}
523 	self->fd = socket(AF_INET, SOCK_STREAM, 0);
524 	if (self->fd < 0) {
525 		close(lfd);
526 		SKIP(return, "TCP socket: %s", strerror(errno));
527 	}
528 	if (connect(self->fd, (struct sockaddr *)&a, sizeof(a))) {
529 		close(lfd);
530 		SKIP(return, "connect: %s", strerror(errno));
531 	}
532 	self->sfd = accept(lfd, NULL, NULL);
533 	close(lfd);
534 	if (setsockopt(self->fd, IPPROTO_TCP, TCP_ULP, "tls", sizeof("tls")))
535 		SKIP(return, "TCP_ULP=tls: %s (built without TLS?)",
536 		     strerror(errno));
537 }
538 
539 FIXTURE_TEARDOWN(tls)
540 {
541 	if (self->fd >= 0)
542 		close(self->fd);
543 	if (self->sfd >= 0)
544 		close(self->sfd);
545 }
546 
547 /* do_tls_getsockopt_tx_zc(): fixed-size int, exact length required. */
548 TEST_F(tls, tx_zerocopy_exact)
549 {
550 	socklen_t optlen = sizeof(int);
551 	int val = -1;
552 
553 	ASSERT_EQ(0, getsockopt(self->fd, SOL_TLS, TLS_TX_ZEROCOPY_RO,
554 				&val, &optlen));
555 	ASSERT_EQ(sizeof(int), optlen);
556 	ASSERT_TRUE(val == 0 || val == 1);
557 }
558 
559 TEST_F(tls, tx_zerocopy_wrong_len)
560 {
561 	socklen_t optlen = 2;
562 	int val;
563 
564 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_TLS, TLS_TX_ZEROCOPY_RO,
565 				 &val, &optlen));
566 	ASSERT_EQ(EINVAL, errno);
567 }
568 
569 /* do_tls_getsockopt_conf(): NULL optval still yields EINVAL -- the
570  * converted code tests opt->iter_out.ubuf in place of optval.
571  */
572 TEST_F(tls, conf_null_optval)
573 {
574 	socklen_t optlen = 64;
575 
576 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_TLS, TLS_TX, NULL, &optlen));
577 	ASSERT_EQ(EINVAL, errno);
578 }
579 
580 TEST_F(tls, conf_short)
581 {
582 	socklen_t optlen = 2;
583 	char buf[2];
584 
585 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_TLS, TLS_TX, buf, &optlen));
586 	ASSERT_EQ(EINVAL, errno);
587 }
588 
589 /* TLS_TX before crypto is set reports not-ready. */
590 TEST_F(tls, conf_not_ready)
591 {
592 	struct tls_crypto_info info;
593 	socklen_t optlen = sizeof(info);
594 
595 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_TLS, TLS_TX, &info, &optlen));
596 	ASSERT_EQ(EBUSY, errno);
597 }
598 
599 /* Set TX crypto, then read it back at the base and full sizes, exercising
600  * both copy_to_iter() branches. SKIP if AES-GCM is unavailable.
601  */
602 TEST_F(tls, conf_crypto_roundtrip)
603 {
604 	struct tls12_crypto_info_aes_gcm_128 tx = {
605 		.info.version = TLS_1_2_VERSION,
606 		.info.cipher_type = TLS_CIPHER_AES_GCM_128,
607 	};
608 	struct tls12_crypto_info_aes_gcm_128 full;
609 	struct tls_crypto_info base;
610 	socklen_t optlen;
611 
612 	if (setsockopt(self->fd, SOL_TLS, TLS_TX, &tx, sizeof(tx)))
613 		SKIP(return, "set TLS_TX aes_gcm_128: %s", strerror(errno));
614 
615 	optlen = sizeof(base);
616 	ASSERT_EQ(0, getsockopt(self->fd, SOL_TLS, TLS_TX, &base, &optlen));
617 	ASSERT_EQ(sizeof(base), optlen);
618 	ASSERT_EQ(TLS_1_2_VERSION, base.version);
619 	ASSERT_EQ(TLS_CIPHER_AES_GCM_128, base.cipher_type);
620 
621 	optlen = sizeof(full);
622 	ASSERT_EQ(0, getsockopt(self->fd, SOL_TLS, TLS_TX, &full, &optlen));
623 	ASSERT_EQ(sizeof(full), optlen);
624 	ASSERT_EQ(TLS_CIPHER_AES_GCM_128, full.info.cipher_type);
625 }
626 
627 TEST_F(tls, bad_optname)
628 {
629 	socklen_t optlen = sizeof(int);
630 	int val;
631 
632 	ASSERT_EQ(-1, getsockopt(self->fd, SOL_TLS, 0x7fff, &val, &optlen));
633 	ASSERT_EQ(ENOPROTOOPT, errno);
634 }
635 
636 TEST_HARNESS_MAIN
637