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