diff --git a/sys/net/gnrc/network_layer/ipv6/ext/frag/gnrc_ipv6_ext_frag.c b/sys/net/gnrc/network_layer/ipv6/ext/frag/gnrc_ipv6_ext_frag.c index c57407729e..2cdefe2428 100644 --- a/sys/net/gnrc/network_layer/ipv6/ext/frag/gnrc_ipv6_ext_frag.c +++ b/sys/net/gnrc/network_layer/ipv6/ext/frag/gnrc_ipv6_ext_frag.c @@ -423,6 +423,10 @@ gnrc_pktsnip_t *gnrc_ipv6_ext_frag_reass(gnrc_pktsnip_t *pkt) DEBUG("ipv6_ext_frag: unable to mark fragmentation header\n"); goto error_release; } + else if (pkt->size == 0) { + DEBUG("ipv6_ext_frag: fragment empty after removing header\n"); + goto error_release; + } fh = fh_snip->data; /* search IPv6 header */ ipv6_snip = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6); @@ -524,6 +528,11 @@ gnrc_pktsnip_t *gnrc_ipv6_ext_frag_reass(gnrc_pktsnip_t *pkt) DEBUG("ipv6_ext_frag: fragment length not divisible by 8"); goto error_exit; } + else if (rbuf->pkt != NULL && rbuf->pkt->size < pkt->size) { + DEBUG("ipv6_ext_frag: reassembly buffer too small to fit first " + "fragment\n"); + goto error_exit; + } _set_nh(fh_snip->next, nh); gnrc_pktbuf_remove_snip(pkt, fh_snip); /* TODO: RFC 8200 says "- 8"; determine if `sizeof(ipv6_ext_frag_t)` is diff --git a/tests/net/gnrc_ipv6_ext_frag/tests-as-root/01-run.py b/tests/net/gnrc_ipv6_ext_frag/tests-as-root/01-run.py index 9687b81124..8c8c4615cd 100755 --- a/tests/net/gnrc_ipv6_ext_frag/tests-as-root/01-run.py +++ b/tests/net/gnrc_ipv6_ext_frag/tests-as-root/01-run.py @@ -157,6 +157,39 @@ def test_reass_offset_too_large(child, iface, hw_dst, ll_dst, ll_src): pktbuf_empty(child) +def test_reass_empty_fragment(child, iface, hw_dst, ll_dst, ll_src): + # Originally proposed by Nils Bernsdorf (Uni Saarland), adapted by Martine Lenders + # send the first packet (without payload) to initialize the reassembly buffer + # with a null pointer + sendp(Ether(dst=hw_dst) / IPv6(dst=ll_dst, src=ll_src) / + IPv6ExtHdrFragment(id=0xabcd, nh=0, m=1, offset=0), + iface=iface, verbose=0) + # send the second packet to potentially trigger a memcpy + sendp(Ether(dst=hw_dst) / IPv6(dst=ll_dst, src=ll_src) / + IPv6ExtHdrFragment(id=0xabcd, nh=0, m=1, offset=0) / + (b"A" * (24 - 8)), + iface=iface, verbose=0) + time.sleep(11) # let reassembly buffer garbage collect + pktbuf_empty(child) + + +def test_reass_first_fragment_repeat(child, iface, hw_dst, ll_dst, ll_src): + # Originally proposed by Nils Bernsdorf (Uni Saarland), adapted by Martine Lenders + # send the first packet to initialize the reassembly buffer + sendp(Ether(dst=hw_dst) / IPv6(dst=ll_dst, src=ll_src) / + IPv6ExtHdrFragment(id=0xabcd, nh=0, m=1, offset=0) / + (b"A"*(24-8)), + iface=iface, verbose=0) + # send the a second larger packet (also with offset 0) to trigger the buffer + # overflow + sendp(Ether(dst=hw_dst) / IPv6(dst=ll_dst, src=ll_src) / + IPv6ExtHdrFragment(id=0xabcd, nh=0, m=1, offset=0) / + (b"A"*(128-8)), + iface=iface, verbose=0) + # the fragments should be discarded + pktbuf_empty(child) + + def test_ipv6_ext_frag_shell_test_0(child, s, iface, ll_dst): child.sendline("test {} 0".format(ll_dst)) data, _ = s.recvfrom(RECV_BUFSIZE) @@ -428,6 +461,8 @@ def testfunc(child): run(test_reass_successful_udp) run(test_reass_too_short_header) run(test_reass_offset_too_large) + run(test_reass_empty_fragment) + run(test_reass_first_fragment_repeat) print("SUCCESS")