buffers: fix crash 25/19925/13
authorKlement Sekera <ksekera@cisco.com>
Tue, 4 Jun 2019 19:14:26 +0000 (21:14 +0200)
committerDamjan Marion <dmarion@me.com>
Thu, 20 Jun 2019 03:36:54 +0000 (03:36 +0000)
this change is being made to fix a crash when current_data < 0 in buffer
linearization function

Ticket: N/A
Type: fix
Fixes: f883f6a1132ad4bb7aa9d9a79d420274fbcf3b64

Change-Id: Ia4ede823f673780e0c30d075b091db42e183650d
Signed-off-by: Klement Sekera <ksekera@cisco.com>
src/plugins/unittest/CMakeLists.txt
src/plugins/unittest/test_buffer.c [new file with mode: 0644]
src/vlib/buffer_funcs.h
test/test_buffers.py [new file with mode: 0644]

index 5b7e1f7..3e0e550 100644 (file)
@@ -36,4 +36,5 @@ add_vpp_plugin(unittest
   svm_fifo_test.c
   unittest.c
   util_test.c
+  test_buffer.c
 )
diff --git a/src/plugins/unittest/test_buffer.c b/src/plugins/unittest/test_buffer.c
new file mode 100644 (file)
index 0000000..e5a5643
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2019 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vlib/vlib.h>
+#include <vlib/buffer_funcs.h>
+
+#define TEST_I(_cond, _comment, _args...)                      \
+({                                                             \
+  int _evald = (_cond);                                                \
+  if (!(_evald)) {                                             \
+    fformat(stderr, "FAIL:%d: " _comment "\n",                 \
+           __LINE__, ##_args);                                 \
+  } else {                                                     \
+    fformat(stderr, "PASS:%d: " _comment "\n",                 \
+           __LINE__, ##_args);                                 \
+  }                                                            \
+  _evald;                                                      \
+})
+
+#define TEST(_cond, _comment, _args...)                        \
+{                                                              \
+    if (!TEST_I(_cond, _comment, ##_args)) {           \
+       return 1;                                               \
+    }                                                          \
+}
+
+/* test function for a specific case where current_data is negative, verify
+ * that there is no crash */
+static int
+linearize_negative_current_data (vlib_main_t * vm)
+{
+  u32 bi[32];
+  TEST (ARRAY_LEN (bi) == vlib_buffer_alloc (vm, bi, ARRAY_LEN (bi)),
+       "buff alloc");
+  u32 data_size = vlib_buffer_get_default_data_size (vm);
+  u32 i;
+  for (i = 0; i < ARRAY_LEN (bi) - 1; ++i)
+    {
+      vlib_buffer_t *b = vlib_get_buffer (vm, bi[i]);
+      b->next_buffer = bi[i + 1];
+      b->flags |= VLIB_BUFFER_NEXT_PRESENT;
+      b->current_data = -14;
+      b->current_length = 14 + data_size;
+    }
+
+  vlib_buffer_chain_linearize (vm, vlib_get_buffer (vm, bi[0]));
+
+  return 0;
+}
+
+static clib_error_t *
+test_linearize_fn (vlib_main_t * vm, unformat_input_t * input,
+                  vlib_cli_command_t * cmd)
+{
+
+  if (linearize_negative_current_data (vm))
+    {
+      return clib_error_return (0, "linearize_negative_current_data failed");
+    }
+
+  return (NULL);
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (test_linearize_command, static) =
+{
+  .path = "test chained-buffer-linearization",
+  .short_help = "test chained-buffer-linearization",
+  .function = test_linearize_fn,
+};
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
index 521a036..8091d83 100644 (file)
@@ -1416,13 +1416,19 @@ vlib_buffer_chain_linearize (vlib_main_t * vm, vlib_buffer_t * b)
 
       if (dst_left == 0)
        {
-         if (db != first)
-           db->current_data = 0;
          db->current_length = dp - (u8 *) vlib_buffer_get_current (db);
          ASSERT (db->flags & VLIB_BUFFER_NEXT_PRESENT);
          db = vlib_get_buffer (vm, db->next_buffer);
          dst_left = data_size;
-         dp = db->data;
+         if (db->current_data > 0)
+           {
+             db->current_data = 0;
+           }
+         else
+           {
+             dst_left += -db->current_data;
+           }
+         dp = vlib_buffer_get_current (db);
        }
 
       while (src_left == 0)
diff --git a/test/test_buffers.py b/test/test_buffers.py
new file mode 100644 (file)
index 0000000..fe92378
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/env python
+
+from framework import VppTestCase
+
+
+class TestBuffers(VppTestCase):
+    """ Buffer C Unit Tests """
+
+    @classmethod
+    def setUpClass(cls):
+        super(TestBuffers, cls).setUpClass()
+
+    @classmethod
+    def tearDownClass(cls):
+        super(TestBuffers, cls).tearDownClass()
+
+    def setUp(self):
+        super(TestBuffers, self).setUp()
+
+    def tearDown(self):
+        super(TestBuffers, self).tearDown()
+
+    def test_linearize(self):
+        """ Chained Buffer Linearization """
+        error = self.vapi.cli("test chained-buffer-linearization")
+
+        if error:
+            self.logger.critical(error)
+            self.assertNotIn('failed', error)