net: ar8216: address security vulnerabilities in swconfig & ar8216
authorPavel Kubelun <be.dissent@gmail.com>
Mon, 28 Nov 2016 15:10:05 +0000 (18:10 +0300)
committerJohn Crispin <john@phrozen.org>
Thu, 1 Dec 2016 14:47:43 +0000 (15:47 +0100)
Imported from https://chromium.googlesource.com/chromiumos/third_party/kernel/+/e1aaf7ec008a97311867f0a7d0418e4693fecfd4%5E%21/#F0
Signed-off-by: Pavel Kubelun <be.dissent@gmail.com>
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 <mathieu@codeaurora.org>
Reviewed-on: https://chromium-review.googlesource.com/236490
Reviewed-by: Toshi Kikuchi <toshik@chromium.org>
Commit-Queue: Toshi Kikuchi <toshik@chromium.org>
Tested-by: Toshi Kikuchi <toshik@chromium.org>
target/linux/generic/files/drivers/net/phy/ar8216.c
target/linux/generic/files/drivers/net/phy/swconfig.c
target/linux/generic/files/include/linux/switch.h

index 6c670dd75f18c64ae9a48c64fcf17d60904cab9a..746d8e6c3dcc312b03f851901b0c4d9ec8edfa96 100644 (file)
@@ -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;
 
        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))
 
        /* 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 */
 
 
        /* 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;
                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);
 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;
 }
        *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);
                  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;
 }
        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);
 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;
 
        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;
        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;
        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];
        int ret;
        char *buf = priv->buf;
        char buf1[64];
index c70ca74cadde948bd330543cdf9811ce130899b1..63a95881361ca76bd8a5f624f48dbe9b121d62dd 100644 (file)
@@ -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;
        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;
 
        /* 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];
        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;
 
 
                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;
                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);
 
        }
        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);
        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);
 
 module_init(swconfig_init);
 module_exit(swconfig_exit);
-
index dda4820a7a4bb85896b48162d2993b5b9a254cbb..f8380b98c56687810816025f63f4e062b69e6f06 100644 (file)
@@ -115,12 +115,12 @@ struct switch_dev {
        const char *alias;
        struct net_device *netdev;
 
        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 */
 
        /* 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;
 
        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;
 
 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;
        union {
                const char *s;
                u32 i;