net: dsa: Discard frames from unused ports
authorAndrew Lunn <andrew@lunn.ch>
Sat, 7 Apr 2018 18:37:40 +0000 (20:37 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 24 Apr 2018 07:36:39 +0000 (09:36 +0200)
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 <cphealy@gmail.com>
Fixes: 91da11f870f0 ("net: Distributed Switch Architecture protocol support")
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/dsa/tag_brcm.c
net/dsa/tag_dsa.c
net/dsa/tag_edsa.c
net/dsa/tag_ksz.c
net/dsa/tag_lan9303.c
net/dsa/tag_mtk.c
net/dsa/tag_qca.c
net/dsa/tag_trailer.c

index dbb016434ace8e3952d707c57f41b9e9eab48dd3..de92fc1fc3be6d996e9e0ec0b16ba4a3cc89f959 100644 (file)
@@ -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);
 
index fbf9ca954773d1b0b616f9e3f2ef2f70a1370e86..b3008a9bacf3ef56b34d7dccc5e9fe7d0b955c37 100644 (file)
@@ -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,
index 76367ba1b2e2433466fb56040e775637a6b41a8f..c86b6d90576d0beb227d6cef25ffa010ecdcbeca 100644 (file)
@@ -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
index 010ca0a336c46a34f6a89d8c6975ca4b00642e6e..6c894692b9cdeb5932371a859423a547232d089a 100644 (file)
@@ -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;
index 0b9826105e421b77a22f77b7d8d7686655580ddb..2d1603009e162e9a0a09b76c75c3fa2614937d9e 100644 (file)
@@ -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;
index ec8ee5f43255e7d95ace5b44f3c04860bd0b8507..5c471854412d6aa554243e4f5096a4a5aa0127af 100644 (file)
@@ -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;
index 1d4c70711c0f456e0bcb6f970954e3f1f45dc9b3..b8c05f1cf47db8b81c3c02b53ae882884593a804 100644 (file)
@@ -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;
 
index d2fd4923aa3eb3d1d56f20dd159d0ca87408b835..fcc9aa72877d685986b1ec52df13bc5a650fbcad 100644 (file)
@@ -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;