From 30593709f80ddf23a3e8b41f3a7edfc68c4786be Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 7 Apr 2018 20:37:40 +0200 Subject: [PATCH] net: dsa: Discard frames from unused ports commit fc5f33768cca7144f8d793205b229d46740d183b upstream. The Marvell switches under some conditions will pass a frame to the host with the port being the CPU port. Such frames are invalid, and should be dropped. Not dropping them can result in a crash when incrementing the receive statistics for an invalid port. This has been reworked for 4.14, which does not have the central dsa_master_find_slave() function, so each tag driver needs to check. Reported-by: Chris Healy Fixes: 91da11f870f0 ("net: Distributed Switch Architecture protocol support") Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/dsa/tag_brcm.c | 3 +++ net/dsa/tag_dsa.c | 3 +++ net/dsa/tag_edsa.c | 3 +++ net/dsa/tag_ksz.c | 3 +++ net/dsa/tag_lan9303.c | 3 +++ net/dsa/tag_mtk.c | 3 +++ net/dsa/tag_qca.c | 3 +++ net/dsa/tag_trailer.c | 3 +++ 8 files changed, 24 insertions(+) diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c index dbb0164..de92fc1 100644 --- a/net/dsa/tag_brcm.c +++ b/net/dsa/tag_brcm.c @@ -121,6 +121,9 @@ static struct sk_buff *brcm_tag_rcv(struct sk_buff *skb, struct net_device *dev, if (source_port >= ds->num_ports || !ds->ports[source_port].netdev) return NULL; + if (unlikely(ds->cpu_port_mask & BIT(source_port))) + return NULL; + /* Remove Broadcom tag and update checksum */ skb_pull_rcsum(skb, BRCM_TAG_LEN); diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c index fbf9ca9..b3008a9 100644 --- a/net/dsa/tag_dsa.c +++ b/net/dsa/tag_dsa.c @@ -107,6 +107,9 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev, if (source_port >= ds->num_ports || !ds->ports[source_port].netdev) return NULL; + if (unlikely(ds->cpu_port_mask & BIT(source_port))) + return NULL; + /* * Convert the DSA header to an 802.1q header if the 'tagged' * bit in the DSA header is set. If the 'tagged' bit is clear, diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c index 76367ba..c86b6d9 100644 --- a/net/dsa/tag_edsa.c +++ b/net/dsa/tag_edsa.c @@ -120,6 +120,9 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev, if (source_port >= ds->num_ports || !ds->ports[source_port].netdev) return NULL; + if (unlikely(ds->cpu_port_mask & BIT(source_port))) + return NULL; + /* * If the 'tagged' bit is set, convert the DSA tag to a 802.1q * tag and delete the ethertype part. If the 'tagged' bit is diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index 010ca0a..6c89469 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -92,6 +92,9 @@ static struct sk_buff *ksz_rcv(struct sk_buff *skb, struct net_device *dev, if (source_port >= ds->num_ports || !ds->ports[source_port].netdev) return NULL; + if (unlikely(ds->cpu_port_mask & BIT(source_port))) + return NULL; + pskb_trim_rcsum(skb, skb->len - KSZ_EGRESS_TAG_LEN); skb->dev = ds->ports[source_port].netdev; diff --git a/net/dsa/tag_lan9303.c b/net/dsa/tag_lan9303.c index 0b98261..2d16030 100644 --- a/net/dsa/tag_lan9303.c +++ b/net/dsa/tag_lan9303.c @@ -108,6 +108,9 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev, return NULL; } + if (unlikely(ds->cpu_port_mask & BIT(source_port))) + return NULL; + if (!ds->ports[source_port].netdev) { dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid netdev or device\n"); return NULL; diff --git a/net/dsa/tag_mtk.c b/net/dsa/tag_mtk.c index ec8ee5f..5c47185 100644 --- a/net/dsa/tag_mtk.c +++ b/net/dsa/tag_mtk.c @@ -81,6 +81,9 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev, if (!ds->ports[port].netdev) return NULL; + if (unlikely(ds->cpu_port_mask & BIT(port))) + return NULL; + skb->dev = ds->ports[port].netdev; return skb; diff --git a/net/dsa/tag_qca.c b/net/dsa/tag_qca.c index 1d4c707..b8c05f1 100644 --- a/net/dsa/tag_qca.c +++ b/net/dsa/tag_qca.c @@ -104,6 +104,9 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev, if (!ds->ports[port].netdev) return NULL; + if (unlikely(ds->cpu_port_mask & BIT(port))) + return NULL; + /* Update skb & forward the frame accordingly */ skb->dev = ds->ports[port].netdev; diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c index d2fd492..fcc9aa7 100644 --- a/net/dsa/tag_trailer.c +++ b/net/dsa/tag_trailer.c @@ -76,6 +76,9 @@ static struct sk_buff *trailer_rcv(struct sk_buff *skb, struct net_device *dev, if (source_port >= ds->num_ports || !ds->ports[source_port].netdev) return NULL; + if (unlikely(ds->cpu_port_mask & BIT(source_port))) + return NULL; + pskb_trim_rcsum(skb, skb->len - 4); skb->dev = ds->ports[source_port].netdev; -- 2.7.4