vppinfra: fix vec_prepend use-after-free 48/40148/6
authorDmitry Valter <d-valter@yandex-team.com>
Fri, 5 Jan 2024 14:28:08 +0000 (14:28 +0000)
committerDamjan Marion <dmarion@0xa5.net>
Fri, 19 Jan 2024 12:37:49 +0000 (12:37 +0000)
Don't access free'd memory in vec_prepend.
Don't allow prepend when v1 == v2 as it also causes a use-after-free.
Found via ASAN.

Type: fix
Signed-off-by: Dmitry Valter <d-valter@yandex-team.com>
Change-Id: I21f8422c007d07d40d237e873b84c042be1fe8e8

src/vppinfra/vec.h

index 607fc28..1a64a69 100644 (file)
@@ -1067,26 +1067,28 @@ _vec_append (void **v1p, void *v2, uword v1_elt_sz, uword v2_elt_sz,
 #define vec_append(v1, v2) vec_append_aligned (v1, v2, 0)
 
 static_always_inline void
-_vec_prepend (void **v1p, void *v2, uword v1_elt_sz, uword v2_elt_sz,
-             uword align)
+_vec_prepend (void *restrict *v1p, void *restrict v2, uword v1_elt_sz,
+             uword v2_elt_sz, uword align)
 {
-  void *v1 = v1p[0];
+  void *restrict v1 = v1p[0];
   uword len1 = vec_len (v1);
   uword len2 = vec_len (v2);
 
   if (PREDICT_TRUE (len2 > 0))
     {
+      /* prepending vector to itself would result in use-after-free */
+      ASSERT (v1 != v2);
       const vec_attr_t va = { .elt_sz = v2_elt_sz, .align = align };
       v1 = _vec_resize_internal (v1, len1 + len2, &va);
-      clib_memmove (v1 + len2 * v2_elt_sz, v1p[0], len1 * v1_elt_sz);
+      clib_memmove (v1 + len2 * v2_elt_sz, v1, len1 * v1_elt_sz);
       clib_memcpy_fast (v1, v2, len2 * v2_elt_sz);
-      _vec_update_pointer (v1p, v1);
+      _vec_update_pointer ((void **) v1p, v1);
     }
 }
 
 /** \brief Prepend v2 before v1. Result in v1. Specified alignment
     @param V1 target vector
-    @param V2 vector to prepend
+    @param V2 vector to prepend, V1 != V2
     @param align required alignment
 */
 
@@ -1096,7 +1098,7 @@ _vec_prepend (void **v1p, void *v2, uword v1_elt_sz, uword v2_elt_sz,
 
 /** \brief Prepend v2 before v1. Result in v1.
     @param V1 target vector
-    @param V2 vector to prepend
+    @param V2 vector to prepend, V1 != V2
 */
 
 #define vec_prepend(v1, v2) vec_prepend_aligned (v1, v2, 0)