The reassembled total length of a packet must not exceed 65535.
A fragment with a high offset could drive the sum past that,
causing silent truncation since IP payload_len/total_length is 16 bits.

When reassembling a packet the total length should not be allowed
to exceed 65535. A fragment with high offset could drive the sum
past that, causing silent truncation.

A valid datagram never exceeds 65535 bytes, so reject any fragment
whose resulting length would exceed that.
Fold the test into the existing zero-length check.

Fixes: cc8f4d020c0b ("examples/ip_reassembly: initial import")
Cc: [email protected]

Signed-off-by: Stephen Hemminger <[email protected]>
---
 lib/ip_frag/rte_ipv4_reassembly.c | 9 +++++++--
 lib/ip_frag/rte_ipv6_reassembly.c | 9 +++++++--
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/lib/ip_frag/rte_ipv4_reassembly.c 
b/lib/ip_frag/rte_ipv4_reassembly.c
index 980f7a3b77..727fc58243 100644
--- a/lib/ip_frag/rte_ipv4_reassembly.c
+++ b/lib/ip_frag/rte_ipv4_reassembly.c
@@ -136,8 +136,13 @@ rte_ipv4_frag_reassemble_packet(struct rte_ip_frag_tbl 
*tbl,
                tbl, tbl->max_cycles, tbl->entry_mask, tbl->max_entries,
                tbl->use_entries);
 
-       /* check that fragment length is greater then zero. */
-       if (ip_len <= 0) {
+       /*
+        * Drop fragments with no payload, and any fragment whose end would
+        * make the reassembled datagram exceed the maximum IPv4 size. The
+        * total_length field is 16 bits, so otherwise it is silently
+        * truncated while the mbuf still holds the full length.
+        */
+       if (ip_len <= 0 || ip_ofs + ip_len + mb->l3_len > UINT16_MAX) {
                IP_FRAG_MBUF2DR(dr, mb);
                return NULL;
        }
diff --git a/lib/ip_frag/rte_ipv6_reassembly.c 
b/lib/ip_frag/rte_ipv6_reassembly.c
index 7c1659002b..0b44275b37 100644
--- a/lib/ip_frag/rte_ipv6_reassembly.c
+++ b/lib/ip_frag/rte_ipv6_reassembly.c
@@ -174,8 +174,13 @@ rte_ipv6_frag_reassemble_packet(struct rte_ip_frag_tbl 
*tbl,
                tbl, tbl->max_cycles, tbl->entry_mask, tbl->max_entries,
                tbl->use_entries);
 
-       /* check that fragment length is greater then zero. */
-       if (ip_len <= 0) {
+       /*
+        * Drop fragments with no payload, and any fragment whose end would
+        * make the reassembled payload exceed 65535 bytes. The payload_len
+        * field is 16 bits, so otherwise it is silently truncated while the
+        * mbuf still holds the full length.
+        */
+       if (ip_len <= 0 || ip_ofs + ip_len > UINT16_MAX) {
                IP_FRAG_MBUF2DR(dr, mb);
                return NULL;
        }
-- 
2.53.0

Reply via email to