Fix buffer overflow when fragmenting packets (VPP-1383) 45/15445/2
authorJuraj Sloboda <jsloboda@cisco.com>
Tue, 16 Oct 2018 10:18:21 +0000 (12:18 +0200)
committerDamjan Marion <dmarion@me.com>
Mon, 22 Oct 2018 12:34:49 +0000 (12:34 +0000)
Change-Id: Idcda9ae55fa2efb0b2e928bac3e8e86ff8d19eba
Signed-off-by: Juraj Sloboda <jsloboda@cisco.com>
src/vnet/ip/ip_frag.c
test/test_ip4.py

index 628d9d6..8de4dfc 100644 (file)
@@ -101,7 +101,8 @@ ip4_frag_do_fragment (vlib_main_t * vm, u32 from_bi, u32 ** buffer,
   ip4 = (ip4_header_t *) vlib_buffer_get_current (from_b);
 
   rem = clib_net_to_host_u16 (ip4->length) - sizeof (ip4_header_t);
-  max = (mtu - sizeof (ip4_header_t)) & ~0x7;
+  max =
+    (clib_min (mtu, VLIB_BUFFER_DATA_SIZE) - sizeof (ip4_header_t)) & ~0x7;
 
   if (rem >
       (vlib_buffer_length_in_chain (vm, from_b) - sizeof (ip4_header_t)))
@@ -152,7 +153,7 @@ ip4_frag_do_fragment (vlib_main_t * vm, u32 from_bi, u32 ** buffer,
       ip4_header_t *to_ip4;
       u8 *to_data;
 
-      len = (rem > (mtu - sizeof (ip4_header_t)) ? max : rem);
+      len = (rem > max ? max : rem);
       if (len != rem)          /* Last fragment does not need to divisible by 8 */
        len &= ~0x7;
       if ((to_b = frag_buffer_alloc (org_from_b, &to_bi)) == 0)
index e9ec71a..ca461f1 100644 (file)
@@ -1554,5 +1554,55 @@ class TestIPLPM(VppTestCase):
         rx = self.send_and_expect(self.pg0, p_24 * 65, self.pg1)
 
 
+class TestIPv4Frag(VppTestCase):
+    """ IPv4 fragmentation """
+
+    @classmethod
+    def setUpClass(cls):
+        super(TestIPv4Frag, cls).setUpClass()
+
+        cls.create_pg_interfaces([0, 1])
+        cls.src_if = cls.pg0
+        cls.dst_if = cls.pg1
+
+        # setup all interfaces
+        for i in cls.pg_interfaces:
+            i.admin_up()
+            i.config_ip4()
+            i.resolve_arp()
+
+    def test_frag_large_packets(self):
+        """ Fragmentation of large packets """
+
+        p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
+             IP(src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4) /
+             UDP(sport=1234, dport=5678) / Raw())
+        self.extend_packet(p, 6000, "abcde")
+        saved_payload = p[Raw].load
+
+        # Force fragmentation by setting MTU of output interface
+        # lower than packet size
+        self.vapi.sw_interface_set_mtu(self.dst_if.sw_if_index,
+                                       [5000, 0, 0, 0])
+
+        self.pg_enable_capture()
+        self.src_if.add_stream(p)
+        self.pg_start()
+
+        # Expecting 3 fragments because size of created fragments currently
+        # cannot be larger then VPP buffer size (which is 2048)
+        packets = self.dst_if.get_capture(3)
+
+        # Assume VPP sends the fragments in order
+        payload = ''
+        for p in packets:
+            payload_offset = p.frag * 8
+            if payload_offset > 0:
+                payload_offset -= 8  # UDP header is not in payload
+            self.assert_equal(payload_offset, len(payload))
+            payload += p[Raw].load
+        self.assert_equal(payload, saved_payload, "payload")
+
+
 if __name__ == '__main__':
     unittest.main(testRunner=VppTestRunner)