1 // SPDX-License-Identifier: GPL-2.0
2 /* Test IPV6_FLOWINFO_MGR */
3
4 #define _GNU_SOURCE
5
6 #include <arpa/inet.h>
7 #include <error.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <limits.h>
11 #include <linux/in6.h>
12 #include <net/if.h>
13 #include <sched.h>
14 #include <stdbool.h>
15 #include <stdio.h>
16 #include <stdint.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/ioctl.h>
20 #include <sys/socket.h>
21 #include <sys/stat.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <unistd.h>
26 #include "kselftest_harness.h"
27
28 /* uapi/glibc weirdness may leave this undefined */
29 #ifndef IPV6_FLOWLABEL_MGR
30 #define IPV6_FLOWLABEL_MGR 32
31 #endif
32 #ifndef IPV6_FLOWINFO_SEND
33 #define IPV6_FLOWINFO_SEND 33
34 #endif
35
36 /* from net/ipv6/ip6_flowlabel.c */
37 #define FL_MIN_LINGER 6
38
flowlabel_get(int fd,uint32_t label,uint8_t share,uint16_t flags)39 static int flowlabel_get(int fd, uint32_t label, uint8_t share, uint16_t flags)
40 {
41 struct in6_flowlabel_req req = {
42 .flr_action = IPV6_FL_A_GET,
43 .flr_label = htonl(label),
44 .flr_flags = flags,
45 .flr_share = share,
46 };
47
48 /* do not pass IPV6_ADDR_ANY or IPV6_ADDR_MAPPED */
49 req.flr_dst.s6_addr[0] = 0xfd;
50 req.flr_dst.s6_addr[15] = 0x1;
51
52 return setsockopt(fd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &req, sizeof(req));
53 }
54
flowlabel_put(int fd,uint32_t label)55 static int flowlabel_put(int fd, uint32_t label)
56 {
57 struct in6_flowlabel_req req = {
58 .flr_action = IPV6_FL_A_PUT,
59 .flr_label = htonl(label),
60 };
61
62 return setsockopt(fd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &req, sizeof(req));
63 }
64
flowlabel_renew(int fd,uint32_t label,uint8_t share,uint16_t linger)65 static int flowlabel_renew(int fd, uint32_t label, uint8_t share,
66 uint16_t linger)
67 {
68 struct in6_flowlabel_req req = {
69 .flr_action = IPV6_FL_A_RENEW,
70 .flr_label = htonl(label),
71 .flr_share = share,
72 .flr_linger = linger,
73 };
74
75 return setsockopt(fd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &req, sizeof(req));
76 }
77
loopback_addr(void)78 static struct sockaddr_in6 loopback_addr(void)
79 {
80 struct sockaddr_in6 addr = {
81 .sin6_family = AF_INET6,
82 .sin6_addr = IN6ADDR_LOOPBACK_INIT,
83 .sin6_port = htons(8888),
84 };
85
86 return addr;
87 }
88
tcp_listen(void)89 static int tcp_listen(void)
90 {
91 struct sockaddr_in6 addr = loopback_addr();
92 const int one = 1;
93 int fd;
94
95 fd = socket(PF_INET6, SOCK_STREAM, 0);
96 if (fd == -1)
97 error(1, errno, "socket listener");
98 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)))
99 error(1, errno, "setsockopt SO_REUSEADDR");
100 if (bind(fd, (void *)&addr, sizeof(addr)))
101 error(1, errno, "bind");
102 if (listen(fd, 1))
103 error(1, errno, "listen");
104
105 return fd;
106 }
107
tcp_connect(int listener,uint32_t flowlabel,int * client,int * accepted)108 static void tcp_connect(int listener, uint32_t flowlabel,
109 int *client, int *accepted)
110 {
111 struct sockaddr_in6 addr = loopback_addr();
112 const int one = 1;
113 int cfd, afd;
114
115 cfd = socket(PF_INET6, SOCK_STREAM, 0);
116 if (cfd == -1)
117 error(1, errno, "socket client");
118
119 if (flowlabel_get(cfd, flowlabel, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE))
120 error(1, errno, "flowlabel_get");
121 if (setsockopt(cfd, SOL_IPV6, IPV6_FLOWINFO_SEND, &one, sizeof(one)))
122 error(1, errno, "setsockopt flowinfo_send");
123 addr.sin6_flowinfo = htonl(flowlabel);
124
125 if (connect(cfd, (void *)&addr, sizeof(addr)))
126 error(1, errno, "connect");
127
128 afd = accept(listener, NULL, NULL);
129 if (afd == -1)
130 error(1, errno, "accept");
131
132 if (flowlabel_put(cfd, flowlabel))
133 error(1, errno, "flowlabel_put");
134
135 *client = cfd;
136 *accepted = afd;
137 }
138
bringup_loopback(void)139 static int bringup_loopback(void)
140 {
141 struct ifreq ifr = {
142 .ifr_name = "lo"
143 };
144 int fd;
145
146 fd = socket(AF_LOCAL, SOCK_STREAM, 0);
147 if (fd < 0)
148 return -1;
149
150 if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
151 goto err;
152
153 ifr.ifr_flags = ifr.ifr_flags | IFF_UP;
154
155 if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0)
156 goto err;
157
158 close(fd);
159 return 0;
160
161 err:
162 close(fd);
163 return -1;
164 }
165
FIXTURE(flowlabel)166 FIXTURE(flowlabel) {};
167
FIXTURE_SETUP(flowlabel)168 FIXTURE_SETUP(flowlabel)
169 {
170 int ret;
171
172 ret = unshare(CLONE_NEWNET);
173 ASSERT_EQ(ret, 0) {
174 TH_LOG("unshare(CLONE_NEWNET) failed: %s", strerror(errno));
175 }
176
177 ret = bringup_loopback();
178 ASSERT_EQ(ret, 0) TH_LOG("Failed to bring up loopback interface");
179 }
180
FIXTURE_TEARDOWN(flowlabel)181 FIXTURE_TEARDOWN(flowlabel)
182 {
183 }
184
TEST_F(flowlabel,cannot_get_non_existent_label)185 TEST_F(flowlabel, cannot_get_non_existent_label)
186 {
187 int fd, err;
188
189 fd = socket(PF_INET6, SOCK_DGRAM, 0);
190 ASSERT_GE(fd, 0) TH_LOG("socket failed");
191
192 err = flowlabel_get(fd, 9, IPV6_FL_S_ANY, 0);
193 EXPECT_TRUE(err) TH_LOG("expected get of a non-existent label to fail");
194 EXPECT_EQ(ENOENT, errno) TH_LOG("expected ENOENT, got %d", errno);
195
196 EXPECT_EQ(0, close(fd));
197 }
198
TEST_F(flowlabel,cannot_put_non_existent_label)199 TEST_F(flowlabel, cannot_put_non_existent_label)
200 {
201 int fd, err;
202
203 fd = socket(PF_INET6, SOCK_DGRAM, 0);
204 ASSERT_GE(fd, 0) TH_LOG("socket failed");
205
206 err = flowlabel_put(fd, 10);
207 EXPECT_TRUE(err) TH_LOG("expected put of a non-existent label to fail");
208 EXPECT_EQ(ESRCH, errno) TH_LOG("expected ESRCH, got %d", errno);
209
210 EXPECT_EQ(0, close(fd));
211 }
212
TEST_F(flowlabel,cannot_create_label_greater_than_20_bits)213 TEST_F(flowlabel, cannot_create_label_greater_than_20_bits)
214 {
215 int fd, err;
216
217 fd = socket(PF_INET6, SOCK_DGRAM, 0);
218 ASSERT_GE(fd, 0) TH_LOG("socket failed");
219
220 err = flowlabel_get(fd, 0x1FFFFF, IPV6_FL_S_ANY, IPV6_FL_F_CREATE);
221 EXPECT_TRUE(err) TH_LOG("expected label > 20 bits to be rejected");
222 EXPECT_EQ(EINVAL, errno) TH_LOG("expected EINVAL, got %d", errno);
223
224 EXPECT_EQ(0, close(fd));
225 }
226
TEST_F(flowlabel,can_create_and_get_and_put_labels)227 TEST_F(flowlabel, can_create_and_get_and_put_labels)
228 {
229 int fd, err;
230
231 fd = socket(PF_INET6, SOCK_DGRAM, 0);
232 ASSERT_GE(fd, 0) TH_LOG("socket failed");
233
234 err = flowlabel_get(fd, 1, IPV6_FL_S_ANY, IPV6_FL_F_CREATE);
235 EXPECT_TRUE(!err) TH_LOG("failed to create label (FL_F_CREATE)");
236
237 err = flowlabel_get(fd, 1, IPV6_FL_S_ANY, 0);
238 EXPECT_TRUE(!err) TH_LOG("failed to get the label without FL_F_CREATE");
239
240 err = flowlabel_get(fd, 1, IPV6_FL_S_ANY, IPV6_FL_F_CREATE);
241 EXPECT_TRUE(!err)
242 TH_LOG("failed to get it again with create flag set, too");
243
244 err = flowlabel_get(fd, 1, IPV6_FL_S_ANY,
245 IPV6_FL_F_CREATE | IPV6_FL_F_EXCL);
246 EXPECT_TRUE(err)
247 TH_LOG("expected FL_F_EXCL to reject existing label");
248 EXPECT_EQ(EEXIST, errno) TH_LOG("expected EEXIST, got %d", errno);
249
250 err = flowlabel_put(fd, 1);
251 EXPECT_TRUE(!err) TH_LOG("failed to put first reference");
252 err = flowlabel_put(fd, 1);
253 EXPECT_TRUE(!err) TH_LOG("failed to put second reference");
254 err = flowlabel_put(fd, 1);
255 EXPECT_TRUE(!err) TH_LOG("failed to put third reference");
256 err = flowlabel_put(fd, 1);
257 EXPECT_TRUE(err)
258 TH_LOG("expected fourth put to fail, no references left");
259 EXPECT_EQ(ESRCH, errno) TH_LOG("expected ESRCH, got %d", errno);
260
261 EXPECT_EQ(0, close(fd));
262 }
263
TEST_F(flowlabel,exclusive_label_share)264 TEST_F(flowlabel, exclusive_label_share)
265 {
266 int fd, err;
267
268 fd = socket(PF_INET6, SOCK_DGRAM, 0);
269 ASSERT_GE(fd, 0) TH_LOG("socket failed");
270
271 err = flowlabel_get(fd, 2, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE);
272 EXPECT_TRUE(!err)
273 TH_LOG("failed to create a new exclusive label (FL_S_EXCL)");
274
275 err = flowlabel_get(fd, 2, IPV6_FL_S_ANY, IPV6_FL_F_CREATE);
276 EXPECT_TRUE(err) TH_LOG("expected reuse in non-exclusive mode to fail");
277 EXPECT_EQ(EPERM, errno) TH_LOG("expected EPERM, got %d", errno);
278
279 err = flowlabel_get(fd, 2, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE);
280 EXPECT_TRUE(err) TH_LOG("expected reuse in exclusive mode to fail too");
281 EXPECT_EQ(EPERM, errno) TH_LOG("expected EPERM, got %d", errno);
282
283 err = flowlabel_put(fd, 2);
284 EXPECT_TRUE(!err) TH_LOG("failed to put the exclusive label");
285
286 err = flowlabel_get(fd, 2, IPV6_FL_S_ANY, IPV6_FL_F_CREATE);
287 EXPECT_TRUE(err) TH_LOG("expected reuse to fail, due to linger");
288 EXPECT_EQ(EPERM, errno) TH_LOG("expected EPERM, got %d", errno);
289
290 sleep(FL_MIN_LINGER * 2 + 1);
291
292 err = flowlabel_get(fd, 2, IPV6_FL_S_ANY, IPV6_FL_F_CREATE);
293 EXPECT_TRUE(!err) TH_LOG("expected reuse to succeed after linger");
294
295 EXPECT_EQ(0, close(fd));
296 }
297
TEST_F(flowlabel,user_private_label_share)298 TEST_F(flowlabel, user_private_label_share)
299 {
300 int fd, err, wstatus;
301 pid_t pid;
302
303 fd = socket(PF_INET6, SOCK_DGRAM, 0);
304 ASSERT_GE(fd, 0) TH_LOG("socket failed");
305
306 err = flowlabel_get(fd, 3, IPV6_FL_S_USER, IPV6_FL_F_CREATE);
307 EXPECT_TRUE(!err)
308 TH_LOG("failed to create a new user-private label (FL_S_USER)");
309
310 err = flowlabel_get(fd, 3, IPV6_FL_S_ANY, 0);
311 EXPECT_TRUE(err) TH_LOG("expected get in non-exclusive mode to fail");
312 EXPECT_EQ(EPERM, errno) TH_LOG("expected EPERM, got %d", errno);
313
314 err = flowlabel_get(fd, 3, IPV6_FL_S_EXCL, 0);
315 EXPECT_TRUE(err) TH_LOG("expected get in exclusive mode to fail");
316 EXPECT_EQ(EPERM, errno) TH_LOG("expected EPERM, got %d", errno);
317
318 err = flowlabel_get(fd, 3, IPV6_FL_S_USER, 0);
319 EXPECT_TRUE(!err) TH_LOG("failed to get it again in user mode");
320
321 pid = fork();
322 ASSERT_NE(-1, pid) TH_LOG("fork failed");
323 if (!pid) {
324 err = flowlabel_get(fd, 3, IPV6_FL_S_USER, 0);
325 EXPECT_TRUE(!err)
326 TH_LOG("child failed to get the user-private label");
327
328 if (setuid(USHRT_MAX))
329 exit(KSFT_SKIP);
330
331 err = flowlabel_get(fd, 3, IPV6_FL_S_USER, 0);
332 EXPECT_TRUE(err)
333 TH_LOG("child unexpectedly got label after setuid");
334 EXPECT_EQ(EPERM, errno) TH_LOG("expected EPERM, got %d", errno);
335 exit(0);
336 }
337 ASSERT_EQ(pid, wait(&wstatus)) TH_LOG("wait failed");
338 ASSERT_TRUE(WIFEXITED(wstatus)) TH_LOG("child did not exit normally");
339 if (WEXITSTATUS(wstatus) == KSFT_SKIP)
340 SKIP(return,
341 "setuid(USHRT_MAX) unavailable (no CAP_SETUID or uid unmapped)");
342 EXPECT_EQ(0, WEXITSTATUS(wstatus))
343 TH_LOG("child reported unexpected result");
344
345 EXPECT_EQ(0, close(fd));
346 }
347
TEST_F(flowlabel,process_private_label_share)348 TEST_F(flowlabel, process_private_label_share)
349 {
350 int fd, err, wstatus;
351 pid_t pid;
352
353 fd = socket(PF_INET6, SOCK_DGRAM, 0);
354 ASSERT_GE(fd, 0) TH_LOG("socket failed");
355
356 err = flowlabel_get(fd, 4, IPV6_FL_S_PROCESS, IPV6_FL_F_CREATE);
357 EXPECT_TRUE(!err)
358 TH_LOG("failed to create a new process-private label");
359
360 err = flowlabel_get(fd, 4, IPV6_FL_S_PROCESS, 0);
361 EXPECT_TRUE(!err) TH_LOG("failed to get it again");
362
363 pid = fork();
364 ASSERT_NE(-1, pid) TH_LOG("fork failed");
365 if (!pid) {
366 err = flowlabel_get(fd, 4, IPV6_FL_S_PROCESS, 0);
367 EXPECT_TRUE(err)
368 TH_LOG("child unexpectedly got process-private label");
369 EXPECT_EQ(EPERM, errno) TH_LOG("expected EPERM, got %d", errno);
370 exit(0);
371 }
372 ASSERT_EQ(pid, wait(&wstatus)) TH_LOG("wait failed");
373 ASSERT_TRUE(WIFEXITED(wstatus)) TH_LOG("child did not exit normally");
374 EXPECT_EQ(0, WEXITSTATUS(wstatus))
375 TH_LOG("child reported unexpected result");
376
377 EXPECT_EQ(0, close(fd));
378 }
379
TEST_F(flowlabel,cannot_renew_non_existent_label)380 TEST_F(flowlabel, cannot_renew_non_existent_label)
381 {
382 int fd, err;
383
384 fd = socket(PF_INET6, SOCK_DGRAM, 0);
385 ASSERT_GE(fd, 0) TH_LOG("socket failed");
386
387 err = flowlabel_renew(fd, 5, IPV6_FL_S_EXCL,
388 2 * (FL_MIN_LINGER * 2 + 1));
389 EXPECT_TRUE(err)
390 TH_LOG("expected renew of a non-existent label to fail");
391 EXPECT_EQ(ESRCH, errno) TH_LOG("expected ESRCH, got %d", errno);
392
393 EXPECT_EQ(0, close(fd));
394 }
395
TEST_F(flowlabel,can_renew_existing_label)396 TEST_F(flowlabel, can_renew_existing_label)
397 {
398 int fd, err;
399
400 fd = socket(PF_INET6, SOCK_DGRAM, 0);
401 ASSERT_GE(fd, 0) TH_LOG("socket failed");
402
403 err = flowlabel_get(fd, 5, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE);
404 EXPECT_TRUE(!err)
405 TH_LOG("failed to create a new label for renew validation");
406
407 err = flowlabel_renew(fd, 5, IPV6_FL_S_EXCL,
408 2 * (FL_MIN_LINGER * 2 + 1));
409 EXPECT_TRUE(!err) TH_LOG("failed to renew an existing valid label");
410
411 err = flowlabel_put(fd, 5);
412 EXPECT_TRUE(!err) TH_LOG("failed to put the label");
413
414 EXPECT_EQ(0, close(fd));
415 }
416
TEST_F(flowlabel,renew_label_linger)417 TEST_F(flowlabel, renew_label_linger)
418 {
419 /* RENEW must extend a label's linger period: putting a renewed
420 * label and waiting out its original linger time must not be
421 * enough to allow the label to be recreated.
422 */
423 int fd, err;
424
425 fd = socket(PF_INET6, SOCK_DGRAM, 0);
426 ASSERT_GE(fd, 0) TH_LOG("socket failed");
427
428 err = flowlabel_get(fd, 6, IPV6_FL_S_EXCL, IPV6_FL_F_CREATE);
429 EXPECT_TRUE(!err)
430 TH_LOG("failed to create label with FL_MIN_LINGER linger time");
431
432 err = flowlabel_renew(fd, 6, IPV6_FL_S_EXCL,
433 2 * (FL_MIN_LINGER * 2 + 1));
434 EXPECT_TRUE(!err)
435 TH_LOG("failed to renew the label to increase its linger time");
436
437 err = flowlabel_put(fd, 6);
438 EXPECT_TRUE(!err) TH_LOG("failed to put the label");
439
440 sleep(FL_MIN_LINGER * 2 + 1);
441
442 err = flowlabel_get(fd, 6, IPV6_FL_S_ANY, IPV6_FL_F_CREATE);
443 EXPECT_TRUE(err)
444 TH_LOG("expected reuse to fail, new linger time not over yet");
445 EXPECT_EQ(EPERM, errno) TH_LOG("expected EPERM, got %d", errno);
446
447 EXPECT_EQ(0, close(fd));
448 }
449
TEST_F(flowlabel,remote_flag)450 TEST_F(flowlabel, remote_flag)
451 {
452 /* The REMOTE flag, used for getsockopt, is expected to retrieve the
453 * label from the latest received header.
454 */
455 struct in6_flowlabel_req freq = {
456 .flr_action = IPV6_FL_A_GET,
457 .flr_flags = IPV6_FL_F_REMOTE,
458 };
459 socklen_t freq_len = sizeof(freq);
460 int listener, cfd, afd, err;
461
462 listener = tcp_listen();
463 tcp_connect(listener, 7, &cfd, &afd);
464
465 err = getsockopt(afd, SOL_IPV6, IPV6_FLOWLABEL_MGR, &freq, &freq_len);
466 EXPECT_TRUE(!err) TH_LOG("getsockopt with IPV6_FL_F_REMOTE failed");
467 EXPECT_EQ(7, ntohl(freq.flr_label))
468 TH_LOG("unexpected remote flow label");
469
470 EXPECT_EQ(0, close(afd));
471 EXPECT_EQ(0, close(cfd));
472 EXPECT_EQ(0, close(listener));
473 }
474
disable_flowlabel_consistency(void)475 static bool disable_flowlabel_consistency(void)
476 {
477 int fd;
478
479 fd = open("/proc/sys/net/ipv6/flowlabel_consistency", O_WRONLY);
480 if (fd == -1)
481 return false;
482
483 if (write(fd, "0", 1) != 1) {
484 close(fd);
485 return false;
486 }
487 close(fd);
488
489 return true;
490 }
491
TEST_F(flowlabel,reflect_flag)492 TEST_F(flowlabel, reflect_flag)
493 {
494 /* The REFLECT flag acts as a trigger to the REPFLOW bit. When REPFLOW
495 * is triggered for a socket, it adopts the label received from the
496 * connected socket.
497 */
498 struct in6_flowlabel_req reflect_on = {
499 .flr_action = IPV6_FL_A_GET,
500 .flr_flags = IPV6_FL_F_REFLECT,
501 };
502 struct in6_flowlabel_req reflect_query = {
503 .flr_action = IPV6_FL_A_GET,
504 };
505 struct in6_flowlabel_req reflect_off = {
506 .flr_action = IPV6_FL_A_PUT,
507 .flr_flags = IPV6_FL_F_REFLECT,
508 };
509 socklen_t reflect_query_len = sizeof(reflect_query);
510 int listener, cfd, afd, err;
511
512 if (!disable_flowlabel_consistency())
513 SKIP(return,
514 "cannot disable net.ipv6.flowlabel_consistency");
515
516 listener = tcp_listen();
517 err = setsockopt(listener, SOL_IPV6, IPV6_FLOWLABEL_MGR,
518 &reflect_on, sizeof(reflect_on));
519 EXPECT_TRUE(!err) TH_LOG("failed to enable REFLECT on the listener");
520
521 tcp_connect(listener, 8, &cfd, &afd);
522
523 err = getsockopt(afd, SOL_IPV6, IPV6_FLOWLABEL_MGR,
524 &reflect_query, &reflect_query_len);
525 EXPECT_TRUE(!err)
526 TH_LOG("failed to query the accepted socket's outgoing label");
527 EXPECT_EQ(8, ntohl(reflect_query.flr_label))
528 TH_LOG("accepted socket did not reflect client's label");
529
530 err = setsockopt(afd, SOL_IPV6, IPV6_FLOWLABEL_MGR,
531 &reflect_off, sizeof(reflect_off));
532 EXPECT_TRUE(!err)
533 TH_LOG("failed to disable REFLECT on the accepted socket");
534
535 err = setsockopt(afd, SOL_IPV6, IPV6_FLOWLABEL_MGR,
536 &reflect_off, sizeof(reflect_off));
537 EXPECT_TRUE(err) TH_LOG("expected disabling REFLECT twice to fail");
538 EXPECT_EQ(ESRCH, errno) TH_LOG("expected ESRCH, got %d", errno);
539
540 EXPECT_EQ(0, close(afd));
541 EXPECT_EQ(0, close(cfd));
542 EXPECT_EQ(0, close(listener));
543 }
544
545 TEST_HARNESS_MAIN
546