Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'rtnetlink-improve-alt_ifname-config-and-fix-dangerous-group-usage'

Florent Fourcot says:

====================
rtnetlink: improve ALT_IFNAME config and fix dangerous GROUP usage

First commit forbids dangerous calls when both IFNAME and GROUP are
given, since it can introduce unexpected behaviour when IFNAME does not
match any interface.

Second patch achieves primary goal of this patchset to fix/improve
IFLA_ALT_IFNAME attribute, since previous code was never working for
newlink/setlink. ip-link command is probably getting interface index
before, and was not using this feature.

Last two patches are improving error code on corner cases.

Changes in v2:
* Remove ifname argument in rtnl_dev_get/do_setlink
functions (simplify code)
* Use a boolean to avoid condition duplication in __rtnl_newlink

Changes in v3:
* Simplify rtnl_dev_get signature

Changes in v4:
* Rename link_lookup to link_specified

Changes in v5:
* Re-order patches
====================

Link: https://lore.kernel.org/r/20220415165330.10497-1-florent.fourcot@wifirst.fr
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

+43 -44
+43 -44
net/core/rtnetlink.c
··· 2644 2644 static int do_setlink(const struct sk_buff *skb, 2645 2645 struct net_device *dev, struct ifinfomsg *ifm, 2646 2646 struct netlink_ext_ack *extack, 2647 - struct nlattr **tb, char *ifname, int status) 2647 + struct nlattr **tb, int status) 2648 2648 { 2649 2649 const struct net_device_ops *ops = dev->netdev_ops; 2650 + char ifname[IFNAMSIZ]; 2650 2651 int err; 2651 2652 2652 2653 err = validate_linkmsg(dev, tb, extack); 2653 2654 if (err < 0) 2654 2655 return err; 2655 2656 2657 + if (tb[IFLA_IFNAME]) 2658 + nla_strscpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); 2659 + else 2660 + ifname[0] = '\0'; 2661 + 2656 2662 if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD] || tb[IFLA_TARGET_NETNSID]) { 2657 - const char *pat = ifname && ifname[0] ? ifname : NULL; 2663 + const char *pat = ifname[0] ? ifname : NULL; 2658 2664 struct net *net; 2659 2665 int new_ifindex; 2660 2666 ··· 3016 3010 } 3017 3011 3018 3012 static struct net_device *rtnl_dev_get(struct net *net, 3019 - struct nlattr *ifname_attr, 3020 - struct nlattr *altifname_attr, 3021 - char *ifname) 3013 + struct nlattr *tb[]) 3022 3014 { 3023 - char buffer[ALTIFNAMSIZ]; 3015 + char ifname[ALTIFNAMSIZ]; 3024 3016 3025 - if (!ifname) { 3026 - ifname = buffer; 3027 - if (ifname_attr) 3028 - nla_strscpy(ifname, ifname_attr, IFNAMSIZ); 3029 - else if (altifname_attr) 3030 - nla_strscpy(ifname, altifname_attr, ALTIFNAMSIZ); 3031 - else 3032 - return NULL; 3033 - } 3017 + if (tb[IFLA_IFNAME]) 3018 + nla_strscpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); 3019 + else if (tb[IFLA_ALT_IFNAME]) 3020 + nla_strscpy(ifname, tb[IFLA_ALT_IFNAME], ALTIFNAMSIZ); 3021 + else 3022 + return NULL; 3034 3023 3035 3024 return __dev_get_by_name(net, ifname); 3036 3025 } ··· 3038 3037 struct net_device *dev; 3039 3038 int err; 3040 3039 struct nlattr *tb[IFLA_MAX+1]; 3041 - char ifname[IFNAMSIZ]; 3042 3040 3043 3041 err = nlmsg_parse_deprecated(nlh, sizeof(*ifm), tb, IFLA_MAX, 3044 3042 ifla_policy, extack); ··· 3048 3048 if (err < 0) 3049 3049 goto errout; 3050 3050 3051 - if (tb[IFLA_IFNAME]) 3052 - nla_strscpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); 3053 - else 3054 - ifname[0] = '\0'; 3055 - 3056 3051 err = -EINVAL; 3057 3052 ifm = nlmsg_data(nlh); 3058 3053 if (ifm->ifi_index > 0) 3059 3054 dev = __dev_get_by_index(net, ifm->ifi_index); 3060 3055 else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME]) 3061 - dev = rtnl_dev_get(net, NULL, tb[IFLA_ALT_IFNAME], ifname); 3056 + dev = rtnl_dev_get(net, tb); 3062 3057 else 3063 3058 goto errout; 3064 3059 ··· 3062 3067 goto errout; 3063 3068 } 3064 3069 3065 - err = do_setlink(skb, dev, ifm, extack, tb, ifname, 0); 3070 + err = do_setlink(skb, dev, ifm, extack, tb, 0); 3066 3071 errout: 3067 3072 return err; 3068 3073 } ··· 3151 3156 if (ifm->ifi_index > 0) 3152 3157 dev = __dev_get_by_index(tgt_net, ifm->ifi_index); 3153 3158 else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME]) 3154 - dev = rtnl_dev_get(net, tb[IFLA_IFNAME], 3155 - tb[IFLA_ALT_IFNAME], NULL); 3159 + dev = rtnl_dev_get(net, tb); 3156 3160 else if (tb[IFLA_GROUP]) 3157 3161 err = rtnl_group_dellink(tgt_net, nla_get_u32(tb[IFLA_GROUP])); 3158 3162 else 3159 3163 goto out; 3160 3164 3161 3165 if (!dev) { 3162 - if (tb[IFLA_IFNAME] || ifm->ifi_index > 0) 3166 + if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME] || ifm->ifi_index > 0) 3163 3167 err = -ENODEV; 3164 3168 3165 3169 goto out; ··· 3293 3299 3294 3300 for_each_netdev_safe(net, dev, aux) { 3295 3301 if (dev->group == group) { 3296 - err = do_setlink(skb, dev, ifm, extack, tb, NULL, 0); 3302 + err = do_setlink(skb, dev, ifm, extack, tb, 0); 3297 3303 if (err < 0) 3298 3304 return err; 3299 3305 } ··· 3320 3326 struct ifinfomsg *ifm; 3321 3327 char ifname[IFNAMSIZ]; 3322 3328 struct nlattr **data; 3329 + bool link_specified; 3323 3330 int err; 3324 3331 3325 3332 #ifdef CONFIG_MODULES ··· 3335 3340 if (err < 0) 3336 3341 return err; 3337 3342 3338 - if (tb[IFLA_IFNAME]) 3339 - nla_strscpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); 3340 - else 3341 - ifname[0] = '\0'; 3342 - 3343 3343 ifm = nlmsg_data(nlh); 3344 - if (ifm->ifi_index > 0) 3344 + if (ifm->ifi_index > 0) { 3345 + link_specified = true; 3345 3346 dev = __dev_get_by_index(net, ifm->ifi_index); 3346 - else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME]) 3347 - dev = rtnl_dev_get(net, NULL, tb[IFLA_ALT_IFNAME], ifname); 3348 - else 3347 + } else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME]) { 3348 + link_specified = true; 3349 + dev = rtnl_dev_get(net, tb); 3350 + } else { 3351 + link_specified = false; 3349 3352 dev = NULL; 3353 + } 3350 3354 3351 3355 master_dev = NULL; 3352 3356 m_ops = NULL; ··· 3444 3450 status |= DO_SETLINK_NOTIFY; 3445 3451 } 3446 3452 3447 - return do_setlink(skb, dev, ifm, extack, tb, ifname, status); 3453 + return do_setlink(skb, dev, ifm, extack, tb, status); 3448 3454 } 3449 3455 3450 3456 if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { 3451 - if (ifm->ifi_index == 0 && tb[IFLA_GROUP]) 3457 + /* No dev found and NLM_F_CREATE not set. Requested dev does not exist, 3458 + * or it's for a group 3459 + */ 3460 + if (link_specified) 3461 + return -ENODEV; 3462 + if (tb[IFLA_GROUP]) 3452 3463 return rtnl_group_changelink(skb, net, 3453 3464 nla_get_u32(tb[IFLA_GROUP]), 3454 3465 ifm, extack, tb); 3455 - return -ENODEV; 3466 + return -EINVAL; 3456 3467 } 3457 3468 3458 3469 if (tb[IFLA_MAP] || tb[IFLA_PROTINFO]) ··· 3481 3482 if (!ops->alloc && !ops->setup) 3482 3483 return -EOPNOTSUPP; 3483 3484 3484 - if (!ifname[0]) { 3485 + if (tb[IFLA_IFNAME]) { 3486 + nla_strscpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); 3487 + } else { 3485 3488 snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); 3486 3489 name_assign_type = NET_NAME_ENUM; 3487 3490 } ··· 3655 3654 if (ifm->ifi_index > 0) 3656 3655 dev = __dev_get_by_index(tgt_net, ifm->ifi_index); 3657 3656 else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME]) 3658 - dev = rtnl_dev_get(tgt_net, tb[IFLA_IFNAME], 3659 - tb[IFLA_ALT_IFNAME], NULL); 3657 + dev = rtnl_dev_get(tgt_net, tb); 3660 3658 else 3661 3659 goto out; 3662 3660 ··· 3750 3750 if (ifm->ifi_index > 0) 3751 3751 dev = __dev_get_by_index(net, ifm->ifi_index); 3752 3752 else if (tb[IFLA_IFNAME] || tb[IFLA_ALT_IFNAME]) 3753 - dev = rtnl_dev_get(net, tb[IFLA_IFNAME], 3754 - tb[IFLA_ALT_IFNAME], NULL); 3753 + dev = rtnl_dev_get(net, tb); 3755 3754 else 3756 3755 return -EINVAL; 3757 3756