From 5a69f596027ff45d9daf7c6584a8a9d4f7ea0770 Mon Sep 17 00:00:00 2001 From: Pavel Kubelun Date: Mon, 28 Nov 2016 18:10:05 +0300 Subject: [PATCH] net: ar8216: address security vulnerabilities in swconfig & ar8216 Imported from https://chromium.googlesource.com/chromiumos/third_party/kernel/+/e1aaf7ec008a97311867f0a7d0418e4693fecfd4%5E%21/#F0 Signed-off-by: Pavel Kubelun CHROMIUM: net: ar8216: address security vulnerabilities in swconfig & ar8216 This patch does the following changes: *address the security vulnerabilities in both swconfig framework and in ar8216 driver (many bound check additions, and turned swconfig structure signed element into unsigned when applicable) *address a couple of whitespaces and indendation issues BUG=chrome-os-partner:33096 TEST=none Change-Id: I94ea78fcce8c1932cc584d1508c6e3b5dfb93ce9 Signed-off-by: Mathieu Olivari Reviewed-on: https://chromium-review.googlesource.com/236490 Reviewed-by: Toshi Kikuchi Commit-Queue: Toshi Kikuchi Tested-by: Toshi Kikuchi --- .../generic/files/drivers/net/phy/ar8216.c | 21 +++++++++++++++---- .../generic/files/drivers/net/phy/swconfig.c | 12 ++++++++--- .../generic/files/include/linux/switch.h | 12 +++++------ 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c index 6c670dd75f..746d8e6c3d 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8216.c +++ b/target/linux/generic/files/drivers/net/phy/ar8216.c @@ -536,7 +536,7 @@ ar8216_mangle_rx(struct net_device *dev, struct sk_buff *skb) if ((buf[12 + 2] != 0x81) || (buf[13 + 2] != 0x00)) return; - port = buf[0] & 0xf; + port = buf[0] & 0x7; /* no need to fix up packets coming from a tagged source */ if (priv->vlan_tagged & (1 << port)) @@ -949,7 +949,8 @@ ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan) /* make sure no invalid PVIDs get set */ - if (vlan >= dev->vlans) + if (vlan < 0 || vlan >= dev->vlans || + port < 0 || port >= AR8X16_MAX_PORTS) return -EINVAL; priv->pvid[port] = vlan; @@ -960,6 +961,10 @@ int ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan) { struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + if (port < 0 || port >= AR8X16_MAX_PORTS) + return -EINVAL; + *vlan = priv->pvid[port]; return 0; } @@ -969,6 +974,10 @@ ar8xxx_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) { struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); + + if (val->port_vlan >= AR8X16_MAX_PORTS) + return -EINVAL; + priv->vlan_id[val->port_vlan] = val->value.i; return 0; } @@ -996,9 +1005,13 @@ static int ar8xxx_sw_get_ports(struct switch_dev *dev, struct switch_val *val) { struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); - u8 ports = priv->vlan_table[val->port_vlan]; + u8 ports; int i; + if (val->port_vlan >= AR8X16_MAX_VLANS) + return -EINVAL; + + ports = priv->vlan_table[val->port_vlan]; val->len = 0; for (i = 0; i < dev->ports; i++) { struct switch_port *p; @@ -1378,7 +1391,7 @@ ar8xxx_sw_get_port_mib(struct switch_dev *dev, struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); const struct ar8xxx_chip *chip = priv->chip; u64 *mib_stats, mib_data; - int port; + unsigned int port; int ret; char *buf = priv->buf; char buf1[64]; diff --git a/target/linux/generic/files/drivers/net/phy/swconfig.c b/target/linux/generic/files/drivers/net/phy/swconfig.c index c70ca74cad..63a9588136 100644 --- a/target/linux/generic/files/drivers/net/phy/swconfig.c +++ b/target/linux/generic/files/drivers/net/phy/swconfig.c @@ -506,7 +506,7 @@ swconfig_lookup_attr(struct switch_dev *dev, struct genl_info *info, struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); const struct switch_attrlist *alist; const struct switch_attr *attr = NULL; - int attr_id; + unsigned int attr_id; /* defaults */ struct switch_attr *def_list; @@ -590,11 +590,13 @@ swconfig_parse_ports(struct sk_buff *msg, struct nlattr *head, val->len = 0; nla_for_each_nested(nla, head, rem) { struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1]; - struct switch_port *port = &val->value.ports[val->len]; + struct switch_port *port; if (val->len >= max) return -EINVAL; + port = &val->value.ports[val->len]; + if (nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, nla, port_policy)) return -EINVAL; @@ -1111,6 +1113,11 @@ register_switch(struct switch_dev *dev, struct net_device *netdev) } BUG_ON(!dev->alias); + /* Make sure swdev_id doesn't overflow */ + if (swdev_id == INT_MAX) { + return -ENOMEM; + } + if (dev->ports > 0) { dev->portbuf = kzalloc(sizeof(struct switch_port) * dev->ports, GFP_KERNEL); @@ -1227,4 +1234,3 @@ swconfig_exit(void) module_init(swconfig_init); module_exit(swconfig_exit); - diff --git a/target/linux/generic/files/include/linux/switch.h b/target/linux/generic/files/include/linux/switch.h index dda4820a7a..f8380b98c5 100644 --- a/target/linux/generic/files/include/linux/switch.h +++ b/target/linux/generic/files/include/linux/switch.h @@ -115,12 +115,12 @@ struct switch_dev { const char *alias; struct net_device *netdev; - int ports; - int vlans; - int cpu_port; + unsigned int ports; + unsigned int vlans; + unsigned int cpu_port; /* the following fields are internal for swconfig */ - int id; + unsigned int id; struct list_head dev_list; unsigned long def_global, def_port, def_vlan; @@ -148,8 +148,8 @@ struct switch_portmap { struct switch_val { const struct switch_attr *attr; - int port_vlan; - int len; + unsigned int port_vlan; + unsigned int len; union { const char *s; u32 i; -- 2.30.2