vlib: address sanitizer support for stack switch, enable clang 99/27199/4
authorDamjan Marion <damarion@cisco.com>
Thu, 21 May 2020 14:47:05 +0000 (16:47 +0200)
committerBenoît Ganne <bganne@cisco.com>
Tue, 16 Jun 2020 16:05:01 +0000 (16:05 +0000)
Type: improvement
Change-Id: I81df4b61d1f0b8c1df77c1ee9bebcb491e155b69
Signed-off-by: Damjan Marion <damarion@cisco.com>
docs/troubleshooting/sanitizer.rst
src/CMakeLists.txt
src/vlib/main.c
src/vlib/main.h
src/vlib/node_funcs.h
src/vlib/threads.c
src/vlib/unix/main.c
src/vlib/unix/plugin.h

index 715f1b3..217f5e5 100644 (file)
@@ -6,7 +6,7 @@ Google Sanitizers
 
 VPP is instrumented to support `Google Sanitizers <https://github.com/google/sanitizers>`_.
 As of today, only `AddressSanitizer <https://github.com/google/sanitizers/wiki/AddressSanitizer>`_
-is supported, only for GCC and only for the heap.
+is supported, both for GCC and clang.
 
 AddressSanitizer
 ================
@@ -20,19 +20,19 @@ build option, so all VPP targets should be supported. For example:
 .. code-block:: console
 
     # build a debug image with ASan support:
-    $ make rebuild VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON CC=gcc-8
+    $ make rebuild VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON
     ....
 
     # build a release image with ASan support:
-    $ make rebuild-release VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON CC=gcc-8
+    $ make rebuild-release VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON
     ....
 
     # build packages in debug mode with ASan support:
-    $ make pkg-deb-debug VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON CC=gcc-8
+    $ make pkg-deb-debug VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON
     ....
 
     # run GBP plugin tests in debug mode with ASan
-    $ make test-debug TEST=test_gbp VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON CC=gcc-8
+    $ make test-debug TEST=test_gbp VPP_EXTRA_CMAKE_ARGS=-DVPP_ENABLE_SANITIZE_ADDR=ON
     ....
 
 Once VPP has been built with ASan support you can use it as usual including
index 133876c..499a39f 100644 (file)
@@ -117,7 +117,7 @@ set(VPP_SANITIZE_ADDR_OPTIONS
 )
 
 if (VPP_ENABLE_SANITIZE_ADDR)
-  set(CMAKE_C_FLAGS "-fsanitize=address --param asan-stack=0 -DCLIB_SANITIZE_ADDR ${CMAKE_C_FLAGS}")
+  set(CMAKE_C_FLAGS "-fsanitize=address -DCLIB_SANITIZE_ADDR ${CMAKE_C_FLAGS}")
   set(CMAKE_EXE_LINKER_FLAGS "-fsanitize=address ${CMAKE_EXE_LINKER_FLAGS}")
   set(CMAKE_SHARED_LINKER_FLAGS "-fsanitize=address ${CMAKE_SHARED_LINKER_FLAGS}")
 endif (VPP_ENABLE_SANITIZE_ADDR)
index 2e100b2..2c397a2 100644 (file)
@@ -1496,6 +1496,8 @@ vlib_process_bootstrap (uword _a)
 
   vm = a->vm;
   p = a->process;
+  vlib_process_finish_switch_stack (vm);
+
   f = a->frame;
   node = &p->node_runtime;
 
@@ -1503,6 +1505,7 @@ vlib_process_bootstrap (uword _a)
 
   ASSERT (vlib_process_stack_is_valid (p));
 
+  vlib_process_start_switch_stack (vm, 0);
   clib_longjmp (&p->return_longjmp, n);
 
   return n;
@@ -1521,14 +1524,19 @@ vlib_process_startup (vlib_main_t * vm, vlib_process_t * p, vlib_frame_t * f)
 
   r = clib_setjmp (&p->return_longjmp, VLIB_PROCESS_RETURN_LONGJMP_RETURN);
   if (r == VLIB_PROCESS_RETURN_LONGJMP_RETURN)
-    r = clib_calljmp (vlib_process_bootstrap, pointer_to_uword (&a),
-                     (void *) p->stack + (1 << p->log2_n_stack_bytes));
+    {
+      vlib_process_start_switch_stack (vm, p);
+      r = clib_calljmp (vlib_process_bootstrap, pointer_to_uword (&a),
+                       (void *) p->stack + (1 << p->log2_n_stack_bytes));
+    }
+  else
+    vlib_process_finish_switch_stack (vm);
 
   return r;
 }
 
 static_always_inline uword
-vlib_process_resume (vlib_process_t * p)
+vlib_process_resume (vlib_main_t * vm, vlib_process_t * p)
 {
   uword r;
   p->flags &= ~(VLIB_PROCESS_IS_SUSPENDED_WAITING_FOR_CLOCK
@@ -1536,7 +1544,12 @@ vlib_process_resume (vlib_process_t * p)
                | VLIB_PROCESS_RESUME_PENDING);
   r = clib_setjmp (&p->return_longjmp, VLIB_PROCESS_RETURN_LONGJMP_RETURN);
   if (r == VLIB_PROCESS_RETURN_LONGJMP_RETURN)
-    clib_longjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_RESUME);
+    {
+      vlib_process_start_switch_stack (vm, p);
+      clib_longjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_RESUME);
+    }
+  else
+    vlib_process_finish_switch_stack (vm);
   return r;
 }
 
@@ -1655,7 +1668,7 @@ dispatch_suspended_process (vlib_main_t * vm,
   /* Save away current process for suspend. */
   nm->current_process_index = node->runtime_index;
 
-  n_vectors = vlib_process_resume (p);
+  n_vectors = vlib_process_resume (vm, p);
   t = clib_cpu_time_now ();
 
   nm->current_process_index = ~0;
index d6b2d1f..2e070aa 100644 (file)
@@ -280,6 +280,10 @@ typedef struct vlib_main_t
   u32 buffer_alloc_success_seed;
   f64 buffer_alloc_success_rate;
 
+#ifdef CLIB_SANITIZE_ADDR
+  /* address sanitizer stack save */
+  void *asan_stack_save;
+#endif
 } vlib_main_t;
 
 /* Global main structure. */
index 263017d..b607ef2 100644 (file)
 #include <vppinfra/fifo.h>
 #include <vppinfra/tw_timer_1t_3w_1024sl_ov.h>
 
+#ifdef CLIB_SANITIZE_ADDR
+#include <sanitizer/asan_interface.h>
+#endif
+
+static_always_inline void
+vlib_process_start_switch_stack (vlib_main_t * vm, vlib_process_t * p)
+{
+#ifdef CLIB_SANITIZE_ADDR
+  void *stack = p ? (void *) p->stack : vlib_thread_stacks[vm->thread_index];
+  u32 stack_bytes = p ? p->log2_n_stack_bytes : VLIB_THREAD_STACK_SIZE;
+  __sanitizer_start_switch_fiber (&vm->asan_stack_save, stack, stack_bytes);
+#endif
+}
+
+static_always_inline void
+vlib_process_finish_switch_stack (vlib_main_t * vm)
+{
+#ifdef CLIB_SANITIZE_ADDR
+  const void *bottom_old;
+  size_t size_old;
+
+  __sanitizer_finish_switch_fiber (&vm->asan_stack_save, &bottom_old,
+                                  &size_old);
+#endif
+}
+
 /** \brief Get vlib node by index.
  @warning This function will ASSERT if @c i is out of range.
  @param vm vlib_main_t pointer, varies by thread
@@ -456,8 +482,11 @@ vlib_process_suspend (vlib_main_t * vm, f64 dt)
     {
       /* expiration time in 10us ticks */
       p->resume_clock_interval = dt * 1e5;
+      vlib_process_start_switch_stack (vm, 0);
       clib_longjmp (&p->return_longjmp, VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
     }
+  else
+    vlib_process_finish_switch_stack (vm);
 
   return r;
 }
@@ -625,8 +654,13 @@ vlib_process_wait_for_event (vlib_main_t * vm)
       r =
        clib_setjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_SUSPEND);
       if (r == VLIB_PROCESS_RESUME_LONGJMP_SUSPEND)
-       clib_longjmp (&p->return_longjmp,
-                     VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
+       {
+         vlib_process_start_switch_stack (vm, 0);
+         clib_longjmp (&p->return_longjmp,
+                       VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
+       }
+      else
+       vlib_process_finish_switch_stack (vm);
     }
 
   return p->non_empty_event_type_bitmap;
@@ -649,8 +683,13 @@ vlib_process_wait_for_one_time_event (vlib_main_t * vm,
       r =
        clib_setjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_SUSPEND);
       if (r == VLIB_PROCESS_RESUME_LONGJMP_SUSPEND)
-       clib_longjmp (&p->return_longjmp,
-                     VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
+       {
+         vlib_process_start_switch_stack (vm, 0);
+         clib_longjmp (&p->return_longjmp,
+                       VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
+       }
+      else
+       vlib_process_finish_switch_stack (vm);
     }
 
   return vlib_process_get_events_helper (p, with_type_index, data_vector);
@@ -673,8 +712,13 @@ vlib_process_wait_for_event_with_type (vlib_main_t * vm,
       r =
        clib_setjmp (&p->resume_longjmp, VLIB_PROCESS_RESUME_LONGJMP_SUSPEND);
       if (r == VLIB_PROCESS_RESUME_LONGJMP_SUSPEND)
-       clib_longjmp (&p->return_longjmp,
-                     VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
+       {
+         vlib_process_start_switch_stack (vm, 0);
+         clib_longjmp (&p->return_longjmp,
+                       VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
+       }
+      else
+       vlib_process_finish_switch_stack (vm);
 
       /* See if unknown event type has been signaled now. */
       if (!h)
@@ -715,8 +759,11 @@ vlib_process_wait_for_event_or_clock (vlib_main_t * vm, f64 dt)
   if (r == VLIB_PROCESS_RESUME_LONGJMP_SUSPEND)
     {
       p->resume_clock_interval = dt * 1e5;
+      vlib_process_start_switch_stack (vm, 0);
       clib_longjmp (&p->return_longjmp, VLIB_PROCESS_RETURN_LONGJMP_SUSPEND);
     }
+  else
+    vlib_process_finish_switch_stack (vm);
 
   /* Return amount of time still left to sleep.
      If <= 0 then we've been waken up by the clock (and not an event). */
index 2f141f1..a8c1a1a 100644 (file)
@@ -581,6 +581,7 @@ vlib_worker_thread_bootstrap_fn (void *arg)
 
   __os_thread_index = w - vlib_worker_threads;
 
+  vlib_process_start_switch_stack (vlib_mains[__os_thread_index], 0);
   rv = (void *) clib_calljmp
     ((uword (*)(uword)) w->thread_function,
      (uword) arg, w->thread_stack + VLIB_THREAD_STACK_SIZE);
@@ -1777,6 +1778,8 @@ vlib_worker_thread_fn (void *arg)
   vlib_main_t *vm = vlib_get_main ();
   clib_error_t *e;
 
+  vlib_process_finish_switch_stack (vm);
+
   ASSERT (vm->thread_index == vlib_get_thread_index ());
 
   vlib_worker_thread_init (w);
index 0f9068c..568876b 100644 (file)
@@ -654,6 +654,8 @@ thread0 (uword arg)
   unformat_input_t input;
   int i;
 
+  vlib_process_finish_switch_stack (vm);
+
   unformat_init_command_line (&input, (char **) vm->argv);
   i = vlib_main (vm, &input);
   unformat_free (&input);
@@ -727,6 +729,7 @@ vlib_unix_main (int argc, char *argv[])
   __os_thread_index = 0;
   vm->thread_index = 0;
 
+  vlib_process_start_switch_stack (vm, 0);
   i = clib_calljmp (thread0, (uword) vm,
                    (void *) (vlib_thread_stacks[0] +
                              VLIB_THREAD_STACK_SIZE));
index 30039c5..a52c57b 100644 (file)
@@ -122,6 +122,7 @@ u8 *vlib_get_vat_plugin_path (void);
 
 #define VLIB_PLUGIN_REGISTER() \
   vlib_plugin_registration_t vlib_plugin_registration \
+  CLIB_NOSANITIZE_ADDR \
   __attribute__((__section__(".vlib_plugin_registration")))
 
 /* Call a plugin init function: used for init function dependencies. */