Fix: ust-fork: reverse order of "after" callbacks
[lttng-ust.git] / src / lib / lttng-ust-fork / ustfork.c
1 /*
2 * SPDX-License-Identifier: LGPL-2.1-only
3 *
4 * Copyright (C) 2009 Pierre-Marc Fournier
5 * Copyright (C) 2011-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
6 */
7
8 /* Has to be included first to override dlfcn.h */
9 #include <common/compat/dlfcn.h>
10
11 #include <unistd.h>
12 #include <stdio.h>
13 #include <signal.h>
14 #include <sched.h>
15 #include <stdarg.h>
16 #include <stdlib.h>
17 #include <errno.h>
18
19 #include <lttng/ust-fork.h>
20
21 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
22 static int (*__ust_before_fork)(sigset_t *save_sigset) = NULL;
23 static int (*__ust_after_fork_child)(sigset_t *restore_sigset) = NULL;
24 static int (*__ust_after_fork_parent)(sigset_t *restore_sigset) = NULL;
25
26 static void (*__ust_after_setns)(void) = NULL;
27 static void (*__ust_after_unshare)(void) = NULL;
28 static void (*__ust_after_setuid)(void) = NULL;
29 static void (*__ust_after_setgid)(void) = NULL;
30 static void (*__ust_after_seteuid)(void) = NULL;
31 static void (*__ust_after_setegid)(void) = NULL;
32 static void (*__ust_after_setreuid)(void) = NULL;
33 static void (*__ust_after_setregid)(void) = NULL;
34 static void (*__ust_after_setresuid)(void) = NULL;
35 static void (*__ust_after_setresgid)(void) = NULL;
36
37 static
38 void *_init_ust_before_fork(void)
39 {
40 if (__ust_before_fork == NULL) {
41 __ust_before_fork = dlsym(RTLD_DEFAULT, "ust_before_fork");
42
43 if (__ust_before_fork == NULL) {
44 fprintf(stderr, "%s\n", dlerror());
45 }
46 }
47
48 return __ust_before_fork;
49 }
50
51 static
52 void *_init_ust_after_fork_child(void)
53 {
54 if (__ust_after_fork_child == NULL) {
55 __ust_after_fork_child = dlsym(RTLD_DEFAULT, "ust_after_fork_child");
56
57 if (__ust_after_fork_child == NULL) {
58 fprintf(stderr, "%s\n", dlerror());
59 }
60 }
61
62 return __ust_after_fork_child;
63 }
64
65 static
66 void *_init_ust_after_fork_parent(void)
67 {
68 if (__ust_after_fork_parent == NULL) {
69 __ust_after_fork_parent = dlsym(RTLD_DEFAULT, "ust_after_fork_parent");
70
71 if (__ust_after_fork_parent == NULL) {
72 fprintf(stderr, "%s\n", dlerror());
73 }
74 }
75
76 return __ust_after_fork_parent;
77 }
78
79 static
80 void *_init_ust_after_setns(void)
81 {
82 if (__ust_after_setns == NULL) {
83 __ust_after_setns = dlsym(RTLD_DEFAULT, "ust_after_setns");
84
85 if (__ust_after_setns == NULL) {
86 fprintf(stderr, "%s\n", dlerror());
87 }
88 }
89
90 return __ust_after_setns;
91 }
92
93 static
94 void *_init_ust_after_unshare(void)
95 {
96 if (__ust_after_unshare == NULL) {
97 __ust_after_unshare = dlsym(RTLD_DEFAULT, "ust_after_unshare");
98
99 if (__ust_after_unshare == NULL) {
100 fprintf(stderr, "%s\n", dlerror());
101 }
102 }
103
104 return __ust_after_unshare;
105 }
106
107 static
108 void *_init_ust_after_setuid(void)
109 {
110 if (__ust_after_setuid == NULL) {
111 __ust_after_setuid = dlsym(RTLD_DEFAULT, "ust_after_setuid");
112
113 if (__ust_after_setuid == NULL) {
114 fprintf(stderr, "%s\n", dlerror());
115 }
116 }
117
118 return __ust_after_setuid;
119 }
120
121 static
122 void *_init_ust_after_setgid(void)
123 {
124 if (__ust_after_setgid == NULL) {
125 __ust_after_setgid = dlsym(RTLD_DEFAULT, "ust_after_setgid");
126
127 if (__ust_after_setgid == NULL) {
128 fprintf(stderr, "%s\n", dlerror());
129 }
130 }
131
132 return __ust_after_setgid;
133 }
134
135 static
136 void *_init_ust_after_seteuid(void)
137 {
138 if (__ust_after_seteuid == NULL) {
139 __ust_after_seteuid = dlsym(RTLD_DEFAULT, "ust_after_seteuid");
140
141 if (__ust_after_seteuid == NULL) {
142 fprintf(stderr, "%s\n", dlerror());
143 }
144 }
145
146 return __ust_after_seteuid;
147 }
148
149 static
150 void *_init_ust_after_setegid(void)
151 {
152 if (__ust_after_setegid == NULL) {
153 __ust_after_setegid = dlsym(RTLD_DEFAULT, "ust_after_setegid");
154
155 if (__ust_after_setegid == NULL) {
156 fprintf(stderr, "%s\n", dlerror());
157 }
158 }
159
160 return __ust_after_setegid;
161 }
162
163 static
164 void *_init_ust_after_setreuid(void)
165 {
166 if (__ust_after_setreuid == NULL) {
167 __ust_after_setreuid = dlsym(RTLD_DEFAULT, "ust_after_setreuid");
168
169 if (__ust_after_setreuid == NULL) {
170 fprintf(stderr, "%s\n", dlerror());
171 }
172 }
173
174 return __ust_after_setreuid;
175 }
176
177 static
178 void *_init_ust_after_setregid(void)
179 {
180 if (__ust_after_setregid == NULL) {
181 __ust_after_setregid = dlsym(RTLD_DEFAULT, "ust_after_setregid");
182
183 if (__ust_after_setregid == NULL) {
184 fprintf(stderr, "%s\n", dlerror());
185 }
186 }
187
188 return __ust_after_setregid;
189 }
190
191 static
192 void *_init_ust_after_setresuid(void)
193 {
194 if (__ust_after_setresuid == NULL) {
195 __ust_after_setresuid = dlsym(RTLD_DEFAULT, "ust_after_setresuid");
196
197 if (__ust_after_setresuid == NULL) {
198 fprintf(stderr, "%s\n", dlerror());
199 }
200 }
201
202 return __ust_after_setresuid;
203 }
204
205 static
206 void *_init_ust_after_setresgid(void)
207 {
208 if (__ust_after_setresgid == NULL) {
209 __ust_after_setresgid = dlsym(RTLD_DEFAULT, "ust_after_setresgid");
210
211 if (__ust_after_setresgid == NULL) {
212 fprintf(stderr, "%s\n", dlerror());
213 }
214 }
215
216 return __ust_after_setresgid;
217 }
218
219 static
220 void _lttng_ust_fork_ctor(void)
221 __attribute__((constructor));
222 static
223 void _lttng_ust_fork_ctor(void)
224 {
225 void *handle = NULL;
226
227 /*
228 * Load ust-2.12 in the global symbol namespace.
229 */
230 handle = dlopen("liblttng-ust.so.0", RTLD_GLOBAL | RTLD_NOW);
231 if (!handle) {
232 fprintf(stderr, "liblttng-ust-fork.so.1: Failed to dlopen liblttng-ust.so.0: %s\n", dlerror());
233 abort();
234 }
235 }
236 #endif
237
238 pid_t fork(void)
239 {
240 static pid_t (*plibc_func)(void) = NULL;
241 sigset_t sigset;
242 pid_t retval;
243 int saved_errno;
244
245 if (plibc_func == NULL) {
246 plibc_func = dlsym(RTLD_NEXT, "fork");
247 if (plibc_func == NULL) {
248 fprintf(stderr, "libustfork: unable to find \"fork\" symbol\n");
249 errno = ENOSYS;
250 return -1;
251 }
252 }
253
254 lttng_ust_before_fork(&sigset);
255 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
256 if (_init_ust_before_fork()) {
257 __ust_before_fork(&sigset);
258 }
259 #endif
260
261 /* Do the real fork */
262 retval = plibc_func();
263 saved_errno = errno;
264 if (retval == 0) {
265 /* child */
266 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
267 if (_init_ust_after_fork_child()) {
268 __ust_after_fork_child(&sigset);
269 }
270 #endif
271 lttng_ust_after_fork_child(&sigset);
272 } else {
273 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
274 if (_init_ust_after_fork_parent()) {
275 __ust_after_fork_parent(&sigset);
276 }
277 #endif
278 lttng_ust_after_fork_parent(&sigset);
279 }
280 errno = saved_errno;
281 return retval;
282 }
283
284 int daemon(int nochdir, int noclose)
285 {
286 static int (*plibc_func)(int nochdir, int noclose) = NULL;
287 sigset_t sigset;
288 int retval;
289 int saved_errno;
290
291 if (plibc_func == NULL) {
292 plibc_func = dlsym(RTLD_NEXT, "daemon");
293 if (plibc_func == NULL) {
294 fprintf(stderr, "libustfork: unable to find \"daemon\" symbol\n");
295 errno = ENOSYS;
296 return -1;
297 }
298 }
299
300 lttng_ust_before_fork(&sigset);
301 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
302 if (_init_ust_before_fork()) {
303 __ust_before_fork(&sigset);
304 }
305 #endif
306
307 /* Do the real daemon call */
308 retval = plibc_func(nochdir, noclose);
309 saved_errno = errno;
310 if (retval == 0) {
311 /* child, parent called _exit() directly */
312 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
313 if (_init_ust_after_fork_child()) {
314 __ust_after_fork_child(&sigset);
315 }
316 #endif
317 lttng_ust_after_fork_child(&sigset);
318 } else {
319 /* on error in the parent */
320 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
321 if (_init_ust_after_fork_parent()) {
322 __ust_after_fork_parent(&sigset);
323 }
324 #endif
325 lttng_ust_after_fork_parent(&sigset);
326 }
327 errno = saved_errno;
328 return retval;
329 }
330
331 int setuid(uid_t uid)
332 {
333 static int (*plibc_func)(uid_t uid) = NULL;
334 int retval;
335 int saved_errno;
336
337 if (plibc_func == NULL) {
338 plibc_func = dlsym(RTLD_NEXT, "setuid");
339 if (plibc_func == NULL) {
340 fprintf(stderr, "libustfork: unable to find \"setuid\" symbol\n");
341 errno = ENOSYS;
342 return -1;
343 }
344 }
345
346 /* Do the real setuid */
347 retval = plibc_func(uid);
348 saved_errno = errno;
349
350 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
351 if (_init_ust_after_setuid()) {
352 __ust_after_setuid();
353 }
354 #endif
355 lttng_ust_after_setuid();
356
357 errno = saved_errno;
358 return retval;
359 }
360
361 int setgid(gid_t gid)
362 {
363 static int (*plibc_func)(gid_t gid) = NULL;
364 int retval;
365 int saved_errno;
366
367 if (plibc_func == NULL) {
368 plibc_func = dlsym(RTLD_NEXT, "setgid");
369 if (plibc_func == NULL) {
370 fprintf(stderr, "libustfork: unable to find \"setgid\" symbol\n");
371 errno = ENOSYS;
372 return -1;
373 }
374 }
375
376 /* Do the real setgid */
377 retval = plibc_func(gid);
378 saved_errno = errno;
379
380 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
381 if (_init_ust_after_setgid()) {
382 __ust_after_setgid();
383 }
384 #endif
385 lttng_ust_after_setgid();
386
387 errno = saved_errno;
388 return retval;
389 }
390
391 int seteuid(uid_t euid)
392 {
393 static int (*plibc_func)(uid_t euid) = NULL;
394 int retval;
395 int saved_errno;
396
397 if (plibc_func == NULL) {
398 plibc_func = dlsym(RTLD_NEXT, "seteuid");
399 if (plibc_func == NULL) {
400 fprintf(stderr, "libustfork: unable to find \"seteuid\" symbol\n");
401 errno = ENOSYS;
402 return -1;
403 }
404 }
405
406 /* Do the real seteuid */
407 retval = plibc_func(euid);
408 saved_errno = errno;
409
410 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
411 if (_init_ust_after_seteuid()) {
412 __ust_after_seteuid();
413 }
414 #endif
415 lttng_ust_after_seteuid();
416
417 errno = saved_errno;
418 return retval;
419 }
420
421 int setegid(gid_t egid)
422 {
423 static int (*plibc_func)(gid_t egid) = NULL;
424 int retval;
425 int saved_errno;
426
427 if (plibc_func == NULL) {
428 plibc_func = dlsym(RTLD_NEXT, "setegid");
429 if (plibc_func == NULL) {
430 fprintf(stderr, "libustfork: unable to find \"setegid\" symbol\n");
431 errno = ENOSYS;
432 return -1;
433 }
434 }
435
436 /* Do the real setegid */
437 retval = plibc_func(egid);
438 saved_errno = errno;
439
440 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
441 if (_init_ust_after_setegid()) {
442 __ust_after_setegid();
443 }
444 #endif
445 lttng_ust_after_setegid();
446
447 errno = saved_errno;
448 return retval;
449 }
450
451 int setreuid(uid_t ruid, uid_t euid)
452 {
453 static int (*plibc_func)(uid_t ruid, uid_t euid) = NULL;
454 int retval;
455 int saved_errno;
456
457 if (plibc_func == NULL) {
458 plibc_func = dlsym(RTLD_NEXT, "setreuid");
459 if (plibc_func == NULL) {
460 fprintf(stderr, "libustfork: unable to find \"setreuid\" symbol\n");
461 errno = ENOSYS;
462 return -1;
463 }
464 }
465
466 /* Do the real setreuid */
467 retval = plibc_func(ruid, euid);
468 saved_errno = errno;
469
470 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
471 if (_init_ust_after_setreuid()) {
472 __ust_after_setreuid();
473 }
474 #endif
475 lttng_ust_after_setreuid();
476
477 errno = saved_errno;
478 return retval;
479 }
480
481 int setregid(gid_t rgid, gid_t egid)
482 {
483 static int (*plibc_func)(gid_t rgid, gid_t egid) = NULL;
484 int retval;
485 int saved_errno;
486
487 if (plibc_func == NULL) {
488 plibc_func = dlsym(RTLD_NEXT, "setregid");
489 if (plibc_func == NULL) {
490 fprintf(stderr, "libustfork: unable to find \"setregid\" symbol\n");
491 errno = ENOSYS;
492 return -1;
493 }
494 }
495
496 /* Do the real setregid */
497 retval = plibc_func(rgid, egid);
498 saved_errno = errno;
499
500 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
501 if (_init_ust_after_setregid()) {
502 __ust_after_setregid();
503 }
504 #endif
505 lttng_ust_after_setregid();
506
507 errno = saved_errno;
508 return retval;
509 }
510
511 #ifdef __linux__
512
513 struct user_desc;
514
515 struct ustfork_clone_info {
516 int (*fn)(void *);
517 void *arg;
518 sigset_t sigset;
519 };
520
521 static int clone_fn(void *arg)
522 {
523 struct ustfork_clone_info *info = (struct ustfork_clone_info *) arg;
524
525 /* clone is now done and we are in child */
526 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
527 if (_init_ust_after_fork_child()) {
528 __ust_after_fork_child(&info->sigset);
529 }
530 #endif
531 lttng_ust_after_fork_child(&info->sigset);
532 return info->fn(info->arg);
533 }
534
535 int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...)
536 {
537 static int (*plibc_func)(int (*fn)(void *), void *child_stack,
538 int flags, void *arg, pid_t *ptid,
539 struct user_desc *tls, pid_t *ctid) = NULL;
540 /* var args */
541 pid_t *ptid;
542 struct user_desc *tls;
543 pid_t *ctid;
544 /* end of var args */
545 va_list ap;
546 int retval;
547 int saved_errno;
548
549 va_start(ap, arg);
550 ptid = va_arg(ap, pid_t *);
551 tls = va_arg(ap, struct user_desc *);
552 ctid = va_arg(ap, pid_t *);
553 va_end(ap);
554
555 if (plibc_func == NULL) {
556 plibc_func = dlsym(RTLD_NEXT, "clone");
557 if (plibc_func == NULL) {
558 fprintf(stderr, "libustfork: unable to find \"clone\" symbol.\n");
559 errno = ENOSYS;
560 return -1;
561 }
562 }
563
564 if (flags & CLONE_VM) {
565 /*
566 * Creating a thread, no need to intervene, just pass on
567 * the arguments.
568 */
569 retval = plibc_func(fn, child_stack, flags, arg, ptid,
570 tls, ctid);
571 saved_errno = errno;
572 } else {
573 /* Creating a real process, we need to intervene. */
574 struct ustfork_clone_info info = { .fn = fn, .arg = arg };
575
576 lttng_ust_before_fork(&info.sigset);
577 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
578 if (_init_ust_before_fork()) {
579 __ust_before_fork(&info.sigset);
580 }
581 #endif
582 retval = plibc_func(clone_fn, child_stack, flags, &info,
583 ptid, tls, ctid);
584 saved_errno = errno;
585 /* The child doesn't get here. */
586 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
587 if (_init_ust_after_fork_parent()) {
588 __ust_after_fork_parent(&info.sigset);
589 }
590 #endif
591 lttng_ust_after_fork_parent(&info.sigset);
592 }
593 errno = saved_errno;
594 return retval;
595 }
596
597 int setns(int fd, int nstype)
598 {
599 static int (*plibc_func)(int fd, int nstype) = NULL;
600 int retval;
601 int saved_errno;
602
603 if (plibc_func == NULL) {
604 plibc_func = dlsym(RTLD_NEXT, "setns");
605 if (plibc_func == NULL) {
606 fprintf(stderr, "libustfork: unable to find \"setns\" symbol\n");
607 errno = ENOSYS;
608 return -1;
609 }
610 }
611
612 /* Do the real setns */
613 retval = plibc_func(fd, nstype);
614 saved_errno = errno;
615
616 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
617 if (_init_ust_after_setns()) {
618 __ust_after_setns();
619 }
620 #endif
621 lttng_ust_after_setns();
622
623 errno = saved_errno;
624 return retval;
625 }
626
627 int unshare(int flags)
628 {
629 static int (*plibc_func)(int flags) = NULL;
630 int retval;
631 int saved_errno;
632
633 if (plibc_func == NULL) {
634 plibc_func = dlsym(RTLD_NEXT, "unshare");
635 if (plibc_func == NULL) {
636 fprintf(stderr, "libustfork: unable to find \"unshare\" symbol\n");
637 errno = ENOSYS;
638 return -1;
639 }
640 }
641
642 /* Do the real setns */
643 retval = plibc_func(flags);
644 saved_errno = errno;
645
646 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
647 if (_init_ust_after_unshare()) {
648 __ust_after_unshare();
649 }
650 #endif
651 lttng_ust_after_unshare();
652
653 errno = saved_errno;
654 return retval;
655 }
656
657 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
658 {
659 static int (*plibc_func)(uid_t ruid, uid_t euid, uid_t suid) = NULL;
660 int retval;
661 int saved_errno;
662
663 if (plibc_func == NULL) {
664 plibc_func = dlsym(RTLD_NEXT, "setresuid");
665 if (plibc_func == NULL) {
666 fprintf(stderr, "libustfork: unable to find \"setresuid\" symbol\n");
667 errno = ENOSYS;
668 return -1;
669 }
670 }
671
672 /* Do the real setresuid */
673 retval = plibc_func(ruid, euid, suid);
674 saved_errno = errno;
675
676 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
677 if (_init_ust_after_setresuid()) {
678 __ust_after_setresuid();
679 }
680 #endif
681 lttng_ust_after_setresuid();
682
683 errno = saved_errno;
684 return retval;
685 }
686
687 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
688 {
689 static int (*plibc_func)(gid_t rgid, gid_t egid, gid_t sgid) = NULL;
690 int retval;
691 int saved_errno;
692
693 if (plibc_func == NULL) {
694 plibc_func = dlsym(RTLD_NEXT, "setresgid");
695 if (plibc_func == NULL) {
696 fprintf(stderr, "libustfork: unable to find \"setresgid\" symbol\n");
697 errno = ENOSYS;
698 return -1;
699 }
700 }
701
702 /* Do the real setresgid */
703 retval = plibc_func(rgid, egid, sgid);
704 saved_errno = errno;
705
706 #if !defined(LTTNG_UST_CUSTOM_UPGRADE_CONFLICTING_SYMBOLS)
707 if (_init_ust_after_setresgid()) {
708 __ust_after_setresgid();
709 }
710 #endif
711 lttng_ust_after_setresgid();
712
713 errno = saved_errno;
714 return retval;
715 }
716
717 #elif defined (__FreeBSD__)
718
719 pid_t rfork(int flags)
720 {
721 static pid_t (*plibc_func)(int flags) = NULL;
722 sigset_t sigset;
723 pid_t retval;
724 int saved_errno;
725
726 if (plibc_func == NULL) {
727 plibc_func = dlsym(RTLD_NEXT, "rfork");
728 if (plibc_func == NULL) {
729 fprintf(stderr, "libustfork: unable to find \"rfork\" symbol\n");
730 errno = ENOSYS;
731 return -1;
732 }
733 }
734
735 lttng_ust_before_fork(&sigset);
736 /* Do the real rfork */
737 retval = plibc_func(flags);
738 saved_errno = errno;
739 if (retval == 0) {
740 /* child */
741 lttng_ust_after_fork_child(&sigset);
742 } else {
743 lttng_ust_after_fork_parent(&sigset);
744 }
745 errno = saved_errno;
746 return retval;
747 }
748
749 /*
750 * On BSD, no need to override vfork, because it runs in the context of
751 * the parent, with parent waiting until execve or exit is executed in
752 * the child.
753 */
754
755 #else
756 #warning "Unknown OS. You might want to ensure that fork/clone/vfork/fork handling is complete."
757 #endif
This page took 0.047692 seconds and 5 git commands to generate.