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