ax25_rx_fragment() accumulates fragment lengths into ax25_cb->fraglen, which is an unsigned short. When the total exceeds 65535, fraglen wraps around to a small value. The subsequent alloc_skb(fraglen) allocates a too-small buffer, and skb_put() in the copy loop triggers skb_over_panic(). Add pskb_may_pull(skb, 1) at function entry to ensure the segmentation header byte is in the linear data area before dereferencing skb->data. This also rejects zero-length skbs, which the original code did not check for. Two issues in the overflow error path are also fixed: First, the current skb, after skb_pull(skb, 1), is neither enqueued nor freed before returning 1, leaking it. Add kfree_skb(skb) before the return. Second, ax25->fraglen is not reset after skb_queue_purge(). Add ax25->fraglen = 0 to restore a consistent state. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Mashiro Chen --- net/ax25/ax25_in.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index d75b3e9ed93de8..e1834e11bb0b6a 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -35,12 +35,22 @@ static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb) { struct sk_buff *skbn, *skbo; + if (!pskb_may_pull(skb, 1)) + return 0; + if (ax25->fragno != 0) { if (!(*skb->data & AX25_SEG_FIRST)) { if ((ax25->fragno - 1) == (*skb->data & AX25_SEG_REM)) { /* Enqueue fragment */ ax25->fragno = *skb->data & AX25_SEG_REM; skb_pull(skb, 1); /* skip fragno */ + if (ax25->fraglen + skb->len > USHRT_MAX) { + kfree_skb(skb); + skb_queue_purge(&ax25->frag_queue); + ax25->fragno = 0; + ax25->fraglen = 0; + return 1; + } ax25->fraglen += skb->len; skb_queue_tail(&ax25->frag_queue, skb); -- 2.53.0