| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * NET3 IP device support routines. |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or |
|---|
| 5 | | - * modify it under the terms of the GNU General Public License |
|---|
| 6 | | - * as published by the Free Software Foundation; either version |
|---|
| 7 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 8 | 4 | * |
|---|
| 9 | 5 | * Derived from the IP parts of dev.c 1.0.19 |
|---|
| 10 | 6 | * Authors: Ross Biro |
|---|
| .. | .. |
|---|
| 105 | 101 | [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, |
|---|
| 106 | 102 | [IFA_FLAGS] = { .type = NLA_U32 }, |
|---|
| 107 | 103 | [IFA_RT_PRIORITY] = { .type = NLA_U32 }, |
|---|
| 104 | + [IFA_TARGET_NETNSID] = { .type = NLA_S32 }, |
|---|
| 105 | +}; |
|---|
| 106 | + |
|---|
| 107 | +struct inet_fill_args { |
|---|
| 108 | + u32 portid; |
|---|
| 109 | + u32 seq; |
|---|
| 110 | + int event; |
|---|
| 111 | + unsigned int flags; |
|---|
| 112 | + int netnsid; |
|---|
| 113 | + int ifindex; |
|---|
| 108 | 114 | }; |
|---|
| 109 | 115 | |
|---|
| 110 | 116 | #define IN4_ADDR_HSIZE_SHIFT 8 |
|---|
| .. | .. |
|---|
| 189 | 195 | |
|---|
| 190 | 196 | static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); |
|---|
| 191 | 197 | static BLOCKING_NOTIFIER_HEAD(inetaddr_validator_chain); |
|---|
| 192 | | -static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, |
|---|
| 198 | +static void inet_del_ifa(struct in_device *in_dev, |
|---|
| 199 | + struct in_ifaddr __rcu **ifap, |
|---|
| 193 | 200 | int destroy); |
|---|
| 194 | 201 | #ifdef CONFIG_SYSCTL |
|---|
| 195 | 202 | static int devinet_sysctl_register(struct in_device *idev); |
|---|
| .. | .. |
|---|
| 296 | 303 | |
|---|
| 297 | 304 | static void inetdev_destroy(struct in_device *in_dev) |
|---|
| 298 | 305 | { |
|---|
| 299 | | - struct in_ifaddr *ifa; |
|---|
| 300 | 306 | struct net_device *dev; |
|---|
| 307 | + struct in_ifaddr *ifa; |
|---|
| 301 | 308 | |
|---|
| 302 | 309 | ASSERT_RTNL(); |
|---|
| 303 | 310 | |
|---|
| .. | .. |
|---|
| 307 | 314 | |
|---|
| 308 | 315 | ip_mc_destroy_dev(in_dev); |
|---|
| 309 | 316 | |
|---|
| 310 | | - while ((ifa = in_dev->ifa_list) != NULL) { |
|---|
| 317 | + while ((ifa = rtnl_dereference(in_dev->ifa_list)) != NULL) { |
|---|
| 311 | 318 | inet_del_ifa(in_dev, &in_dev->ifa_list, 0); |
|---|
| 312 | 319 | inet_free_ifa(ifa); |
|---|
| 313 | 320 | } |
|---|
| .. | .. |
|---|
| 323 | 330 | |
|---|
| 324 | 331 | int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b) |
|---|
| 325 | 332 | { |
|---|
| 333 | + const struct in_ifaddr *ifa; |
|---|
| 334 | + |
|---|
| 326 | 335 | rcu_read_lock(); |
|---|
| 327 | | - for_primary_ifa(in_dev) { |
|---|
| 336 | + in_dev_for_each_ifa_rcu(ifa, in_dev) { |
|---|
| 328 | 337 | if (inet_ifa_match(a, ifa)) { |
|---|
| 329 | 338 | if (!b || inet_ifa_match(b, ifa)) { |
|---|
| 330 | 339 | rcu_read_unlock(); |
|---|
| 331 | 340 | return 1; |
|---|
| 332 | 341 | } |
|---|
| 333 | 342 | } |
|---|
| 334 | | - } endfor_ifa(in_dev); |
|---|
| 343 | + } |
|---|
| 335 | 344 | rcu_read_unlock(); |
|---|
| 336 | 345 | return 0; |
|---|
| 337 | 346 | } |
|---|
| 338 | 347 | |
|---|
| 339 | | -static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, |
|---|
| 340 | | - int destroy, struct nlmsghdr *nlh, u32 portid) |
|---|
| 348 | +static void __inet_del_ifa(struct in_device *in_dev, |
|---|
| 349 | + struct in_ifaddr __rcu **ifap, |
|---|
| 350 | + int destroy, struct nlmsghdr *nlh, u32 portid) |
|---|
| 341 | 351 | { |
|---|
| 342 | 352 | struct in_ifaddr *promote = NULL; |
|---|
| 343 | | - struct in_ifaddr *ifa, *ifa1 = *ifap; |
|---|
| 344 | | - struct in_ifaddr *last_prim = in_dev->ifa_list; |
|---|
| 353 | + struct in_ifaddr *ifa, *ifa1; |
|---|
| 354 | + struct in_ifaddr __rcu **last_prim; |
|---|
| 345 | 355 | struct in_ifaddr *prev_prom = NULL; |
|---|
| 346 | 356 | int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev); |
|---|
| 347 | 357 | |
|---|
| 348 | 358 | ASSERT_RTNL(); |
|---|
| 349 | 359 | |
|---|
| 360 | + ifa1 = rtnl_dereference(*ifap); |
|---|
| 361 | + last_prim = ifap; |
|---|
| 350 | 362 | if (in_dev->dead) |
|---|
| 351 | 363 | goto no_promotions; |
|---|
| 352 | 364 | |
|---|
| .. | .. |
|---|
| 355 | 367 | **/ |
|---|
| 356 | 368 | |
|---|
| 357 | 369 | if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) { |
|---|
| 358 | | - struct in_ifaddr **ifap1 = &ifa1->ifa_next; |
|---|
| 370 | + struct in_ifaddr __rcu **ifap1 = &ifa1->ifa_next; |
|---|
| 359 | 371 | |
|---|
| 360 | | - while ((ifa = *ifap1) != NULL) { |
|---|
| 372 | + while ((ifa = rtnl_dereference(*ifap1)) != NULL) { |
|---|
| 361 | 373 | if (!(ifa->ifa_flags & IFA_F_SECONDARY) && |
|---|
| 362 | 374 | ifa1->ifa_scope <= ifa->ifa_scope) |
|---|
| 363 | | - last_prim = ifa; |
|---|
| 375 | + last_prim = &ifa->ifa_next; |
|---|
| 364 | 376 | |
|---|
| 365 | 377 | if (!(ifa->ifa_flags & IFA_F_SECONDARY) || |
|---|
| 366 | 378 | ifa1->ifa_mask != ifa->ifa_mask || |
|---|
| .. | .. |
|---|
| 390 | 402 | * and later to add them back with new prefsrc. Do this |
|---|
| 391 | 403 | * while all addresses are on the device list. |
|---|
| 392 | 404 | */ |
|---|
| 393 | | - for (ifa = promote; ifa; ifa = ifa->ifa_next) { |
|---|
| 405 | + for (ifa = promote; ifa; ifa = rtnl_dereference(ifa->ifa_next)) { |
|---|
| 394 | 406 | if (ifa1->ifa_mask == ifa->ifa_mask && |
|---|
| 395 | 407 | inet_ifa_match(ifa1->ifa_address, ifa)) |
|---|
| 396 | 408 | fib_del_ifaddr(ifa, ifa1); |
|---|
| .. | .. |
|---|
| 416 | 428 | blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); |
|---|
| 417 | 429 | |
|---|
| 418 | 430 | if (promote) { |
|---|
| 419 | | - struct in_ifaddr *next_sec = promote->ifa_next; |
|---|
| 431 | + struct in_ifaddr *next_sec; |
|---|
| 420 | 432 | |
|---|
| 433 | + next_sec = rtnl_dereference(promote->ifa_next); |
|---|
| 421 | 434 | if (prev_prom) { |
|---|
| 422 | | - prev_prom->ifa_next = promote->ifa_next; |
|---|
| 423 | | - promote->ifa_next = last_prim->ifa_next; |
|---|
| 424 | | - last_prim->ifa_next = promote; |
|---|
| 435 | + struct in_ifaddr *last_sec; |
|---|
| 436 | + |
|---|
| 437 | + rcu_assign_pointer(prev_prom->ifa_next, next_sec); |
|---|
| 438 | + |
|---|
| 439 | + last_sec = rtnl_dereference(*last_prim); |
|---|
| 440 | + rcu_assign_pointer(promote->ifa_next, last_sec); |
|---|
| 441 | + rcu_assign_pointer(*last_prim, promote); |
|---|
| 425 | 442 | } |
|---|
| 426 | 443 | |
|---|
| 427 | 444 | promote->ifa_flags &= ~IFA_F_SECONDARY; |
|---|
| 428 | 445 | rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid); |
|---|
| 429 | 446 | blocking_notifier_call_chain(&inetaddr_chain, |
|---|
| 430 | 447 | NETDEV_UP, promote); |
|---|
| 431 | | - for (ifa = next_sec; ifa; ifa = ifa->ifa_next) { |
|---|
| 448 | + for (ifa = next_sec; ifa; |
|---|
| 449 | + ifa = rtnl_dereference(ifa->ifa_next)) { |
|---|
| 432 | 450 | if (ifa1->ifa_mask != ifa->ifa_mask || |
|---|
| 433 | 451 | !inet_ifa_match(ifa1->ifa_address, ifa)) |
|---|
| 434 | 452 | continue; |
|---|
| .. | .. |
|---|
| 440 | 458 | inet_free_ifa(ifa1); |
|---|
| 441 | 459 | } |
|---|
| 442 | 460 | |
|---|
| 443 | | -static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, |
|---|
| 461 | +static void inet_del_ifa(struct in_device *in_dev, |
|---|
| 462 | + struct in_ifaddr __rcu **ifap, |
|---|
| 444 | 463 | int destroy) |
|---|
| 445 | 464 | { |
|---|
| 446 | 465 | __inet_del_ifa(in_dev, ifap, destroy, NULL, 0); |
|---|
| .. | .. |
|---|
| 453 | 472 | static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh, |
|---|
| 454 | 473 | u32 portid, struct netlink_ext_ack *extack) |
|---|
| 455 | 474 | { |
|---|
| 475 | + struct in_ifaddr __rcu **last_primary, **ifap; |
|---|
| 456 | 476 | struct in_device *in_dev = ifa->ifa_dev; |
|---|
| 457 | | - struct in_ifaddr *ifa1, **ifap, **last_primary; |
|---|
| 458 | 477 | struct in_validator_info ivi; |
|---|
| 478 | + struct in_ifaddr *ifa1; |
|---|
| 459 | 479 | int ret; |
|---|
| 460 | 480 | |
|---|
| 461 | 481 | ASSERT_RTNL(); |
|---|
| .. | .. |
|---|
| 471 | 491 | /* Don't set IPv6 only flags to IPv4 addresses */ |
|---|
| 472 | 492 | ifa->ifa_flags &= ~IPV6ONLY_FLAGS; |
|---|
| 473 | 493 | |
|---|
| 474 | | - for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL; |
|---|
| 475 | | - ifap = &ifa1->ifa_next) { |
|---|
| 494 | + ifap = &in_dev->ifa_list; |
|---|
| 495 | + ifa1 = rtnl_dereference(*ifap); |
|---|
| 496 | + |
|---|
| 497 | + while (ifa1) { |
|---|
| 476 | 498 | if (!(ifa1->ifa_flags & IFA_F_SECONDARY) && |
|---|
| 477 | 499 | ifa->ifa_scope <= ifa1->ifa_scope) |
|---|
| 478 | 500 | last_primary = &ifa1->ifa_next; |
|---|
| .. | .. |
|---|
| 488 | 510 | } |
|---|
| 489 | 511 | ifa->ifa_flags |= IFA_F_SECONDARY; |
|---|
| 490 | 512 | } |
|---|
| 513 | + |
|---|
| 514 | + ifap = &ifa1->ifa_next; |
|---|
| 515 | + ifa1 = rtnl_dereference(*ifap); |
|---|
| 491 | 516 | } |
|---|
| 492 | 517 | |
|---|
| 493 | 518 | /* Allow any devices that wish to register ifaddr validtors to weigh |
|---|
| .. | .. |
|---|
| 513 | 538 | ifap = last_primary; |
|---|
| 514 | 539 | } |
|---|
| 515 | 540 | |
|---|
| 516 | | - ifa->ifa_next = *ifap; |
|---|
| 517 | | - *ifap = ifa; |
|---|
| 541 | + rcu_assign_pointer(ifa->ifa_next, *ifap); |
|---|
| 542 | + rcu_assign_pointer(*ifap, ifa); |
|---|
| 518 | 543 | |
|---|
| 519 | 544 | inet_hash_insert(dev_net(in_dev->dev), ifa); |
|---|
| 520 | 545 | |
|---|
| .. | .. |
|---|
| 579 | 604 | struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, |
|---|
| 580 | 605 | __be32 mask) |
|---|
| 581 | 606 | { |
|---|
| 607 | + struct in_ifaddr *ifa; |
|---|
| 608 | + |
|---|
| 582 | 609 | ASSERT_RTNL(); |
|---|
| 583 | 610 | |
|---|
| 584 | | - for_primary_ifa(in_dev) { |
|---|
| 611 | + in_dev_for_each_ifa_rtnl(ifa, in_dev) { |
|---|
| 585 | 612 | if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa)) |
|---|
| 586 | 613 | return ifa; |
|---|
| 587 | | - } endfor_ifa(in_dev); |
|---|
| 614 | + } |
|---|
| 588 | 615 | return NULL; |
|---|
| 589 | 616 | } |
|---|
| 590 | 617 | |
|---|
| .. | .. |
|---|
| 618 | 645 | struct netlink_ext_ack *extack) |
|---|
| 619 | 646 | { |
|---|
| 620 | 647 | struct net *net = sock_net(skb->sk); |
|---|
| 648 | + struct in_ifaddr __rcu **ifap; |
|---|
| 621 | 649 | struct nlattr *tb[IFA_MAX+1]; |
|---|
| 622 | 650 | struct in_device *in_dev; |
|---|
| 623 | 651 | struct ifaddrmsg *ifm; |
|---|
| 624 | | - struct in_ifaddr *ifa, **ifap; |
|---|
| 652 | + struct in_ifaddr *ifa; |
|---|
| 653 | + |
|---|
| 625 | 654 | int err = -EINVAL; |
|---|
| 626 | 655 | |
|---|
| 627 | 656 | ASSERT_RTNL(); |
|---|
| 628 | 657 | |
|---|
| 629 | | - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy, |
|---|
| 630 | | - extack); |
|---|
| 658 | + err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX, |
|---|
| 659 | + ifa_ipv4_policy, extack); |
|---|
| 631 | 660 | if (err < 0) |
|---|
| 632 | 661 | goto errout; |
|---|
| 633 | 662 | |
|---|
| .. | .. |
|---|
| 638 | 667 | goto errout; |
|---|
| 639 | 668 | } |
|---|
| 640 | 669 | |
|---|
| 641 | | - for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; |
|---|
| 670 | + for (ifap = &in_dev->ifa_list; (ifa = rtnl_dereference(*ifap)) != NULL; |
|---|
| 642 | 671 | ifap = &ifa->ifa_next) { |
|---|
| 643 | 672 | if (tb[IFA_LOCAL] && |
|---|
| 644 | 673 | ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL])) |
|---|
| .. | .. |
|---|
| 726 | 755 | |
|---|
| 727 | 756 | if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME && |
|---|
| 728 | 757 | age >= ifa->ifa_valid_lft) { |
|---|
| 729 | | - struct in_ifaddr **ifap; |
|---|
| 758 | + struct in_ifaddr __rcu **ifap; |
|---|
| 759 | + struct in_ifaddr *tmp; |
|---|
| 730 | 760 | |
|---|
| 731 | | - for (ifap = &ifa->ifa_dev->ifa_list; |
|---|
| 732 | | - *ifap != NULL; ifap = &(*ifap)->ifa_next) { |
|---|
| 733 | | - if (*ifap == ifa) { |
|---|
| 761 | + ifap = &ifa->ifa_dev->ifa_list; |
|---|
| 762 | + tmp = rtnl_dereference(*ifap); |
|---|
| 763 | + while (tmp) { |
|---|
| 764 | + if (tmp == ifa) { |
|---|
| 734 | 765 | inet_del_ifa(ifa->ifa_dev, |
|---|
| 735 | 766 | ifap, 1); |
|---|
| 736 | 767 | break; |
|---|
| 737 | 768 | } |
|---|
| 769 | + ifap = &tmp->ifa_next; |
|---|
| 770 | + tmp = rtnl_dereference(*ifap); |
|---|
| 738 | 771 | } |
|---|
| 739 | 772 | } else if (ifa->ifa_preferred_lft != |
|---|
| 740 | 773 | INFINITY_LIFE_TIME && |
|---|
| .. | .. |
|---|
| 788 | 821 | } |
|---|
| 789 | 822 | |
|---|
| 790 | 823 | static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, |
|---|
| 791 | | - __u32 *pvalid_lft, __u32 *pprefered_lft) |
|---|
| 824 | + __u32 *pvalid_lft, __u32 *pprefered_lft, |
|---|
| 825 | + struct netlink_ext_ack *extack) |
|---|
| 792 | 826 | { |
|---|
| 793 | 827 | struct nlattr *tb[IFA_MAX+1]; |
|---|
| 794 | 828 | struct in_ifaddr *ifa; |
|---|
| .. | .. |
|---|
| 797 | 831 | struct in_device *in_dev; |
|---|
| 798 | 832 | int err; |
|---|
| 799 | 833 | |
|---|
| 800 | | - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy, |
|---|
| 801 | | - NULL); |
|---|
| 834 | + err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFA_MAX, |
|---|
| 835 | + ifa_ipv4_policy, extack); |
|---|
| 802 | 836 | if (err < 0) |
|---|
| 803 | 837 | goto errout; |
|---|
| 804 | 838 | |
|---|
| .. | .. |
|---|
| 877 | 911 | static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa) |
|---|
| 878 | 912 | { |
|---|
| 879 | 913 | struct in_device *in_dev = ifa->ifa_dev; |
|---|
| 880 | | - struct in_ifaddr *ifa1, **ifap; |
|---|
| 914 | + struct in_ifaddr *ifa1; |
|---|
| 881 | 915 | |
|---|
| 882 | 916 | if (!ifa->ifa_local) |
|---|
| 883 | 917 | return NULL; |
|---|
| 884 | 918 | |
|---|
| 885 | | - for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL; |
|---|
| 886 | | - ifap = &ifa1->ifa_next) { |
|---|
| 919 | + in_dev_for_each_ifa_rtnl(ifa1, in_dev) { |
|---|
| 887 | 920 | if (ifa1->ifa_mask == ifa->ifa_mask && |
|---|
| 888 | 921 | inet_ifa_match(ifa1->ifa_address, ifa) && |
|---|
| 889 | 922 | ifa1->ifa_local == ifa->ifa_local) |
|---|
| .. | .. |
|---|
| 903 | 936 | |
|---|
| 904 | 937 | ASSERT_RTNL(); |
|---|
| 905 | 938 | |
|---|
| 906 | | - ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft); |
|---|
| 939 | + ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft, extack); |
|---|
| 907 | 940 | if (IS_ERR(ifa)) |
|---|
| 908 | 941 | return PTR_ERR(ifa); |
|---|
| 909 | 942 | |
|---|
| .. | .. |
|---|
| 955 | 988 | { |
|---|
| 956 | 989 | int rc = -1; /* Something else, probably a multicast. */ |
|---|
| 957 | 990 | |
|---|
| 958 | | - if (ipv4_is_zeronet(addr)) |
|---|
| 991 | + if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr)) |
|---|
| 959 | 992 | rc = 0; |
|---|
| 960 | 993 | else { |
|---|
| 961 | 994 | __u32 haddr = ntohl(addr); |
|---|
| 962 | | - |
|---|
| 963 | 995 | if (IN_CLASSA(haddr)) |
|---|
| 964 | 996 | rc = 8; |
|---|
| 965 | 997 | else if (IN_CLASSB(haddr)) |
|---|
| 966 | 998 | rc = 16; |
|---|
| 967 | 999 | else if (IN_CLASSC(haddr)) |
|---|
| 968 | 1000 | rc = 24; |
|---|
| 1001 | + else if (IN_CLASSE(haddr)) |
|---|
| 1002 | + rc = 32; |
|---|
| 969 | 1003 | } |
|---|
| 970 | 1004 | |
|---|
| 971 | 1005 | return rc; |
|---|
| .. | .. |
|---|
| 976 | 1010 | { |
|---|
| 977 | 1011 | struct sockaddr_in sin_orig; |
|---|
| 978 | 1012 | struct sockaddr_in *sin = (struct sockaddr_in *)&ifr->ifr_addr; |
|---|
| 1013 | + struct in_ifaddr __rcu **ifap = NULL; |
|---|
| 979 | 1014 | struct in_device *in_dev; |
|---|
| 980 | | - struct in_ifaddr **ifap = NULL; |
|---|
| 981 | 1015 | struct in_ifaddr *ifa = NULL; |
|---|
| 982 | 1016 | struct net_device *dev; |
|---|
| 983 | 1017 | char *colon; |
|---|
| .. | .. |
|---|
| 1048 | 1082 | /* note: we only do this for a limited set of ioctls |
|---|
| 1049 | 1083 | and only if the original address family was AF_INET. |
|---|
| 1050 | 1084 | This is checked above. */ |
|---|
| 1051 | | - for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; |
|---|
| 1085 | + |
|---|
| 1086 | + for (ifap = &in_dev->ifa_list; |
|---|
| 1087 | + (ifa = rtnl_dereference(*ifap)) != NULL; |
|---|
| 1052 | 1088 | ifap = &ifa->ifa_next) { |
|---|
| 1053 | 1089 | if (!strcmp(ifr->ifr_name, ifa->ifa_label) && |
|---|
| 1054 | 1090 | sin_orig.sin_addr.s_addr == |
|---|
| .. | .. |
|---|
| 1061 | 1097 | 4.3BSD-style and passed in junk so we fall back to |
|---|
| 1062 | 1098 | comparing just the label */ |
|---|
| 1063 | 1099 | if (!ifa) { |
|---|
| 1064 | | - for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; |
|---|
| 1100 | + for (ifap = &in_dev->ifa_list; |
|---|
| 1101 | + (ifa = rtnl_dereference(*ifap)) != NULL; |
|---|
| 1065 | 1102 | ifap = &ifa->ifa_next) |
|---|
| 1066 | 1103 | if (!strcmp(ifr->ifr_name, ifa->ifa_label)) |
|---|
| 1067 | 1104 | break; |
|---|
| .. | .. |
|---|
| 1103 | 1140 | inet_del_ifa(in_dev, ifap, 1); |
|---|
| 1104 | 1141 | break; |
|---|
| 1105 | 1142 | } |
|---|
| 1106 | | - ret = dev_change_flags(dev, ifr->ifr_flags); |
|---|
| 1143 | + ret = dev_change_flags(dev, ifr->ifr_flags, NULL); |
|---|
| 1107 | 1144 | break; |
|---|
| 1108 | 1145 | |
|---|
| 1109 | 1146 | case SIOCSIFADDR: /* Set interface address (and family) */ |
|---|
| .. | .. |
|---|
| 1207 | 1244 | return ret; |
|---|
| 1208 | 1245 | } |
|---|
| 1209 | 1246 | |
|---|
| 1210 | | -static int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size) |
|---|
| 1247 | +int inet_gifconf(struct net_device *dev, char __user *buf, int len, int size) |
|---|
| 1211 | 1248 | { |
|---|
| 1212 | 1249 | struct in_device *in_dev = __in_dev_get_rtnl(dev); |
|---|
| 1213 | | - struct in_ifaddr *ifa; |
|---|
| 1250 | + const struct in_ifaddr *ifa; |
|---|
| 1214 | 1251 | struct ifreq ifr; |
|---|
| 1215 | 1252 | int done = 0; |
|---|
| 1216 | 1253 | |
|---|
| .. | .. |
|---|
| 1220 | 1257 | if (!in_dev) |
|---|
| 1221 | 1258 | goto out; |
|---|
| 1222 | 1259 | |
|---|
| 1223 | | - for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { |
|---|
| 1260 | + in_dev_for_each_ifa_rtnl(ifa, in_dev) { |
|---|
| 1224 | 1261 | if (!buf) { |
|---|
| 1225 | 1262 | done += size; |
|---|
| 1226 | 1263 | continue; |
|---|
| .. | .. |
|---|
| 1248 | 1285 | static __be32 in_dev_select_addr(const struct in_device *in_dev, |
|---|
| 1249 | 1286 | int scope) |
|---|
| 1250 | 1287 | { |
|---|
| 1251 | | - for_primary_ifa(in_dev) { |
|---|
| 1288 | + const struct in_ifaddr *ifa; |
|---|
| 1289 | + |
|---|
| 1290 | + in_dev_for_each_ifa_rcu(ifa, in_dev) { |
|---|
| 1291 | + if (ifa->ifa_flags & IFA_F_SECONDARY) |
|---|
| 1292 | + continue; |
|---|
| 1252 | 1293 | if (ifa->ifa_scope != RT_SCOPE_LINK && |
|---|
| 1253 | 1294 | ifa->ifa_scope <= scope) |
|---|
| 1254 | 1295 | return ifa->ifa_local; |
|---|
| 1255 | | - } endfor_ifa(in_dev); |
|---|
| 1296 | + } |
|---|
| 1256 | 1297 | |
|---|
| 1257 | 1298 | return 0; |
|---|
| 1258 | 1299 | } |
|---|
| 1259 | 1300 | |
|---|
| 1260 | 1301 | __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) |
|---|
| 1261 | 1302 | { |
|---|
| 1303 | + const struct in_ifaddr *ifa; |
|---|
| 1262 | 1304 | __be32 addr = 0; |
|---|
| 1305 | + unsigned char localnet_scope = RT_SCOPE_HOST; |
|---|
| 1263 | 1306 | struct in_device *in_dev; |
|---|
| 1264 | 1307 | struct net *net = dev_net(dev); |
|---|
| 1265 | 1308 | int master_idx; |
|---|
| .. | .. |
|---|
| 1269 | 1312 | if (!in_dev) |
|---|
| 1270 | 1313 | goto no_in_dev; |
|---|
| 1271 | 1314 | |
|---|
| 1272 | | - for_primary_ifa(in_dev) { |
|---|
| 1273 | | - if (ifa->ifa_scope > scope) |
|---|
| 1315 | + if (unlikely(IN_DEV_ROUTE_LOCALNET(in_dev))) |
|---|
| 1316 | + localnet_scope = RT_SCOPE_LINK; |
|---|
| 1317 | + |
|---|
| 1318 | + in_dev_for_each_ifa_rcu(ifa, in_dev) { |
|---|
| 1319 | + if (ifa->ifa_flags & IFA_F_SECONDARY) |
|---|
| 1320 | + continue; |
|---|
| 1321 | + if (min(ifa->ifa_scope, localnet_scope) > scope) |
|---|
| 1274 | 1322 | continue; |
|---|
| 1275 | 1323 | if (!dst || inet_ifa_match(dst, ifa)) { |
|---|
| 1276 | 1324 | addr = ifa->ifa_local; |
|---|
| .. | .. |
|---|
| 1278 | 1326 | } |
|---|
| 1279 | 1327 | if (!addr) |
|---|
| 1280 | 1328 | addr = ifa->ifa_local; |
|---|
| 1281 | | - } endfor_ifa(in_dev); |
|---|
| 1329 | + } |
|---|
| 1282 | 1330 | |
|---|
| 1283 | 1331 | if (addr) |
|---|
| 1284 | 1332 | goto out_unlock; |
|---|
| .. | .. |
|---|
| 1323 | 1371 | static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst, |
|---|
| 1324 | 1372 | __be32 local, int scope) |
|---|
| 1325 | 1373 | { |
|---|
| 1326 | | - int same = 0; |
|---|
| 1374 | + unsigned char localnet_scope = RT_SCOPE_HOST; |
|---|
| 1375 | + const struct in_ifaddr *ifa; |
|---|
| 1327 | 1376 | __be32 addr = 0; |
|---|
| 1377 | + int same = 0; |
|---|
| 1328 | 1378 | |
|---|
| 1329 | | - for_ifa(in_dev) { |
|---|
| 1379 | + if (unlikely(IN_DEV_ROUTE_LOCALNET(in_dev))) |
|---|
| 1380 | + localnet_scope = RT_SCOPE_LINK; |
|---|
| 1381 | + |
|---|
| 1382 | + in_dev_for_each_ifa_rcu(ifa, in_dev) { |
|---|
| 1383 | + unsigned char min_scope = min(ifa->ifa_scope, localnet_scope); |
|---|
| 1384 | + |
|---|
| 1330 | 1385 | if (!addr && |
|---|
| 1331 | 1386 | (local == ifa->ifa_local || !local) && |
|---|
| 1332 | | - ifa->ifa_scope <= scope) { |
|---|
| 1387 | + min_scope <= scope) { |
|---|
| 1333 | 1388 | addr = ifa->ifa_local; |
|---|
| 1334 | 1389 | if (same) |
|---|
| 1335 | 1390 | break; |
|---|
| .. | .. |
|---|
| 1344 | 1399 | if (inet_ifa_match(addr, ifa)) |
|---|
| 1345 | 1400 | break; |
|---|
| 1346 | 1401 | /* No, then can we use new local src? */ |
|---|
| 1347 | | - if (ifa->ifa_scope <= scope) { |
|---|
| 1402 | + if (min_scope <= scope) { |
|---|
| 1348 | 1403 | addr = ifa->ifa_local; |
|---|
| 1349 | 1404 | break; |
|---|
| 1350 | 1405 | } |
|---|
| .. | .. |
|---|
| 1352 | 1407 | same = 0; |
|---|
| 1353 | 1408 | } |
|---|
| 1354 | 1409 | } |
|---|
| 1355 | | - } endfor_ifa(in_dev); |
|---|
| 1410 | + } |
|---|
| 1356 | 1411 | |
|---|
| 1357 | 1412 | return same ? addr : 0; |
|---|
| 1358 | 1413 | } |
|---|
| .. | .. |
|---|
| 1426 | 1481 | struct in_ifaddr *ifa; |
|---|
| 1427 | 1482 | int named = 0; |
|---|
| 1428 | 1483 | |
|---|
| 1429 | | - for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { |
|---|
| 1484 | + in_dev_for_each_ifa_rtnl(ifa, in_dev) { |
|---|
| 1430 | 1485 | char old[IFNAMSIZ], *dot; |
|---|
| 1431 | 1486 | |
|---|
| 1432 | 1487 | memcpy(old, ifa->ifa_label, IFNAMSIZ); |
|---|
| .. | .. |
|---|
| 1451 | 1506 | struct in_device *in_dev) |
|---|
| 1452 | 1507 | |
|---|
| 1453 | 1508 | { |
|---|
| 1454 | | - struct in_ifaddr *ifa; |
|---|
| 1509 | + const struct in_ifaddr *ifa; |
|---|
| 1455 | 1510 | |
|---|
| 1456 | | - for (ifa = in_dev->ifa_list; ifa; |
|---|
| 1457 | | - ifa = ifa->ifa_next) { |
|---|
| 1511 | + in_dev_for_each_ifa_rtnl(ifa, in_dev) { |
|---|
| 1458 | 1512 | arp_send(ARPOP_REQUEST, ETH_P_ARP, |
|---|
| 1459 | 1513 | ifa->ifa_local, dev, |
|---|
| 1460 | 1514 | ifa->ifa_local, NULL, |
|---|
| .. | .. |
|---|
| 1518 | 1572 | } |
|---|
| 1519 | 1573 | } |
|---|
| 1520 | 1574 | ip_mc_up(in_dev); |
|---|
| 1521 | | - /* fall through */ |
|---|
| 1575 | + fallthrough; |
|---|
| 1522 | 1576 | case NETDEV_CHANGEADDR: |
|---|
| 1523 | 1577 | if (!IN_DEV_ARP_NOTIFY(in_dev)) |
|---|
| 1524 | 1578 | break; |
|---|
| 1525 | | - /* fall through */ |
|---|
| 1579 | + fallthrough; |
|---|
| 1526 | 1580 | case NETDEV_NOTIFY_PEERS: |
|---|
| 1527 | 1581 | /* Send gratuitous ARP to notify of link change */ |
|---|
| 1528 | 1582 | inetdev_send_gratuitous_arp(dev, in_dev); |
|---|
| .. | .. |
|---|
| 1540 | 1594 | if (inetdev_valid_mtu(dev->mtu)) |
|---|
| 1541 | 1595 | break; |
|---|
| 1542 | 1596 | /* disable IP when MTU is not enough */ |
|---|
| 1543 | | - /* fall through */ |
|---|
| 1597 | + fallthrough; |
|---|
| 1544 | 1598 | case NETDEV_UNREGISTER: |
|---|
| 1545 | 1599 | inetdev_destroy(in_dev); |
|---|
| 1546 | 1600 | break; |
|---|
| .. | .. |
|---|
| 1593 | 1647 | } |
|---|
| 1594 | 1648 | |
|---|
| 1595 | 1649 | static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, |
|---|
| 1596 | | - u32 portid, u32 seq, int event, unsigned int flags) |
|---|
| 1650 | + struct inet_fill_args *args) |
|---|
| 1597 | 1651 | { |
|---|
| 1598 | 1652 | struct ifaddrmsg *ifm; |
|---|
| 1599 | 1653 | struct nlmsghdr *nlh; |
|---|
| 1600 | 1654 | u32 preferred, valid; |
|---|
| 1601 | 1655 | |
|---|
| 1602 | | - nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags); |
|---|
| 1656 | + nlh = nlmsg_put(skb, args->portid, args->seq, args->event, sizeof(*ifm), |
|---|
| 1657 | + args->flags); |
|---|
| 1603 | 1658 | if (!nlh) |
|---|
| 1604 | 1659 | return -EMSGSIZE; |
|---|
| 1605 | 1660 | |
|---|
| .. | .. |
|---|
| 1609 | 1664 | ifm->ifa_flags = ifa->ifa_flags; |
|---|
| 1610 | 1665 | ifm->ifa_scope = ifa->ifa_scope; |
|---|
| 1611 | 1666 | ifm->ifa_index = ifa->ifa_dev->dev->ifindex; |
|---|
| 1667 | + |
|---|
| 1668 | + if (args->netnsid >= 0 && |
|---|
| 1669 | + nla_put_s32(skb, IFA_TARGET_NETNSID, args->netnsid)) |
|---|
| 1670 | + goto nla_put_failure; |
|---|
| 1612 | 1671 | |
|---|
| 1613 | 1672 | if (!(ifm->ifa_flags & IFA_F_PERMANENT)) { |
|---|
| 1614 | 1673 | preferred = ifa->ifa_preferred_lft; |
|---|
| .. | .. |
|---|
| 1654 | 1713 | return -EMSGSIZE; |
|---|
| 1655 | 1714 | } |
|---|
| 1656 | 1715 | |
|---|
| 1716 | +static int inet_valid_dump_ifaddr_req(const struct nlmsghdr *nlh, |
|---|
| 1717 | + struct inet_fill_args *fillargs, |
|---|
| 1718 | + struct net **tgt_net, struct sock *sk, |
|---|
| 1719 | + struct netlink_callback *cb) |
|---|
| 1720 | +{ |
|---|
| 1721 | + struct netlink_ext_ack *extack = cb->extack; |
|---|
| 1722 | + struct nlattr *tb[IFA_MAX+1]; |
|---|
| 1723 | + struct ifaddrmsg *ifm; |
|---|
| 1724 | + int err, i; |
|---|
| 1725 | + |
|---|
| 1726 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ifm))) { |
|---|
| 1727 | + NL_SET_ERR_MSG(extack, "ipv4: Invalid header for address dump request"); |
|---|
| 1728 | + return -EINVAL; |
|---|
| 1729 | + } |
|---|
| 1730 | + |
|---|
| 1731 | + ifm = nlmsg_data(nlh); |
|---|
| 1732 | + if (ifm->ifa_prefixlen || ifm->ifa_flags || ifm->ifa_scope) { |
|---|
| 1733 | + NL_SET_ERR_MSG(extack, "ipv4: Invalid values in header for address dump request"); |
|---|
| 1734 | + return -EINVAL; |
|---|
| 1735 | + } |
|---|
| 1736 | + |
|---|
| 1737 | + fillargs->ifindex = ifm->ifa_index; |
|---|
| 1738 | + if (fillargs->ifindex) { |
|---|
| 1739 | + cb->answer_flags |= NLM_F_DUMP_FILTERED; |
|---|
| 1740 | + fillargs->flags |= NLM_F_DUMP_FILTERED; |
|---|
| 1741 | + } |
|---|
| 1742 | + |
|---|
| 1743 | + err = nlmsg_parse_deprecated_strict(nlh, sizeof(*ifm), tb, IFA_MAX, |
|---|
| 1744 | + ifa_ipv4_policy, extack); |
|---|
| 1745 | + if (err < 0) |
|---|
| 1746 | + return err; |
|---|
| 1747 | + |
|---|
| 1748 | + for (i = 0; i <= IFA_MAX; ++i) { |
|---|
| 1749 | + if (!tb[i]) |
|---|
| 1750 | + continue; |
|---|
| 1751 | + |
|---|
| 1752 | + if (i == IFA_TARGET_NETNSID) { |
|---|
| 1753 | + struct net *net; |
|---|
| 1754 | + |
|---|
| 1755 | + fillargs->netnsid = nla_get_s32(tb[i]); |
|---|
| 1756 | + |
|---|
| 1757 | + net = rtnl_get_net_ns_capable(sk, fillargs->netnsid); |
|---|
| 1758 | + if (IS_ERR(net)) { |
|---|
| 1759 | + fillargs->netnsid = -1; |
|---|
| 1760 | + NL_SET_ERR_MSG(extack, "ipv4: Invalid target network namespace id"); |
|---|
| 1761 | + return PTR_ERR(net); |
|---|
| 1762 | + } |
|---|
| 1763 | + *tgt_net = net; |
|---|
| 1764 | + } else { |
|---|
| 1765 | + NL_SET_ERR_MSG(extack, "ipv4: Unsupported attribute in dump request"); |
|---|
| 1766 | + return -EINVAL; |
|---|
| 1767 | + } |
|---|
| 1768 | + } |
|---|
| 1769 | + |
|---|
| 1770 | + return 0; |
|---|
| 1771 | +} |
|---|
| 1772 | + |
|---|
| 1773 | +static int in_dev_dump_addr(struct in_device *in_dev, struct sk_buff *skb, |
|---|
| 1774 | + struct netlink_callback *cb, int s_ip_idx, |
|---|
| 1775 | + struct inet_fill_args *fillargs) |
|---|
| 1776 | +{ |
|---|
| 1777 | + struct in_ifaddr *ifa; |
|---|
| 1778 | + int ip_idx = 0; |
|---|
| 1779 | + int err; |
|---|
| 1780 | + |
|---|
| 1781 | + in_dev_for_each_ifa_rtnl(ifa, in_dev) { |
|---|
| 1782 | + if (ip_idx < s_ip_idx) { |
|---|
| 1783 | + ip_idx++; |
|---|
| 1784 | + continue; |
|---|
| 1785 | + } |
|---|
| 1786 | + err = inet_fill_ifaddr(skb, ifa, fillargs); |
|---|
| 1787 | + if (err < 0) |
|---|
| 1788 | + goto done; |
|---|
| 1789 | + |
|---|
| 1790 | + nl_dump_check_consistent(cb, nlmsg_hdr(skb)); |
|---|
| 1791 | + ip_idx++; |
|---|
| 1792 | + } |
|---|
| 1793 | + err = 0; |
|---|
| 1794 | + |
|---|
| 1795 | +done: |
|---|
| 1796 | + cb->args[2] = ip_idx; |
|---|
| 1797 | + |
|---|
| 1798 | + return err; |
|---|
| 1799 | +} |
|---|
| 1800 | + |
|---|
| 1657 | 1801 | static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) |
|---|
| 1658 | 1802 | { |
|---|
| 1803 | + const struct nlmsghdr *nlh = cb->nlh; |
|---|
| 1804 | + struct inet_fill_args fillargs = { |
|---|
| 1805 | + .portid = NETLINK_CB(cb->skb).portid, |
|---|
| 1806 | + .seq = nlh->nlmsg_seq, |
|---|
| 1807 | + .event = RTM_NEWADDR, |
|---|
| 1808 | + .flags = NLM_F_MULTI, |
|---|
| 1809 | + .netnsid = -1, |
|---|
| 1810 | + }; |
|---|
| 1659 | 1811 | struct net *net = sock_net(skb->sk); |
|---|
| 1812 | + struct net *tgt_net = net; |
|---|
| 1660 | 1813 | int h, s_h; |
|---|
| 1661 | 1814 | int idx, s_idx; |
|---|
| 1662 | | - int ip_idx, s_ip_idx; |
|---|
| 1815 | + int s_ip_idx; |
|---|
| 1663 | 1816 | struct net_device *dev; |
|---|
| 1664 | 1817 | struct in_device *in_dev; |
|---|
| 1665 | | - struct in_ifaddr *ifa; |
|---|
| 1666 | 1818 | struct hlist_head *head; |
|---|
| 1819 | + int err = 0; |
|---|
| 1667 | 1820 | |
|---|
| 1668 | 1821 | s_h = cb->args[0]; |
|---|
| 1669 | 1822 | s_idx = idx = cb->args[1]; |
|---|
| 1670 | | - s_ip_idx = ip_idx = cb->args[2]; |
|---|
| 1823 | + s_ip_idx = cb->args[2]; |
|---|
| 1824 | + |
|---|
| 1825 | + if (cb->strict_check) { |
|---|
| 1826 | + err = inet_valid_dump_ifaddr_req(nlh, &fillargs, &tgt_net, |
|---|
| 1827 | + skb->sk, cb); |
|---|
| 1828 | + if (err < 0) |
|---|
| 1829 | + goto put_tgt_net; |
|---|
| 1830 | + |
|---|
| 1831 | + err = 0; |
|---|
| 1832 | + if (fillargs.ifindex) { |
|---|
| 1833 | + dev = __dev_get_by_index(tgt_net, fillargs.ifindex); |
|---|
| 1834 | + if (!dev) { |
|---|
| 1835 | + err = -ENODEV; |
|---|
| 1836 | + goto put_tgt_net; |
|---|
| 1837 | + } |
|---|
| 1838 | + |
|---|
| 1839 | + in_dev = __in_dev_get_rtnl(dev); |
|---|
| 1840 | + if (in_dev) { |
|---|
| 1841 | + err = in_dev_dump_addr(in_dev, skb, cb, s_ip_idx, |
|---|
| 1842 | + &fillargs); |
|---|
| 1843 | + } |
|---|
| 1844 | + goto put_tgt_net; |
|---|
| 1845 | + } |
|---|
| 1846 | + } |
|---|
| 1671 | 1847 | |
|---|
| 1672 | 1848 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
|---|
| 1673 | 1849 | idx = 0; |
|---|
| 1674 | | - head = &net->dev_index_head[h]; |
|---|
| 1850 | + head = &tgt_net->dev_index_head[h]; |
|---|
| 1675 | 1851 | rcu_read_lock(); |
|---|
| 1676 | | - cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^ |
|---|
| 1677 | | - net->dev_base_seq; |
|---|
| 1852 | + cb->seq = atomic_read(&tgt_net->ipv4.dev_addr_genid) ^ |
|---|
| 1853 | + tgt_net->dev_base_seq; |
|---|
| 1678 | 1854 | hlist_for_each_entry_rcu(dev, head, index_hlist) { |
|---|
| 1679 | 1855 | if (idx < s_idx) |
|---|
| 1680 | 1856 | goto cont; |
|---|
| .. | .. |
|---|
| 1684 | 1860 | if (!in_dev) |
|---|
| 1685 | 1861 | goto cont; |
|---|
| 1686 | 1862 | |
|---|
| 1687 | | - for (ifa = in_dev->ifa_list, ip_idx = 0; ifa; |
|---|
| 1688 | | - ifa = ifa->ifa_next, ip_idx++) { |
|---|
| 1689 | | - if (ip_idx < s_ip_idx) |
|---|
| 1690 | | - continue; |
|---|
| 1691 | | - if (inet_fill_ifaddr(skb, ifa, |
|---|
| 1692 | | - NETLINK_CB(cb->skb).portid, |
|---|
| 1693 | | - cb->nlh->nlmsg_seq, |
|---|
| 1694 | | - RTM_NEWADDR, NLM_F_MULTI) < 0) { |
|---|
| 1695 | | - rcu_read_unlock(); |
|---|
| 1696 | | - goto done; |
|---|
| 1697 | | - } |
|---|
| 1698 | | - nl_dump_check_consistent(cb, nlmsg_hdr(skb)); |
|---|
| 1863 | + err = in_dev_dump_addr(in_dev, skb, cb, s_ip_idx, |
|---|
| 1864 | + &fillargs); |
|---|
| 1865 | + if (err < 0) { |
|---|
| 1866 | + rcu_read_unlock(); |
|---|
| 1867 | + goto done; |
|---|
| 1699 | 1868 | } |
|---|
| 1700 | 1869 | cont: |
|---|
| 1701 | 1870 | idx++; |
|---|
| .. | .. |
|---|
| 1706 | 1875 | done: |
|---|
| 1707 | 1876 | cb->args[0] = h; |
|---|
| 1708 | 1877 | cb->args[1] = idx; |
|---|
| 1709 | | - cb->args[2] = ip_idx; |
|---|
| 1878 | +put_tgt_net: |
|---|
| 1879 | + if (fillargs.netnsid >= 0) |
|---|
| 1880 | + put_net(tgt_net); |
|---|
| 1710 | 1881 | |
|---|
| 1711 | | - return skb->len; |
|---|
| 1882 | + return skb->len ? : err; |
|---|
| 1712 | 1883 | } |
|---|
| 1713 | 1884 | |
|---|
| 1714 | 1885 | static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh, |
|---|
| 1715 | 1886 | u32 portid) |
|---|
| 1716 | 1887 | { |
|---|
| 1888 | + struct inet_fill_args fillargs = { |
|---|
| 1889 | + .portid = portid, |
|---|
| 1890 | + .seq = nlh ? nlh->nlmsg_seq : 0, |
|---|
| 1891 | + .event = event, |
|---|
| 1892 | + .flags = 0, |
|---|
| 1893 | + .netnsid = -1, |
|---|
| 1894 | + }; |
|---|
| 1717 | 1895 | struct sk_buff *skb; |
|---|
| 1718 | | - u32 seq = nlh ? nlh->nlmsg_seq : 0; |
|---|
| 1719 | 1896 | int err = -ENOBUFS; |
|---|
| 1720 | 1897 | struct net *net; |
|---|
| 1721 | 1898 | |
|---|
| .. | .. |
|---|
| 1724 | 1901 | if (!skb) |
|---|
| 1725 | 1902 | goto errout; |
|---|
| 1726 | 1903 | |
|---|
| 1727 | | - err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0); |
|---|
| 1904 | + err = inet_fill_ifaddr(skb, ifa, &fillargs); |
|---|
| 1728 | 1905 | if (err < 0) { |
|---|
| 1729 | 1906 | /* -EMSGSIZE implies BUG in inet_nlmsg_size() */ |
|---|
| 1730 | 1907 | WARN_ON(err == -EMSGSIZE); |
|---|
| .. | .. |
|---|
| 1782 | 1959 | if (dev && !__in_dev_get_rcu(dev)) |
|---|
| 1783 | 1960 | return -EAFNOSUPPORT; |
|---|
| 1784 | 1961 | |
|---|
| 1785 | | - err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy, NULL); |
|---|
| 1962 | + err = nla_parse_nested_deprecated(tb, IFLA_INET_MAX, nla, |
|---|
| 1963 | + inet_af_policy, NULL); |
|---|
| 1786 | 1964 | if (err < 0) |
|---|
| 1787 | 1965 | return err; |
|---|
| 1788 | 1966 | |
|---|
| .. | .. |
|---|
| 1810 | 1988 | if (!in_dev) |
|---|
| 1811 | 1989 | return -EAFNOSUPPORT; |
|---|
| 1812 | 1990 | |
|---|
| 1813 | | - if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL, NULL) < 0) |
|---|
| 1814 | | - BUG(); |
|---|
| 1991 | + if (nla_parse_nested_deprecated(tb, IFLA_INET_MAX, nla, NULL, NULL) < 0) |
|---|
| 1992 | + return -EINVAL; |
|---|
| 1815 | 1993 | |
|---|
| 1816 | 1994 | if (tb[IFLA_INET_CONF]) { |
|---|
| 1817 | 1995 | nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) |
|---|
| .. | .. |
|---|
| 1939 | 2117 | [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) }, |
|---|
| 1940 | 2118 | }; |
|---|
| 1941 | 2119 | |
|---|
| 2120 | +static int inet_netconf_valid_get_req(struct sk_buff *skb, |
|---|
| 2121 | + const struct nlmsghdr *nlh, |
|---|
| 2122 | + struct nlattr **tb, |
|---|
| 2123 | + struct netlink_ext_ack *extack) |
|---|
| 2124 | +{ |
|---|
| 2125 | + int i, err; |
|---|
| 2126 | + |
|---|
| 2127 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(struct netconfmsg))) { |
|---|
| 2128 | + NL_SET_ERR_MSG(extack, "ipv4: Invalid header for netconf get request"); |
|---|
| 2129 | + return -EINVAL; |
|---|
| 2130 | + } |
|---|
| 2131 | + |
|---|
| 2132 | + if (!netlink_strict_get_check(skb)) |
|---|
| 2133 | + return nlmsg_parse_deprecated(nlh, sizeof(struct netconfmsg), |
|---|
| 2134 | + tb, NETCONFA_MAX, |
|---|
| 2135 | + devconf_ipv4_policy, extack); |
|---|
| 2136 | + |
|---|
| 2137 | + err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct netconfmsg), |
|---|
| 2138 | + tb, NETCONFA_MAX, |
|---|
| 2139 | + devconf_ipv4_policy, extack); |
|---|
| 2140 | + if (err) |
|---|
| 2141 | + return err; |
|---|
| 2142 | + |
|---|
| 2143 | + for (i = 0; i <= NETCONFA_MAX; i++) { |
|---|
| 2144 | + if (!tb[i]) |
|---|
| 2145 | + continue; |
|---|
| 2146 | + |
|---|
| 2147 | + switch (i) { |
|---|
| 2148 | + case NETCONFA_IFINDEX: |
|---|
| 2149 | + break; |
|---|
| 2150 | + default: |
|---|
| 2151 | + NL_SET_ERR_MSG(extack, "ipv4: Unsupported attribute in netconf get request"); |
|---|
| 2152 | + return -EINVAL; |
|---|
| 2153 | + } |
|---|
| 2154 | + } |
|---|
| 2155 | + |
|---|
| 2156 | + return 0; |
|---|
| 2157 | +} |
|---|
| 2158 | + |
|---|
| 1942 | 2159 | static int inet_netconf_get_devconf(struct sk_buff *in_skb, |
|---|
| 1943 | 2160 | struct nlmsghdr *nlh, |
|---|
| 1944 | 2161 | struct netlink_ext_ack *extack) |
|---|
| 1945 | 2162 | { |
|---|
| 1946 | 2163 | struct net *net = sock_net(in_skb->sk); |
|---|
| 1947 | 2164 | struct nlattr *tb[NETCONFA_MAX+1]; |
|---|
| 1948 | | - struct netconfmsg *ncm; |
|---|
| 1949 | 2165 | struct sk_buff *skb; |
|---|
| 1950 | 2166 | struct ipv4_devconf *devconf; |
|---|
| 1951 | 2167 | struct in_device *in_dev; |
|---|
| .. | .. |
|---|
| 1953 | 2169 | int ifindex; |
|---|
| 1954 | 2170 | int err; |
|---|
| 1955 | 2171 | |
|---|
| 1956 | | - err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX, |
|---|
| 1957 | | - devconf_ipv4_policy, extack); |
|---|
| 1958 | | - if (err < 0) |
|---|
| 2172 | + err = inet_netconf_valid_get_req(in_skb, nlh, tb, extack); |
|---|
| 2173 | + if (err) |
|---|
| 1959 | 2174 | goto errout; |
|---|
| 1960 | 2175 | |
|---|
| 1961 | 2176 | err = -EINVAL; |
|---|
| .. | .. |
|---|
| 2004 | 2219 | static int inet_netconf_dump_devconf(struct sk_buff *skb, |
|---|
| 2005 | 2220 | struct netlink_callback *cb) |
|---|
| 2006 | 2221 | { |
|---|
| 2222 | + const struct nlmsghdr *nlh = cb->nlh; |
|---|
| 2007 | 2223 | struct net *net = sock_net(skb->sk); |
|---|
| 2008 | 2224 | int h, s_h; |
|---|
| 2009 | 2225 | int idx, s_idx; |
|---|
| 2010 | 2226 | struct net_device *dev; |
|---|
| 2011 | 2227 | struct in_device *in_dev; |
|---|
| 2012 | 2228 | struct hlist_head *head; |
|---|
| 2229 | + |
|---|
| 2230 | + if (cb->strict_check) { |
|---|
| 2231 | + struct netlink_ext_ack *extack = cb->extack; |
|---|
| 2232 | + struct netconfmsg *ncm; |
|---|
| 2233 | + |
|---|
| 2234 | + if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ncm))) { |
|---|
| 2235 | + NL_SET_ERR_MSG(extack, "ipv4: Invalid header for netconf dump request"); |
|---|
| 2236 | + return -EINVAL; |
|---|
| 2237 | + } |
|---|
| 2238 | + |
|---|
| 2239 | + if (nlmsg_attrlen(nlh, sizeof(*ncm))) { |
|---|
| 2240 | + NL_SET_ERR_MSG(extack, "ipv4: Invalid data after header in netconf dump request"); |
|---|
| 2241 | + return -EINVAL; |
|---|
| 2242 | + } |
|---|
| 2243 | + } |
|---|
| 2013 | 2244 | |
|---|
| 2014 | 2245 | s_h = cb->args[0]; |
|---|
| 2015 | 2246 | s_idx = idx = cb->args[1]; |
|---|
| .. | .. |
|---|
| 2030 | 2261 | if (inet_netconf_fill_devconf(skb, dev->ifindex, |
|---|
| 2031 | 2262 | &in_dev->cnf, |
|---|
| 2032 | 2263 | NETLINK_CB(cb->skb).portid, |
|---|
| 2033 | | - cb->nlh->nlmsg_seq, |
|---|
| 2264 | + nlh->nlmsg_seq, |
|---|
| 2034 | 2265 | RTM_NEWNETCONF, |
|---|
| 2035 | 2266 | NLM_F_MULTI, |
|---|
| 2036 | 2267 | NETCONFA_ALL) < 0) { |
|---|
| .. | .. |
|---|
| 2047 | 2278 | if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL, |
|---|
| 2048 | 2279 | net->ipv4.devconf_all, |
|---|
| 2049 | 2280 | NETLINK_CB(cb->skb).portid, |
|---|
| 2050 | | - cb->nlh->nlmsg_seq, |
|---|
| 2281 | + nlh->nlmsg_seq, |
|---|
| 2051 | 2282 | RTM_NEWNETCONF, NLM_F_MULTI, |
|---|
| 2052 | 2283 | NETCONFA_ALL) < 0) |
|---|
| 2053 | 2284 | goto done; |
|---|
| .. | .. |
|---|
| 2058 | 2289 | if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT, |
|---|
| 2059 | 2290 | net->ipv4.devconf_dflt, |
|---|
| 2060 | 2291 | NETLINK_CB(cb->skb).portid, |
|---|
| 2061 | | - cb->nlh->nlmsg_seq, |
|---|
| 2292 | + nlh->nlmsg_seq, |
|---|
| 2062 | 2293 | RTM_NEWNETCONF, NLM_F_MULTI, |
|---|
| 2063 | 2294 | NETCONFA_ALL) < 0) |
|---|
| 2064 | 2295 | goto done; |
|---|
| .. | .. |
|---|
| 2136 | 2367 | } |
|---|
| 2137 | 2368 | |
|---|
| 2138 | 2369 | static int devinet_conf_proc(struct ctl_table *ctl, int write, |
|---|
| 2139 | | - void __user *buffer, |
|---|
| 2140 | | - size_t *lenp, loff_t *ppos) |
|---|
| 2370 | + void *buffer, size_t *lenp, loff_t *ppos) |
|---|
| 2141 | 2371 | { |
|---|
| 2142 | 2372 | int old_value = *(int *)ctl->data; |
|---|
| 2143 | 2373 | int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); |
|---|
| .. | .. |
|---|
| 2189 | 2419 | } |
|---|
| 2190 | 2420 | |
|---|
| 2191 | 2421 | static int devinet_sysctl_forward(struct ctl_table *ctl, int write, |
|---|
| 2192 | | - void __user *buffer, |
|---|
| 2193 | | - size_t *lenp, loff_t *ppos) |
|---|
| 2422 | + void *buffer, size_t *lenp, loff_t *ppos) |
|---|
| 2194 | 2423 | { |
|---|
| 2195 | 2424 | int *valp = ctl->data; |
|---|
| 2196 | 2425 | int val = *valp; |
|---|
| .. | .. |
|---|
| 2233 | 2462 | } |
|---|
| 2234 | 2463 | |
|---|
| 2235 | 2464 | static int ipv4_doint_and_flush(struct ctl_table *ctl, int write, |
|---|
| 2236 | | - void __user *buffer, |
|---|
| 2237 | | - size_t *lenp, loff_t *ppos) |
|---|
| 2465 | + void *buffer, size_t *lenp, loff_t *ppos) |
|---|
| 2238 | 2466 | { |
|---|
| 2239 | 2467 | int *valp = ctl->data; |
|---|
| 2240 | 2468 | int val = *valp; |
|---|
| .. | .. |
|---|
| 2416 | 2644 | int err; |
|---|
| 2417 | 2645 | struct ipv4_devconf *all, *dflt; |
|---|
| 2418 | 2646 | #ifdef CONFIG_SYSCTL |
|---|
| 2419 | | - struct ctl_table *tbl = ctl_forward_entry; |
|---|
| 2647 | + struct ctl_table *tbl; |
|---|
| 2420 | 2648 | struct ctl_table_header *forw_hdr; |
|---|
| 2421 | 2649 | #endif |
|---|
| 2422 | 2650 | |
|---|
| 2423 | 2651 | err = -ENOMEM; |
|---|
| 2424 | | - all = &ipv4_devconf; |
|---|
| 2425 | | - dflt = &ipv4_devconf_dflt; |
|---|
| 2652 | + all = kmemdup(&ipv4_devconf, sizeof(ipv4_devconf), GFP_KERNEL); |
|---|
| 2653 | + if (!all) |
|---|
| 2654 | + goto err_alloc_all; |
|---|
| 2426 | 2655 | |
|---|
| 2427 | | - if (!net_eq(net, &init_net)) { |
|---|
| 2428 | | - all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL); |
|---|
| 2429 | | - if (!all) |
|---|
| 2430 | | - goto err_alloc_all; |
|---|
| 2431 | | - |
|---|
| 2432 | | - dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL); |
|---|
| 2433 | | - if (!dflt) |
|---|
| 2434 | | - goto err_alloc_dflt; |
|---|
| 2656 | + dflt = kmemdup(&ipv4_devconf_dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL); |
|---|
| 2657 | + if (!dflt) |
|---|
| 2658 | + goto err_alloc_dflt; |
|---|
| 2435 | 2659 | |
|---|
| 2436 | 2660 | #ifdef CONFIG_SYSCTL |
|---|
| 2437 | | - tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL); |
|---|
| 2438 | | - if (!tbl) |
|---|
| 2439 | | - goto err_alloc_ctl; |
|---|
| 2661 | + tbl = kmemdup(ctl_forward_entry, sizeof(ctl_forward_entry), GFP_KERNEL); |
|---|
| 2662 | + if (!tbl) |
|---|
| 2663 | + goto err_alloc_ctl; |
|---|
| 2440 | 2664 | |
|---|
| 2441 | | - tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1]; |
|---|
| 2442 | | - tbl[0].extra1 = all; |
|---|
| 2443 | | - tbl[0].extra2 = net; |
|---|
| 2665 | + tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1]; |
|---|
| 2666 | + tbl[0].extra1 = all; |
|---|
| 2667 | + tbl[0].extra2 = net; |
|---|
| 2444 | 2668 | #endif |
|---|
| 2669 | + |
|---|
| 2670 | + if (!net_eq(net, &init_net)) { |
|---|
| 2671 | + switch (net_inherit_devconf()) { |
|---|
| 2672 | + case 3: |
|---|
| 2673 | + /* copy from the current netns */ |
|---|
| 2674 | + memcpy(all, current->nsproxy->net_ns->ipv4.devconf_all, |
|---|
| 2675 | + sizeof(ipv4_devconf)); |
|---|
| 2676 | + memcpy(dflt, |
|---|
| 2677 | + current->nsproxy->net_ns->ipv4.devconf_dflt, |
|---|
| 2678 | + sizeof(ipv4_devconf_dflt)); |
|---|
| 2679 | + break; |
|---|
| 2680 | + case 0: |
|---|
| 2681 | + case 1: |
|---|
| 2682 | + /* copy from init_net */ |
|---|
| 2683 | + memcpy(all, init_net.ipv4.devconf_all, |
|---|
| 2684 | + sizeof(ipv4_devconf)); |
|---|
| 2685 | + memcpy(dflt, init_net.ipv4.devconf_dflt, |
|---|
| 2686 | + sizeof(ipv4_devconf_dflt)); |
|---|
| 2687 | + break; |
|---|
| 2688 | + case 2: |
|---|
| 2689 | + /* use compiled values */ |
|---|
| 2690 | + break; |
|---|
| 2691 | + } |
|---|
| 2445 | 2692 | } |
|---|
| 2446 | 2693 | |
|---|
| 2447 | 2694 | #ifdef CONFIG_SYSCTL |
|---|
| .. | .. |
|---|
| 2471 | 2718 | err_reg_dflt: |
|---|
| 2472 | 2719 | __devinet_sysctl_unregister(net, all, NETCONFA_IFINDEX_ALL); |
|---|
| 2473 | 2720 | err_reg_all: |
|---|
| 2474 | | - if (tbl != ctl_forward_entry) |
|---|
| 2475 | | - kfree(tbl); |
|---|
| 2721 | + kfree(tbl); |
|---|
| 2476 | 2722 | err_alloc_ctl: |
|---|
| 2477 | 2723 | #endif |
|---|
| 2478 | | - if (dflt != &ipv4_devconf_dflt) |
|---|
| 2479 | | - kfree(dflt); |
|---|
| 2724 | + kfree(dflt); |
|---|
| 2480 | 2725 | err_alloc_dflt: |
|---|
| 2481 | | - if (all != &ipv4_devconf) |
|---|
| 2482 | | - kfree(all); |
|---|
| 2726 | + kfree(all); |
|---|
| 2483 | 2727 | err_alloc_all: |
|---|
| 2484 | 2728 | return err; |
|---|
| 2485 | 2729 | } |
|---|
| .. | .. |
|---|
| 2522 | 2766 | INIT_HLIST_HEAD(&inet_addr_lst[i]); |
|---|
| 2523 | 2767 | |
|---|
| 2524 | 2768 | register_pernet_subsys(&devinet_ops); |
|---|
| 2525 | | - |
|---|
| 2526 | | - register_gifconf(PF_INET, inet_gifconf); |
|---|
| 2527 | 2769 | register_netdevice_notifier(&ip_netdev_notifier); |
|---|
| 2528 | 2770 | |
|---|
| 2529 | 2771 | queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0); |
|---|