LCOV - code coverage report
Current view: top level - lib/tevent - tevent_wrapper.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 136 239 56.9 %
Date: 2021-09-23 10:06:22 Functions: 11 16 68.8 %

          Line data    Source code
       1             : /*
       2             :    Infrastructure for event context wrappers
       3             : 
       4             :    Copyright (C) Stefan Metzmacher 2014
       5             : 
       6             :      ** NOTE! The following LGPL license applies to the tevent
       7             :      ** library. This does NOT imply that all of Samba is released
       8             :      ** under the LGPL
       9             : 
      10             :    This library is free software; you can redistribute it and/or
      11             :    modify it under the terms of the GNU Lesser General Public
      12             :    License as published by the Free Software Foundation; either
      13             :    version 3 of the License, or (at your option) any later version.
      14             : 
      15             :    This library is distributed in the hope that it will be useful,
      16             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      18             :    Lesser General Public License for more details.
      19             : 
      20             :    You should have received a copy of the GNU Lesser General Public
      21             :    License along with this library; if not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "replace.h"
      25             : #ifdef HAVE_PTHREAD
      26             : #include "system/threads.h"
      27             : #endif
      28             : #define TEVENT_DEPRECATED 1
      29             : #include "tevent.h"
      30             : #include "tevent_internal.h"
      31             : #include "tevent_util.h"
      32             : 
      33           0 : static int tevent_wrapper_glue_context_init(struct tevent_context *ev)
      34             : {
      35           0 :         tevent_abort(ev, "tevent_wrapper_glue_context_init() called");
      36           0 :         errno = ENOSYS;
      37           0 :         return -1;
      38             : }
      39             : 
      40           8 : static struct tevent_fd *tevent_wrapper_glue_add_fd(struct tevent_context *ev,
      41             :                                                     TALLOC_CTX *mem_ctx,
      42             :                                                     int fd, uint16_t flags,
      43             :                                                     tevent_fd_handler_t handler,
      44             :                                                     void *private_data,
      45             :                                                     const char *handler_name,
      46             :                                                     const char *location)
      47             : {
      48           8 :         struct tevent_wrapper_glue *glue = ev->wrapper.glue;
      49           8 :         struct tevent_fd *fde = NULL;
      50             : 
      51           8 :         if (glue->destroyed) {
      52           0 :                 tevent_abort(ev, "add_fd wrapper use after free");
      53           0 :                 return NULL;
      54             :         }
      55             : 
      56           8 :         if (glue->main_ev == NULL) {
      57           0 :                 errno = EINVAL;
      58           0 :                 return NULL;
      59             :         }
      60             : 
      61           8 :         fde = _tevent_add_fd(glue->main_ev, mem_ctx, fd, flags,
      62             :                              handler, private_data,
      63             :                              handler_name, location);
      64           8 :         if (fde == NULL) {
      65           0 :                 return NULL;
      66             :         }
      67             : 
      68           8 :         fde->wrapper = glue;
      69             : 
      70           8 :         return fde;
      71             : }
      72             : 
      73           8 : static struct tevent_timer *tevent_wrapper_glue_add_timer(struct tevent_context *ev,
      74             :                                                           TALLOC_CTX *mem_ctx,
      75             :                                                           struct timeval next_event,
      76             :                                                           tevent_timer_handler_t handler,
      77             :                                                           void *private_data,
      78             :                                                           const char *handler_name,
      79             :                                                           const char *location)
      80             : {
      81           8 :         struct tevent_wrapper_glue *glue = ev->wrapper.glue;
      82           8 :         struct tevent_timer *te = NULL;
      83             : 
      84           8 :         if (glue->destroyed) {
      85           0 :                 tevent_abort(ev, "add_timer wrapper use after free");
      86           0 :                 return NULL;
      87             :         }
      88             : 
      89           8 :         if (glue->main_ev == NULL) {
      90           0 :                 errno = EINVAL;
      91           0 :                 return NULL;
      92             :         }
      93             : 
      94           8 :         te = _tevent_add_timer(glue->main_ev, mem_ctx, next_event,
      95             :                                handler, private_data,
      96             :                                handler_name, location);
      97           8 :         if (te == NULL) {
      98           0 :                 return NULL;
      99             :         }
     100             : 
     101           8 :         te->wrapper = glue;
     102             : 
     103           8 :         return te;
     104             : }
     105             : 
     106           8 : static void tevent_wrapper_glue_schedule_immediate(struct tevent_immediate *im,
     107             :                                                    struct tevent_context *ev,
     108             :                                                    tevent_immediate_handler_t handler,
     109             :                                                    void *private_data,
     110             :                                                    const char *handler_name,
     111             :                                                    const char *location)
     112             : {
     113           8 :         struct tevent_wrapper_glue *glue = ev->wrapper.glue;
     114             : 
     115           8 :         if (glue->destroyed) {
     116           0 :                 tevent_abort(ev, "scheduke_immediate wrapper use after free");
     117           0 :                 return;
     118             :         }
     119             : 
     120           8 :         if (glue->main_ev == NULL) {
     121           0 :                 tevent_abort(ev, location);
     122           0 :                 errno = EINVAL;
     123           0 :                 return;
     124             :         }
     125             : 
     126           8 :         _tevent_schedule_immediate(im, glue->main_ev,
     127             :                                    handler, private_data,
     128             :                                    handler_name, location);
     129             : 
     130           8 :         im->wrapper = glue;
     131             : 
     132           8 :         return;
     133             : }
     134             : 
     135           8 : static struct tevent_signal *tevent_wrapper_glue_add_signal(struct tevent_context *ev,
     136             :                                                             TALLOC_CTX *mem_ctx,
     137             :                                                             int signum, int sa_flags,
     138             :                                                             tevent_signal_handler_t handler,
     139             :                                                             void *private_data,
     140             :                                                             const char *handler_name,
     141             :                                                             const char *location)
     142             : {
     143           8 :         struct tevent_wrapper_glue *glue = ev->wrapper.glue;
     144           8 :         struct tevent_signal *se = NULL;
     145             : 
     146           8 :         if (glue->destroyed) {
     147           0 :                 tevent_abort(ev, "add_signal wrapper use after free");
     148           0 :                 return NULL;
     149             :         }
     150             : 
     151           8 :         if (glue->main_ev == NULL) {
     152           0 :                 errno = EINVAL;
     153           0 :                 return NULL;
     154             :         }
     155             : 
     156           8 :         se = _tevent_add_signal(glue->main_ev, mem_ctx,
     157             :                                 signum, sa_flags,
     158             :                                 handler, private_data,
     159             :                                 handler_name, location);
     160           8 :         if (se == NULL) {
     161           0 :                 return NULL;
     162             :         }
     163             : 
     164           8 :         se->wrapper = glue;
     165             : 
     166           8 :         return se;
     167             : }
     168             : 
     169           0 : static int tevent_wrapper_glue_loop_once(struct tevent_context *ev, const char *location)
     170             : {
     171           0 :         tevent_abort(ev, "tevent_wrapper_glue_loop_once() called");
     172           0 :         errno = ENOSYS;
     173           0 :         return -1;
     174             : }
     175             : 
     176           0 : static int tevent_wrapper_glue_loop_wait(struct tevent_context *ev, const char *location)
     177             : {
     178           0 :         tevent_abort(ev, "tevent_wrapper_glue_loop_wait() called");
     179           0 :         errno = ENOSYS;
     180           0 :         return -1;
     181             : }
     182             : 
     183             : static const struct tevent_ops tevent_wrapper_glue_ops = {
     184             :         .context_init           = tevent_wrapper_glue_context_init,
     185             :         .add_fd                 = tevent_wrapper_glue_add_fd,
     186             :         .set_fd_close_fn        = tevent_common_fd_set_close_fn,
     187             :         .get_fd_flags           = tevent_common_fd_get_flags,
     188             :         .set_fd_flags           = tevent_common_fd_set_flags,
     189             :         .add_timer              = tevent_wrapper_glue_add_timer,
     190             :         .schedule_immediate     = tevent_wrapper_glue_schedule_immediate,
     191             :         .add_signal             = tevent_wrapper_glue_add_signal,
     192             :         .loop_once              = tevent_wrapper_glue_loop_once,
     193             :         .loop_wait              = tevent_wrapper_glue_loop_wait,
     194             : };
     195             : 
     196          12 : static int tevent_wrapper_context_destructor(struct tevent_context *wrap_ev)
     197             : {
     198          12 :         struct tevent_wrapper_glue *glue = wrap_ev->wrapper.glue;
     199          12 :         struct tevent_context *main_ev = NULL;
     200          12 :         struct tevent_fd *fd = NULL, *fn = NULL;
     201          12 :         struct tevent_timer *te = NULL, *tn = NULL;
     202          12 :         struct tevent_immediate *ie = NULL, *in = NULL;
     203          12 :         struct tevent_signal *se = NULL, *sn = NULL;
     204             : #ifdef HAVE_PTHREAD
     205          12 :         struct tevent_threaded_context *tctx = NULL, *tctxn = NULL;
     206             : #endif
     207             : 
     208          12 :         if (glue == NULL) {
     209           0 :                 tevent_abort(wrap_ev,
     210             :                         "tevent_wrapper_context_destructor() active on main");
     211             :                 /* static checker support, return below is never reached */
     212           0 :                 return -1;
     213             :         }
     214             : 
     215          12 :         if (glue->destroyed && glue->busy) {
     216           0 :                 tevent_common_check_double_free(wrap_ev,
     217             :                         "tevent_context wrapper double free");
     218             :         }
     219          12 :         glue->destroyed = true;
     220             : 
     221          12 :         if (glue->busy) {
     222           0 :                 return -1;
     223             :         }
     224             : 
     225           8 :         main_ev = glue->main_ev;
     226           8 :         if (main_ev == NULL) {
     227           0 :                 return 0;
     228             :         }
     229             : 
     230           8 :         tevent_debug(wrap_ev, TEVENT_DEBUG_TRACE,
     231             :                      "Destroying wrapper context %p \"%s\"\n",
     232           8 :                      wrap_ev, talloc_get_name(glue->private_state));
     233             : 
     234           8 :         glue->main_ev = NULL;
     235           8 :         DLIST_REMOVE(main_ev->wrapper.list, glue);
     236             : 
     237             : #ifdef HAVE_PTHREAD
     238          16 :         for (tctx = main_ev->threaded_contexts; tctx != NULL; tctx = tctxn) {
     239             :                 int ret;
     240             : 
     241           0 :                 tctxn = tctx->next;
     242             : 
     243           0 :                 if (tctx->event_ctx != glue->wrap_ev) {
     244           0 :                         continue;
     245             :                 }
     246             : 
     247           0 :                 ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
     248           0 :                 if (ret != 0) {
     249           0 :                         abort();
     250             :                 }
     251             : 
     252             :                 /*
     253             :                  * Indicate to the thread that the tevent_context is
     254             :                  * gone. The counterpart of this is in
     255             :                  * _tevent_threaded_schedule_immediate, there we read
     256             :                  * this under the threaded_context's mutex.
     257             :                  */
     258             : 
     259           0 :                 tctx->event_ctx = NULL;
     260             : 
     261           0 :                 ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
     262           0 :                 if (ret != 0) {
     263           0 :                         abort();
     264             :                 }
     265             : 
     266           0 :                 DLIST_REMOVE(main_ev->threaded_contexts, tctx);
     267             :         }
     268             : #endif
     269             : 
     270          28 :         for (fd = main_ev->fd_events; fd; fd = fn) {
     271          12 :                 fn = fd->next;
     272             : 
     273          12 :                 if (fd->wrapper != glue) {
     274           8 :                         continue;
     275             :                 }
     276             : 
     277           4 :                 tevent_fd_set_flags(fd, 0);
     278             : 
     279           4 :                 fd->wrapper = NULL;
     280           4 :                 fd->event_ctx = NULL;
     281           4 :                 DLIST_REMOVE(main_ev->fd_events, fd);
     282             :         }
     283             : 
     284          20 :         for (te = main_ev->timer_events; te; te = tn) {
     285           4 :                 tn = te->next;
     286             : 
     287           4 :                 if (te->wrapper != glue) {
     288           0 :                         continue;
     289             :                 }
     290             : 
     291           4 :                 te->wrapper = NULL;
     292           4 :                 te->event_ctx = NULL;
     293             : 
     294           4 :                 if (main_ev->last_zero_timer == te) {
     295           0 :                         main_ev->last_zero_timer = DLIST_PREV(te);
     296             :                 }
     297           4 :                 DLIST_REMOVE(main_ev->timer_events, te);
     298             :         }
     299             : 
     300          20 :         for (ie = main_ev->immediate_events; ie; ie = in) {
     301           4 :                 in = ie->next;
     302             : 
     303           4 :                 if (ie->wrapper != glue) {
     304           0 :                         continue;
     305             :                 }
     306             : 
     307           4 :                 ie->wrapper = NULL;
     308           4 :                 ie->event_ctx = NULL;
     309           4 :                 ie->cancel_fn = NULL;
     310           4 :                 DLIST_REMOVE(main_ev->immediate_events, ie);
     311             :         }
     312             : 
     313          16 :         for (se = main_ev->signal_events; se; se = sn) {
     314           0 :                 sn = se->next;
     315             : 
     316           0 :                 if (se->wrapper != glue) {
     317           0 :                         continue;
     318             :                 }
     319             : 
     320           0 :                 se->wrapper = NULL;
     321           0 :                 tevent_cleanup_pending_signal_handlers(se);
     322             :         }
     323             : 
     324           0 :         return 0;
     325             : }
     326             : 
     327           8 : struct tevent_context *_tevent_context_wrapper_create(struct tevent_context *main_ev,
     328             :                                                 TALLOC_CTX *mem_ctx,
     329             :                                                 const struct tevent_wrapper_ops *ops,
     330             :                                                 void *pstate,
     331             :                                                 size_t psize,
     332             :                                                 const char *type,
     333             :                                                 const char *location)
     334             : {
     335           8 :         void **ppstate = (void **)pstate;
     336           8 :         struct tevent_context *ev = NULL;
     337             : 
     338           8 :         if (main_ev->wrapper.glue != NULL) {
     339             :                 /*
     340             :                  * stacking of wrappers is not supported
     341             :                  */
     342           0 :                 tevent_debug(main_ev->wrapper.glue->main_ev, TEVENT_DEBUG_FATAL,
     343             :                              "%s: %s() stacking not allowed\n",
     344             :                              __func__, location);
     345           0 :                 errno = EINVAL;
     346           0 :                 return NULL;
     347             :         }
     348             : 
     349           8 :         if (main_ev->nesting.allowed) {
     350             :                 /*
     351             :                  * wrappers conflict with nesting
     352             :                  */
     353           0 :                 tevent_debug(main_ev, TEVENT_DEBUG_FATAL,
     354             :                              "%s: %s() conflicts with nesting\n",
     355             :                              __func__, location);
     356           0 :                 errno = EINVAL;
     357           0 :                 return NULL;
     358             :         }
     359             : 
     360           8 :         ev = talloc_zero(mem_ctx, struct tevent_context);
     361           8 :         if (ev == NULL) {
     362           0 :                 return NULL;
     363             :         }
     364           8 :         ev->ops = &tevent_wrapper_glue_ops;
     365             : 
     366           8 :         ev->wrapper.glue = talloc_zero(ev, struct tevent_wrapper_glue);
     367           8 :         if (ev->wrapper.glue == NULL) {
     368           0 :                 talloc_free(ev);
     369           0 :                 return NULL;
     370             :         }
     371             : 
     372           8 :         talloc_set_destructor(ev, tevent_wrapper_context_destructor);
     373             : 
     374           8 :         ev->wrapper.glue->wrap_ev = ev;
     375           8 :         ev->wrapper.glue->main_ev = main_ev;
     376           8 :         ev->wrapper.glue->ops = ops;
     377           8 :         ev->wrapper.glue->private_state = talloc_zero_size(ev->wrapper.glue, psize);
     378           8 :         if (ev->wrapper.glue->private_state == NULL) {
     379           0 :                 talloc_free(ev);
     380           0 :                 return NULL;
     381             :         }
     382           8 :         talloc_set_name_const(ev->wrapper.glue->private_state, type);
     383             : 
     384           8 :         DLIST_ADD_END(main_ev->wrapper.list, ev->wrapper.glue);
     385             : 
     386           8 :         *ppstate = ev->wrapper.glue->private_state;
     387           8 :         return ev;
     388             : }
     389             : 
     390           0 : bool tevent_context_is_wrapper(struct tevent_context *ev)
     391             : {
     392           0 :         if (ev->wrapper.glue != NULL) {
     393           0 :                 return true;
     394             :         }
     395             : 
     396           0 :         return false;
     397             : }
     398             : 
     399             : _PRIVATE_
     400      216966 : struct tevent_context *tevent_wrapper_main_ev(struct tevent_context *ev)
     401             : {
     402      216966 :         if (ev == NULL) {
     403        1264 :                 return NULL;
     404             :         }
     405             : 
     406      215695 :         if (ev->wrapper.glue == NULL) {
     407      186438 :                 return ev;
     408             :         }
     409             : 
     410           8 :         return ev->wrapper.glue->main_ev;
     411             : }
     412             : 
     413             : /*
     414             :  * 32 stack elements should be more than enough
     415             :  *
     416             :  * e.g. Samba uses just 8 elements for [un]become_{root,user}()
     417             :  */
     418             : #define TEVENT_WRAPPER_STACK_SIZE 32
     419             : 
     420             : static struct tevent_wrapper_stack {
     421             :         const void *ev_ptr;
     422             :         const struct tevent_wrapper_glue *wrapper;
     423             : } wrapper_stack[TEVENT_WRAPPER_STACK_SIZE];
     424             : 
     425             : static size_t wrapper_stack_idx;
     426             : 
     427             : _PRIVATE_
     428          28 : void tevent_wrapper_push_use_internal(struct tevent_context *ev,
     429             :                                       struct tevent_wrapper_glue *wrapper)
     430             : {
     431             :         /*
     432             :          * ev and wrapper need to belong together!
     433             :          * It's also fine to only have a raw ev
     434             :          * without a wrapper.
     435             :          */
     436          28 :         if (unlikely(ev->wrapper.glue != wrapper)) {
     437           0 :                 tevent_abort(ev, "tevent_wrapper_push_use_internal() invalid arguments");
     438           0 :                 return;
     439             :         }
     440             : 
     441          28 :         if (wrapper != NULL) {
     442          24 :                 if (unlikely(wrapper->busy)) {
     443           0 :                         tevent_abort(ev, "wrapper already busy!");
     444           0 :                         return;
     445             :                 }
     446          24 :                 wrapper->busy = true;
     447             :         }
     448             : 
     449          28 :         if (unlikely(wrapper_stack_idx >= TEVENT_WRAPPER_STACK_SIZE)) {
     450           0 :                 tevent_abort(ev, "TEVENT_WRAPPER_STACK_SIZE overflow");
     451           0 :                 return;
     452             :         }
     453             : 
     454          28 :         wrapper_stack[wrapper_stack_idx] = (struct tevent_wrapper_stack) {
     455             :                 .ev_ptr = ev,
     456             :                 .wrapper = wrapper,
     457             :         };
     458          28 :         wrapper_stack_idx++;
     459             : }
     460             : 
     461             : _PRIVATE_
     462          28 : void tevent_wrapper_pop_use_internal(const struct tevent_context *__ev_ptr,
     463             :                                      struct tevent_wrapper_glue *wrapper)
     464             : {
     465          28 :         struct tevent_context *main_ev = NULL;
     466             : 
     467             :         /*
     468             :          * Note that __ev_ptr might a a stale pointer and should not
     469             :          * be touched, we just compare the pointer value in order
     470             :          * to enforce the stack order.
     471             :          */
     472             : 
     473          28 :         if (wrapper != NULL) {
     474          24 :                 main_ev = wrapper->main_ev;
     475             :         }
     476             : 
     477          28 :         if (unlikely(wrapper_stack_idx == 0)) {
     478           0 :                 tevent_abort(main_ev, "tevent_wrapper stack already empty");
     479           0 :                 return;
     480             :         }
     481          28 :         wrapper_stack_idx--;
     482             : 
     483          28 :         if (wrapper != NULL) {
     484          24 :                 wrapper->busy = false;
     485             :         }
     486             : 
     487          28 :         if (wrapper_stack[wrapper_stack_idx].ev_ptr != __ev_ptr) {
     488           0 :                 tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch ev!");
     489           0 :                 return;
     490             :         }
     491          28 :         if (wrapper_stack[wrapper_stack_idx].wrapper != wrapper) {
     492           0 :                 tevent_abort(main_ev, "tevent_wrapper_pop_use mismatch wrap!");
     493           0 :                 return;
     494             :         }
     495             : 
     496          28 :         if (wrapper == NULL) {
     497           0 :                 return;
     498             :         }
     499             : 
     500          24 :         if (wrapper->destroyed) {
     501             :                 /*
     502             :                  * Notice that we can't use TALLOC_FREE()
     503             :                  * here because wrapper is a talloc child
     504             :                  * of wrapper->wrap_ev.
     505             :                  */
     506           4 :                 talloc_free(wrapper->wrap_ev);
     507             :         }
     508             : }
     509             : 
     510           8 : bool _tevent_context_push_use(struct tevent_context *ev,
     511             :                               const char *location)
     512             : {
     513             :         bool ok;
     514             : 
     515           8 :         if (ev->wrapper.glue == NULL) {
     516           4 :                 tevent_wrapper_push_use_internal(ev, NULL);
     517           4 :                 return true;
     518             :         }
     519             : 
     520           4 :         if (ev->wrapper.glue->main_ev == NULL) {
     521           0 :                 return false;
     522             :         }
     523             : 
     524           4 :         tevent_wrapper_push_use_internal(ev, ev->wrapper.glue);
     525           4 :         ok = ev->wrapper.glue->ops->before_use(ev->wrapper.glue->wrap_ev,
     526           0 :                                                ev->wrapper.glue->private_state,
     527           0 :                                                ev->wrapper.glue->main_ev,
     528             :                                                location);
     529           4 :         if (!ok) {
     530           0 :                 tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
     531           0 :                 return false;
     532             :         }
     533             : 
     534           0 :         return true;
     535             : }
     536             : 
     537           8 : void _tevent_context_pop_use(struct tevent_context *ev,
     538             :                              const char *location)
     539             : {
     540           8 :         tevent_wrapper_pop_use_internal(ev, ev->wrapper.glue);
     541             : 
     542           8 :         if (ev->wrapper.glue == NULL) {
     543           0 :                 return;
     544             :         }
     545             : 
     546           4 :         if (ev->wrapper.glue->main_ev == NULL) {
     547           0 :                 return;
     548             :         }
     549             : 
     550           4 :         ev->wrapper.glue->ops->after_use(ev->wrapper.glue->wrap_ev,
     551           0 :                                          ev->wrapper.glue->private_state,
     552           0 :                                          ev->wrapper.glue->main_ev,
     553             :                                          location);
     554             : }
     555             : 
     556           0 : bool tevent_context_same_loop(struct tevent_context *ev1,
     557             :                               struct tevent_context *ev2)
     558             : {
     559           0 :         struct tevent_context *main_ev1 = tevent_wrapper_main_ev(ev1);
     560           0 :         struct tevent_context *main_ev2 = tevent_wrapper_main_ev(ev2);
     561             : 
     562           0 :         if (main_ev1 == NULL) {
     563           0 :                 return false;
     564             :         }
     565             : 
     566           0 :         if (main_ev1 == main_ev2) {
     567           0 :                 return true;
     568             :         }
     569             : 
     570           0 :         return false;
     571             : }

Generated by: LCOV version 1.13