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.
Cc: stable@vger.kernel.org # v2.4.0+ Signed-off-by: Uwe Kleine-König u.kleine-koenig@pengutronix.de --- Hello,
the problem exists in v2.4.0 already, I didn't look further to identify the offending commit.
Best regards Uwe --- drivers/net/arcnet/arcnet.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-)
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 0efef7aa5b89..2b8cf58e4de0 100644 --- 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 *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,
On Fri, Sep 20, 2019 at 04:08:21PM +0200, Uwe Kleine-König wrote:
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.
Cc: stable@vger.kernel.org # v2.4.0+ Signed-off-by: Uwe Kleine-König u.kleine-koenig@pengutronix.de
Acked-by: Michael Grzeschik m.grzeschik@pengutronix.de
Hello,
the problem exists in v2.4.0 already, I didn't look further to identify the offending commit.
Best regards Uwe
drivers/net/arcnet/arcnet.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-)
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 0efef7aa5b89..2b8cf58e4de0 100644 --- 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]) {
length = 256 - ofs; } else {ofs = rxdata.pkt.hard.offset[0];
ofs = pkt.hard.offset[1];
length = 512 - ofs; }ofs = rxdata.pkt.hard.offset[1];
/* 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) {
} else {lp->hw.copy_from_card(dev, bufnum, ofs, soft, sizeof(rxdata.pkt.soft));
memset(&pkt.soft, 0, sizeof(pkt.soft));
lp->hw.copy_from_card(dev, bufnum, ofs, soft, length); }memset(&rxdata.pkt.soft, 0, sizeof(rxdata.pkt.soft));
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;
} /* call the protocol-specific receiver. */lp->default_proto[rxdata.pkt.hard.source] = soft->proto;
- 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, -- 2.23.0
From: Uwe Kleine-König u.kleine-koenig@pengutronix.de Date: Fri, 20 Sep 2019 16:08:21 +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.
Cc: stable@vger.kernel.org # v2.4.0+
Do not CC: stable for networking patches, I take care of it.
Signed-off-by: Uwe Kleine-König u.kleine-koenig@pengutronix.de
Applied and queued up for -stable.
linux-stable-mirror@lists.linaro.org