vlib: crash in linux_epoll_input_inline for accessing free file index [VPP-1412] 41/14741/2
authorSteven <sluong@cisco.com>
Sat, 8 Sep 2018 21:06:16 +0000 (14:06 -0700)
committerDamjan Marion <dmarion@me.com>
Sun, 9 Sep 2018 20:26:40 +0000 (20:26 +0000)
Under rare scenario, epoll may still post an event to VPP although the file
descriptor is already deleted via epoll_ctl (EPOLL_CTL_DEL) and the file
descriptor is close. VPP tries to access the free file index entry and crash.

The fix is to throw away the events which the file descriptor is already deleted.

Change-Id: Ieca3a1873aecb28630c3abc42c40341f27c2faa7
Signed-off-by: Steven <sluong@cisco.com>
(cherry picked from commit aec7297ba012e1fe4bbf85cdaec8e810aa476cea)

src/vlib/unix/input.c

index 0a61c05..8be0770 100644 (file)
@@ -247,11 +247,40 @@ linux_epoll_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
   for (e = em->epoll_events; e < em->epoll_events + n_fds_ready; e++)
     {
       u32 i = e->data.u32;
-      clib_file_t *f = pool_elt_at_index (fm->file_pool, i);
+      clib_file_t *f = fm->file_pool + i;
       clib_error_t *errors[4];
       int n_errors = 0;
 
-      if (PREDICT_TRUE (!(e->events & EPOLLERR)))
+      if (PREDICT_FALSE (pool_is_free (fm->file_pool, f)))
+       {
+         /*
+          * Under rare scenerop, epoll may still post us events for the
+          * deleted file descriptor. We just deal with it and throw away the
+          * events for the corresponding file descriptor.
+          */
+         if (e->events & EPOLLIN)
+           {
+             errors[n_errors] =
+               clib_error_return (0, "epoll event EPOLLIN dropped due "
+                                  "to free index %u", i);
+             n_errors++;
+           }
+         if (e->events & EPOLLOUT)
+           {
+             errors[n_errors] =
+               clib_error_return (0, "epoll event EPOLLOUT dropped due "
+                                  "to free index %u", i);
+             n_errors++;
+           }
+         if (e->events & EPOLLERR)
+           {
+             errors[n_errors] =
+               clib_error_return (0, "epoll event EPOLLERR dropped due "
+                                  "to free index %u", i);
+             n_errors++;
+           }
+       }
+      else if (PREDICT_TRUE (!(e->events & EPOLLERR)))
        {
          if (e->events & EPOLLIN)
            {