Merge branch 'vlan-rtnetlink-newlink-fixes'

Eric Dumazet says:

====================
vlan: rtnetlink newlink fixes

First patch fixes a potential memory leak found by syzbot

Second patch makes vlan_changelink() aware of errors
and report them to user.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2020-01-07 13:35:14 -08:00
commit b57e1fff7d
3 changed files with 15 additions and 8 deletions

View File

@ -126,6 +126,7 @@ int vlan_check_real_dev(struct net_device *real_dev,
void vlan_setup(struct net_device *dev); void vlan_setup(struct net_device *dev);
int register_vlan_dev(struct net_device *dev, struct netlink_ext_ack *extack); int register_vlan_dev(struct net_device *dev, struct netlink_ext_ack *extack);
void unregister_vlan_dev(struct net_device *dev, struct list_head *head); void unregister_vlan_dev(struct net_device *dev, struct list_head *head);
void vlan_dev_uninit(struct net_device *dev);
bool vlan_dev_inherit_address(struct net_device *dev, bool vlan_dev_inherit_address(struct net_device *dev,
struct net_device *real_dev); struct net_device *real_dev);

View File

@ -586,7 +586,8 @@ static int vlan_dev_init(struct net_device *dev)
return 0; return 0;
} }
static void vlan_dev_uninit(struct net_device *dev) /* Note: this function might be called multiple times for the same device. */
void vlan_dev_uninit(struct net_device *dev)
{ {
struct vlan_priority_tci_mapping *pm; struct vlan_priority_tci_mapping *pm;
struct vlan_dev_priv *vlan = vlan_dev_priv(dev); struct vlan_dev_priv *vlan = vlan_dev_priv(dev);

View File

@ -108,11 +108,13 @@ static int vlan_changelink(struct net_device *dev, struct nlattr *tb[],
struct ifla_vlan_flags *flags; struct ifla_vlan_flags *flags;
struct ifla_vlan_qos_mapping *m; struct ifla_vlan_qos_mapping *m;
struct nlattr *attr; struct nlattr *attr;
int rem; int rem, err;
if (data[IFLA_VLAN_FLAGS]) { if (data[IFLA_VLAN_FLAGS]) {
flags = nla_data(data[IFLA_VLAN_FLAGS]); flags = nla_data(data[IFLA_VLAN_FLAGS]);
vlan_dev_change_flags(dev, flags->flags, flags->mask); err = vlan_dev_change_flags(dev, flags->flags, flags->mask);
if (err)
return err;
} }
if (data[IFLA_VLAN_INGRESS_QOS]) { if (data[IFLA_VLAN_INGRESS_QOS]) {
nla_for_each_nested(attr, data[IFLA_VLAN_INGRESS_QOS], rem) { nla_for_each_nested(attr, data[IFLA_VLAN_INGRESS_QOS], rem) {
@ -123,7 +125,9 @@ static int vlan_changelink(struct net_device *dev, struct nlattr *tb[],
if (data[IFLA_VLAN_EGRESS_QOS]) { if (data[IFLA_VLAN_EGRESS_QOS]) {
nla_for_each_nested(attr, data[IFLA_VLAN_EGRESS_QOS], rem) { nla_for_each_nested(attr, data[IFLA_VLAN_EGRESS_QOS], rem) {
m = nla_data(attr); m = nla_data(attr);
vlan_dev_set_egress_priority(dev, m->from, m->to); err = vlan_dev_set_egress_priority(dev, m->from, m->to);
if (err)
return err;
} }
} }
return 0; return 0;
@ -179,10 +183,11 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev,
return -EINVAL; return -EINVAL;
err = vlan_changelink(dev, tb, data, extack); err = vlan_changelink(dev, tb, data, extack);
if (err < 0) if (!err)
err = register_vlan_dev(dev, extack);
if (err)
vlan_dev_uninit(dev);
return err; return err;
return register_vlan_dev(dev, extack);
} }
static inline size_t vlan_qos_map_size(unsigned int n) static inline size_t vlan_qos_map_size(unsigned int n)