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