lists.openwall.net | lists / announce owl-users owl-dev john-users john-dev passwdqc-users yescrypt popa3d-users / oss-security kernel-hardening musl sabotage tlsify passwords / crypt-dev xvendor / Bugtraq Full-Disclosure linux-kernel linux-netdev linux-ext4 linux-hardening linux-cve-announce PHC | |
Open Source and information security mailing list archives
| ||
|
Date: Wed, 23 Feb 2022 20:25:09 -0800 From: Jakub Kicinski <kuba@...nel.org> To: Roopa Prabhu <roopa@...dia.com> Cc: <davem@...emloft.net>, <netdev@...r.kernel.org>, <stephen@...workplumber.org>, <nikolay@...ulusnetworks.com>, <idosch@...dia.com>, <dsahern@...il.com>, <bpoirier@...dia.com> Subject: Re: [PATCH net-next v2 09/12] vxlan: vni filtering support on collect metadata device On Tue, 22 Feb 2022 02:52:27 +0000 Roopa Prabhu wrote: > +static int vxlan_vni_add(struct vxlan_dev *vxlan, > + struct vxlan_vni_group *vg, > + u32 vni, union vxlan_addr *group, > + struct netlink_ext_ack *extack) > +{ > + struct vxlan_vni_node *vninode; > + __be32 v = cpu_to_be32(vni); > + bool changed = false; > + int err = 0; > + > + if (vxlan_vnifilter_lookup(vxlan, v)) > + return vxlan_vni_update(vxlan, vg, v, group, &changed, extack); > + > + err = vxlan_vni_in_use(vxlan->net, vxlan, &vxlan->cfg, v); > + if (err) { > + NL_SET_ERR_MSG(extack, "VNI in use"); > + return err; > + } > + > + vninode = vxlan_vni_alloc(vxlan, v); > + if (!vninode) > + return -ENOMEM; > + > + err = rhashtable_lookup_insert_fast(&vg->vni_hash, > + &vninode->vnode, > + vxlan_vni_rht_params); > + if (err) leak ? > + return err; > + > + __vxlan_vni_add_list(vg, vninode); > + > + if (vxlan->dev->flags & IFF_UP) > + vxlan_vs_add_del_vninode(vxlan, vninode, false); > + > + err = vxlan_vni_update_group(vxlan, vninode, group, true, &changed, > + extack); > + > + if (changed) > + vxlan_vnifilter_notify(vxlan, vninode, RTM_NEWTUNNEL); > + > + return err; > +} > + > +static void vxlan_vni_node_rcu_free(struct rcu_head *rcu) > +{ > + struct vxlan_vni_node *v; > + > + v = container_of(rcu, struct vxlan_vni_node, rcu); > + kfree(v); > +} kfree_rcu()? > +static int vxlan_vni_del(struct vxlan_dev *vxlan, > + struct vxlan_vni_group *vg, > + u32 vni, struct netlink_ext_ack *extack) > +{ > + struct vxlan_vni_node *vninode; > + __be32 v = cpu_to_be32(vni); > + int err = 0; > + > + vg = rtnl_dereference(vxlan->vnigrp); > + > + vninode = rhashtable_lookup_fast(&vg->vni_hash, &v, > + vxlan_vni_rht_params); > + if (!vninode) { > + err = -ENOENT; > + goto out; > + } > + > + vxlan_vni_delete_group(vxlan, vninode); > + > + err = rhashtable_remove_fast(&vg->vni_hash, > + &vninode->vnode, > + vxlan_vni_rht_params); > + if (err) > + goto out; > + > + __vxlan_vni_del_list(vg, vninode); > + > + vxlan_vnifilter_notify(vxlan, vninode, RTM_DELTUNNEL); > + > + if (vxlan->dev->flags & IFF_UP) > + vxlan_vs_add_del_vninode(vxlan, vninode, true); > + > + call_rcu(&vninode->rcu, vxlan_vni_node_rcu_free); > + > + return 0; > +out: > + return err; > +} > + > +static int vxlan_vni_add_del(struct vxlan_dev *vxlan, __u32 start_vni, > + __u32 end_vni, union vxlan_addr *group, > + int cmd, struct netlink_ext_ack *extack) > +{ > + struct vxlan_vni_group *vg; > + int v, err = 0; > + > + vg = rtnl_dereference(vxlan->vnigrp); > + > + for (v = start_vni; v <= end_vni; v++) { > + switch (cmd) { > + case RTM_NEWTUNNEL: > + err = vxlan_vni_add(vxlan, vg, v, group, extack); > + break; > + case RTM_DELTUNNEL: > + err = vxlan_vni_del(vxlan, vg, v, extack); > + break; > + default: > + err = -EOPNOTSUPP; > + break; > + } > + if (err) > + goto out; > + } > + > + return 0; > +out: > + return err; > +} > + > +static int vxlan_process_vni_filter(struct vxlan_dev *vxlan, > + struct nlattr *nlvnifilter, > + int cmd, struct netlink_ext_ack *extack) > +{ > + struct nlattr *vattrs[VXLAN_VNIFILTER_ENTRY_MAX + 1]; > + u32 vni_start = 0, vni_end = 0; > + union vxlan_addr group; > + int err = 0; unnecessary init > + err = nla_parse_nested(vattrs, > + VXLAN_VNIFILTER_ENTRY_MAX, > + nlvnifilter, vni_filter_entry_policy, > + extack); > + if (err) > + return err; > + > + if (vattrs[VXLAN_VNIFILTER_ENTRY_START]) { > + vni_start = nla_get_u32(vattrs[VXLAN_VNIFILTER_ENTRY_START]); > + vni_end = vni_start; > + } > + > + if (vattrs[VXLAN_VNIFILTER_ENTRY_END]) > + vni_end = nla_get_u32(vattrs[VXLAN_VNIFILTER_ENTRY_END]); > + > + if (!vni_start && !vni_end) { > + NL_SET_ERR_MSG_ATTR(extack, nlvnifilter, > + "vni start nor end found in vni entry"); > + return -EINVAL; > + } > + > + if (vattrs[VXLAN_VNIFILTER_ENTRY_GROUP]) { > + group.sin.sin_addr.s_addr = > + nla_get_in_addr(vattrs[VXLAN_VNIFILTER_ENTRY_GROUP]); > + group.sa.sa_family = AF_INET; > + } else if (vattrs[VXLAN_VNIFILTER_ENTRY_GROUP6]) { > + group.sin6.sin6_addr = > + nla_get_in6_addr(vattrs[VXLAN_VNIFILTER_ENTRY_GROUP6]); > + group.sa.sa_family = AF_INET6; > + } else { > + memset(&group, 0, sizeof(group)); > + } > + > + err = vxlan_vni_add_del(vxlan, vni_start, vni_end, &group, cmd, > + extack); > + if (err) > + return err; > + > + return 0; > +} > + > +void vxlan_vnigroup_uninit(struct vxlan_dev *vxlan) > +{ > + struct vxlan_vni_node *v, *tmp; > + struct vxlan_vni_group *vg; > + > + vg = rtnl_dereference(vxlan->vnigrp); > + list_for_each_entry_safe(v, tmp, &vg->vni_list, vlist) { > + rhashtable_remove_fast(&vg->vni_hash, &v->vnode, > + vxlan_vni_rht_params); > + hlist_del_init_rcu(&v->hlist4.hlist); > +#if IS_ENABLED(CONFIG_IPV6) > + hlist_del_init_rcu(&v->hlist6.hlist); > +#endif no need to generate the notifications here? > + __vxlan_vni_del_list(vg, v); > + call_rcu(&v->rcu, vxlan_vni_node_rcu_free); > + } > + rhashtable_destroy(&vg->vni_hash); > + kfree(vg); > +} > + > +int vxlan_vnigroup_init(struct vxlan_dev *vxlan) > +{ > + struct vxlan_vni_group *vg; > + int ret = -ENOMEM; > + > + vg = kzalloc(sizeof(*vg), GFP_KERNEL); > + if (!vg) > + goto out; return -ENOMEM; the jumping dance is really not worth it here > + ret = rhashtable_init(&vg->vni_hash, &vxlan_vni_rht_params); > + if (ret) > + goto err_rhtbl; > + INIT_LIST_HEAD(&vg->vni_list); > + rcu_assign_pointer(vxlan->vnigrp, vg); > + > + return 0; > + > +out: > + return ret; > + > +err_rhtbl: > + kfree(vg); > + > + goto out; > +} > + > +static int vxlan_vnifilter_process(struct sk_buff *skb, struct nlmsghdr *nlh, > + struct netlink_ext_ack *extack) > +{ > + struct net *net = sock_net(skb->sk); > + struct tunnel_msg *tmsg; > + struct vxlan_dev *vxlan; > + struct net_device *dev; > + struct nlattr *attr; > + int err, vnis = 0; > + int rem; > + > + /* this should validate the header and check for remaining bytes */ > + err = nlmsg_parse(nlh, sizeof(*tmsg), NULL, VXLAN_VNIFILTER_MAX, NULL, > + extack); Could be useful to provide a policy here, even if it only points to single type (entry which is nested). Otherwise we will not reject UNSPEC, and validate if ENTRY has NLA_F_NESTED set, no? > + if (err < 0) > + return err; > + > + tmsg = nlmsg_data(nlh); > + dev = __dev_get_by_index(net, tmsg->ifindex); > + if (!dev) > + return -ENODEV; > + > + if (!netif_is_vxlan(dev)) { > + NL_SET_ERR_MSG_MOD(extack, "The device is not a vxlan device"); > + return -EINVAL; > + } > + > + vxlan = netdev_priv(dev); > + > + if (!(vxlan->cfg.flags & VXLAN_F_VNIFILTER)) > + return -EOPNOTSUPP; > + > + nlmsg_for_each_attr(attr, nlh, sizeof(*tmsg), rem) { > + switch (nla_type(attr)) { > + case VXLAN_VNIFILTER_ENTRY: > + err = vxlan_process_vni_filter(vxlan, attr, > + nlh->nlmsg_type, extack); > + break; > + default: > + continue; > + } > + vnis++; > + if (err) > + break; > + } > + > + if (!vnis) { > + NL_SET_ERR_MSG_MOD(extack, "No vnis found to process"); > + err = -EINVAL; > + } > + > + return err; > +}
Powered by blists - more mailing lists