On Wed, May 13, 2026 at 12:01 AM Sven Eckelmann <[email protected]> wrote: > > batadv_frag_skb_buffer() is called by batadv_batman_skb_recv() when a > BATADV_UNICAST_FRAG packet is received. Once all fragments are collected > and the packet is reassembled, batadv_recv_frag_packet() calls > batadv_batman_skb_recv() again to process the defragmented payload. > > A malicious sender can craft a BATADV_UNICAST_FRAG packet whose reassembled > payload is itself a BATADV_UNICAST_FRAG packet (matryoshka-style nesting). > Each nesting level recurses through batadv_batman_skb_recv() without bound, > growing the kernel stack until it is exhausted. > > Since refragmentation or fragments in fragments are not actually allowed, > discard all packets which are still BATADV_UNICAST_FRAG packets after the > defragmentation process. > > Cc: [email protected] > Fixes: 610bfc6bc99b ("batman-adv: Receive fragmented packets and merge") > Reported-by: Yuan Tan <[email protected]> > Reported-by: Yifan Wu <[email protected]> > Reported-by: Juefei Pu <[email protected]> > Reported-by: Xin Liu <[email protected]> > Signed-off-by: Sven Eckelmann <[email protected]> > --- > net/batman-adv/fragmentation.c | 35 +++++++++++++++++++++++++++++++++++ > 1 file changed, 35 insertions(+) > > diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c > index f4e45cc2..42f3d4ee 100644 > --- a/net/batman-adv/fragmentation.c > +++ b/net/batman-adv/fragmentation.c > @@ -293,6 +293,31 @@ batadv_frag_merge_packets(struct hlist_head *chain) > return skb_out; > } > > +/** > + * batadv_skb_is_frag() - check if newly merged skb is gain a unicast packet > + * @skb: newly merged skb > + * > + * Return: if newly skb is of type BATADV_UNICAST_FRAG > + */ > +static bool batadv_skb_is_frag(struct sk_buff *skb) > +{ > + struct batadv_ogm_packet *batadv_ogm_packet; > + > + /* packet should hold at least type and version */ > + if (unlikely(!pskb_may_pull(skb, 2))) > + return false; > + > + batadv_ogm_packet = (struct batadv_ogm_packet *)skb->data; > + > + if (batadv_ogm_packet->version != BATADV_COMPAT_VERSION) > + return false; > + > + if (batadv_ogm_packet->packet_type != BATADV_UNICAST_FRAG) > + return false; > + > + return true; > +} > + > /** > * batadv_frag_skb_buffer() - buffer fragment for later merge > * @skb: skb to buffer > @@ -326,6 +351,16 @@ bool batadv_frag_skb_buffer(struct sk_buff **skb, > if (!skb_out) > goto out_err; > > + /* fragment in fragment is not allowed. otherwise it is possible > + * to exhaust the stack when receiving a matryoshka-style > + * "fragments in a fragment packet" > + */ > + if (batadv_skb_is_frag(skb_out)) { > + kfree_skb(skb_out); > + skb_out = NULL; > + goto out_err; > + } > + > out: > ret = true; > out_err: > > -- > 2.47.3 >
Reviewed-by: Yuan Tan <[email protected]>
