net: ar8216: address security vulnerabilities in swconfig & ar8216
Imported from e1aaf7ec00%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>
			
			
This commit is contained in:
		 Pavel Kubelun
					Pavel Kubelun
				
			
				
					committed by
					
						 John Crispin
						John Crispin
					
				
			
			
				
	
			
			
			 John Crispin
						John Crispin
					
				
			
						parent
						
							a3454d1929
						
					
				
				
					commit
					5a69f59602
				
			| @@ -536,7 +536,7 @@ ar8216_mangle_rx(struct net_device *dev, struct sk_buff *skb) | |||||||
| 	if ((buf[12 + 2] != 0x81) || (buf[13 + 2] != 0x00)) | 	if ((buf[12 + 2] != 0x81) || (buf[13 + 2] != 0x00)) | ||||||
| 		return; | 		return; | ||||||
|  |  | ||||||
| 	port = buf[0] & 0xf; | 	port = buf[0] & 0x7; | ||||||
|  |  | ||||||
| 	/* no need to fix up packets coming from a tagged source */ | 	/* no need to fix up packets coming from a tagged source */ | ||||||
| 	if (priv->vlan_tagged & (1 << port)) | 	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; | 		return -EINVAL; | ||||||
|  |  | ||||||
| 	priv->pvid[port] = vlan; | 	priv->pvid[port] = vlan; | ||||||
| @@ -960,6 +961,10 @@ int | |||||||
| ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan) | ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan) | ||||||
| { | { | ||||||
| 	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); | 	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); | ||||||
|  |  | ||||||
|  | 	if (port < 0 || port >= AR8X16_MAX_PORTS) | ||||||
|  | 		return -EINVAL; | ||||||
|  |  | ||||||
| 	*vlan = priv->pvid[port]; | 	*vlan = priv->pvid[port]; | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| @@ -969,6 +974,10 @@ ar8xxx_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr, | |||||||
| 		  struct switch_val *val) | 		  struct switch_val *val) | ||||||
| { | { | ||||||
| 	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); | 	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; | 	priv->vlan_id[val->port_vlan] = val->value.i; | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| @@ -996,9 +1005,13 @@ static int | |||||||
| ar8xxx_sw_get_ports(struct switch_dev *dev, struct switch_val *val) | ar8xxx_sw_get_ports(struct switch_dev *dev, struct switch_val *val) | ||||||
| { | { | ||||||
| 	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); | 	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; | 	val->len = 0; | ||||||
| 	for (i = 0; i < dev->ports; i++) { | 	for (i = 0; i < dev->ports; i++) { | ||||||
| 		struct switch_port *p; | 		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); | 	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev); | ||||||
| 	const struct ar8xxx_chip *chip = priv->chip; | 	const struct ar8xxx_chip *chip = priv->chip; | ||||||
| 	u64 *mib_stats, mib_data; | 	u64 *mib_stats, mib_data; | ||||||
| 	int port; | 	unsigned int port; | ||||||
| 	int ret; | 	int ret; | ||||||
| 	char *buf = priv->buf; | 	char *buf = priv->buf; | ||||||
| 	char buf1[64]; | 	char buf1[64]; | ||||||
|   | |||||||
| @@ -506,7 +506,7 @@ swconfig_lookup_attr(struct switch_dev *dev, struct genl_info *info, | |||||||
| 	struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); | 	struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); | ||||||
| 	const struct switch_attrlist *alist; | 	const struct switch_attrlist *alist; | ||||||
| 	const struct switch_attr *attr = NULL; | 	const struct switch_attr *attr = NULL; | ||||||
| 	int attr_id; | 	unsigned int attr_id; | ||||||
|  |  | ||||||
| 	/* defaults */ | 	/* defaults */ | ||||||
| 	struct switch_attr *def_list; | 	struct switch_attr *def_list; | ||||||
| @@ -590,11 +590,13 @@ swconfig_parse_ports(struct sk_buff *msg, struct nlattr *head, | |||||||
| 	val->len = 0; | 	val->len = 0; | ||||||
| 	nla_for_each_nested(nla, head, rem) { | 	nla_for_each_nested(nla, head, rem) { | ||||||
| 		struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1]; | 		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) | 		if (val->len >= max) | ||||||
| 			return -EINVAL; | 			return -EINVAL; | ||||||
|  |  | ||||||
|  | 		port = &val->value.ports[val->len]; | ||||||
|  |  | ||||||
| 		if (nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, nla, | 		if (nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, nla, | ||||||
| 				port_policy)) | 				port_policy)) | ||||||
| 			return -EINVAL; | 			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) { | 	if (dev->ports > 0) { | ||||||
| 		dev->portbuf = kzalloc(sizeof(struct switch_port) * | 		dev->portbuf = kzalloc(sizeof(struct switch_port) * | ||||||
| 				dev->ports, GFP_KERNEL); | 				dev->ports, GFP_KERNEL); | ||||||
| @@ -1227,4 +1234,3 @@ swconfig_exit(void) | |||||||
|  |  | ||||||
| module_init(swconfig_init); | module_init(swconfig_init); | ||||||
| module_exit(swconfig_exit); | module_exit(swconfig_exit); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -115,12 +115,12 @@ struct switch_dev { | |||||||
| 	const char *alias; | 	const char *alias; | ||||||
| 	struct net_device *netdev; | 	struct net_device *netdev; | ||||||
|  |  | ||||||
| 	int ports; | 	unsigned int ports; | ||||||
| 	int vlans; | 	unsigned int vlans; | ||||||
| 	int cpu_port; | 	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; | 	struct list_head dev_list; | ||||||
| 	unsigned long def_global, def_port, def_vlan; | 	unsigned long def_global, def_port, def_vlan; | ||||||
|  |  | ||||||
| @@ -148,8 +148,8 @@ struct switch_portmap { | |||||||
|  |  | ||||||
| struct switch_val { | struct switch_val { | ||||||
| 	const struct switch_attr *attr; | 	const struct switch_attr *attr; | ||||||
| 	int port_vlan; | 	unsigned int port_vlan; | ||||||
| 	int len; | 	unsigned int len; | ||||||
| 	union { | 	union { | ||||||
| 		const char *s; | 		const char *s; | ||||||
| 		u32 i; | 		u32 i; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user