.. | .. |
---|
| 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); |
---|