| From foo@baz Tue 01 Oct 2019 03:27:55 PM CEST |
| From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> |
| Date: Fri, 20 Sep 2019 16:08:21 +0200 |
| Subject: arcnet: provide a buffer big enough to actually receive packets |
| |
| From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> |
| |
| [ Upstream commit 108639aac35eb57f1d0e8333f5fc8c7ff68df938 ] |
| |
| 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> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/arcnet/arcnet.c | 31 +++++++++++++++++-------------- |
| 1 file changed, 17 insertions(+), 14 deletions(-) |
| |
| --- a/drivers/net/arcnet/arcnet.c |
| +++ b/drivers/net/arcnet/arcnet.c |
| @@ -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 |
| 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 |
| 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, |