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 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 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 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 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 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 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 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 166 FIXTURE(flowlabel) {}; 167 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 181 FIXTURE_TEARDOWN(flowlabel) 182 { 183 } 184 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 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 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 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 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 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 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 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 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 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 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 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 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