arcnet: provide a buffer big enough to actually receive packets
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Fri, 20 Sep 2019 14:08:21 +0000 (16:08 +0200)
committerDavid S. Miller <davem@davemloft.net>
Tue, 24 Sep 2019 14:48:31 +0000 (16:48 +0200)
struct archdr is only big enough to hold the header of various types of
arcnet packets. So to provide enough space to hold the data read from
hardware provide a buffer large enough to hold a packet with maximal
size.

The problem was noticed by the stack protector which makes the kernel
oops.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Acked-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/arcnet/arcnet.c

index 8459115..553776c 100644 (file)
@@ -1063,31 +1063,34 @@ EXPORT_SYMBOL(arcnet_interrupt);
 static void arcnet_rx(struct net_device *dev, int bufnum)
 {
        struct arcnet_local *lp = netdev_priv(dev);
-       struct archdr pkt;
+       union {
+               struct archdr pkt;
+               char buf[512];
+       } rxdata;
        struct arc_rfc1201 *soft;
        int length, ofs;
 
-       soft = &pkt.soft.rfc1201;
+       soft = &rxdata.pkt.soft.rfc1201;
 
-       lp->hw.copy_from_card(dev, bufnum, 0, &pkt, ARC_HDR_SIZE);
-       if (pkt.hard.offset[0]) {
-               ofs = pkt.hard.offset[0];
+       lp->hw.copy_from_card(dev, bufnum, 0, &rxdata.pkt, ARC_HDR_SIZE);
+       if (rxdata.pkt.hard.offset[0]) {
+               ofs = rxdata.pkt.hard.offset[0];
                length = 256 - ofs;
        } else {
-               ofs = pkt.hard.offset[1];
+               ofs = rxdata.pkt.hard.offset[1];
                length = 512 - ofs;
        }
 
        /* get the full header, if possible */
-       if (sizeof(pkt.soft) <= length) {
-               lp->hw.copy_from_card(dev, bufnum, ofs, soft, sizeof(pkt.soft));
+       if (sizeof(rxdata.pkt.soft) <= length) {
+               lp->hw.copy_from_card(dev, bufnum, ofs, soft, sizeof(rxdata.pkt.soft));
        } else {
-               memset(&pkt.soft, 0, sizeof(pkt.soft));
+               memset(&rxdata.pkt.soft, 0, sizeof(rxdata.pkt.soft));
                lp->hw.copy_from_card(dev, bufnum, ofs, soft, length);
        }
 
        arc_printk(D_DURING, dev, "Buffer #%d: received packet from %02Xh to %02Xh (%d+4 bytes)\n",
-                  bufnum, pkt.hard.source, pkt.hard.dest, length);
+                  bufnum, rxdata.pkt.hard.source, rxdata.pkt.hard.dest, length);
 
        dev->stats.rx_packets++;
        dev->stats.rx_bytes += length + ARC_HDR_SIZE;
@@ -1096,13 +1099,13 @@ static void arcnet_rx(struct net_device *dev, int bufnum)
        if (arc_proto_map[soft->proto]->is_ip) {
                if (BUGLVL(D_PROTO)) {
                        struct ArcProto
-                       *oldp = arc_proto_map[lp->default_proto[pkt.hard.source]],
+                       *oldp = arc_proto_map[lp->default_proto[rxdata.pkt.hard.source]],
                        *newp = arc_proto_map[soft->proto];
 
                        if (oldp != newp) {
                                arc_printk(D_PROTO, dev,
                                           "got protocol %02Xh; encap for host %02Xh is now '%c' (was '%c')\n",
-                                          soft->proto, pkt.hard.source,
+                                          soft->proto, rxdata.pkt.hard.source,
                                           newp->suffix, oldp->suffix);
                        }
                }
@@ -1111,10 +1114,10 @@ static void arcnet_rx(struct net_device *dev, int bufnum)
                lp->default_proto[0] = soft->proto;
 
                /* in striking contrast, the following isn't a hack. */
-               lp->default_proto[pkt.hard.source] = soft->proto;
+               lp->default_proto[rxdata.pkt.hard.source] = soft->proto;
        }
        /* call the protocol-specific receiver. */
-       arc_proto_map[soft->proto]->rx(dev, bufnum, &pkt, length);
+       arc_proto_map[soft->proto]->rx(dev, bufnum, &rxdata.pkt, length);
 }
 
 static void null_rx(struct net_device *dev, int bufnum,