mirror of
https://github.com/torvalds/linux.git
synced 2026-05-26 16:12:59 +02:00
batman-adv: frag: disallow unicast fragment in fragment
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: stable@kernel.org
Fixes: 610bfc6bc9 ("batman-adv: Receive fragmented packets and merge")
Reported-by: Yuan Tan <yuantan098@gmail.com>
Reported-by: Yifan Wu <yifanwucs@gmail.com>
Reported-by: Juefei Pu <tomapufckgml@gmail.com>
Reported-by: Xin Liu <bird@lzu.edu.cn>
Reviewed-by: Yuan Tan <yuantan098@gmail.com>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
This commit is contained in:
parent
6c65cf23d4
commit
bc62216dc8
|
|
@ -304,6 +304,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
|
||||
|
|
@ -337,6 +362,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:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user