2 * SPDX-License-Identifier: LGPL-2.1-only
4 * Copyright (C) 2009 Pierre-Marc Fournier
5 * Copyright (C) 2011-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 /* Has to be included first to override dlfcn.h */
9 #include <common/compat/dlfcn.h>
22 #include <lttng/ust-fork.h>
24 #include <urcu/uatomic.h>
26 #include "common/macros.h"
33 #define DEFINE_LIBC_POINTER(name) { (void**)&plibc_## name, #name }
39 static int (*plibc_clone
)(int (*fn
)(void *), void *child_stack
,
40 int flags
, void *arg
, pid_t
*ptid
,
41 struct user_desc
*tls
, pid_t
*ctid
) = NULL
;
43 static int (*plibc_setns
)(int fd
, int nstype
) = NULL
;
45 static int (*plibc_setresgid
)(gid_t rgid
, gid_t egid
, gid_t sgid
) = NULL
;
47 static int (*plibc_setresuid
)(uid_t ruid
, uid_t euid
, uid_t suid
) = NULL
;
49 static int (*plibc_unshare
)(int flags
) = NULL
;
51 #elif defined (__FreeBSD__)
53 static pid_t (*plibc_rfork
)(int flags
) = NULL
;
57 static int (*plibc_daemon
)(int nochdir
, int noclose
) = NULL
;
59 static pid_t (*plibc_fork
)(void) = NULL
;
61 static int (*plibc_setegid
)(gid_t egid
) = NULL
;
63 static int (*plibc_seteuid
)(uid_t euid
) = NULL
;
65 static int (*plibc_setgid
)(gid_t gid
) = NULL
;
67 static int (*plibc_setregid
)(gid_t rgid
, gid_t egid
) = NULL
;
69 static int (*plibc_setreuid
)(uid_t ruid
, uid_t euid
) = NULL
;
71 static int (*plibc_setuid
)(uid_t uid
) = NULL
;
73 static void lttng_ust_fork_wrapper_ctor(void)
74 __attribute__((constructor
));
76 static pthread_mutex_t initialization_guard
= PTHREAD_MUTEX_INITIALIZER
;
77 static bool was_initialized
= false;
80 * Must be called with initialization_guard held.
82 static void initialize(void)
84 const struct libc_pointer libc_pointers
[] = {
86 DEFINE_LIBC_POINTER(clone
),
87 DEFINE_LIBC_POINTER(setns
),
88 DEFINE_LIBC_POINTER(setresgid
),
89 DEFINE_LIBC_POINTER(setresuid
),
90 DEFINE_LIBC_POINTER(unshare
),
91 #elif defined (__FreeBSD__)
92 DEFINE_LIBC_POINTER(rfork
),
94 DEFINE_LIBC_POINTER(daemon
),
95 DEFINE_LIBC_POINTER(fork
),
96 DEFINE_LIBC_POINTER(setegid
),
97 DEFINE_LIBC_POINTER(seteuid
),
98 DEFINE_LIBC_POINTER(setgid
),
99 DEFINE_LIBC_POINTER(setregid
),
100 DEFINE_LIBC_POINTER(setreuid
),
101 DEFINE_LIBC_POINTER(setuid
),
106 for (k
= 0; k
< LTTNG_ARRAY_SIZE(libc_pointers
); ++k
) {
107 void *procedure
= dlsym(RTLD_NEXT
, libc_pointers
[k
].symbol
);
109 if (NULL
== procedure
) {
111 "libustfork: unable to find \"%s\" symbol\n",
112 libc_pointers
[k
].symbol
);
116 uatomic_set(libc_pointers
[k
].procedure
, procedure
);
121 * Lazy initialization is required because it is possible for a shared library
122 * to have a constructor that is executed before our constructor, which could
123 * call some libc functions that we are wrapping.
125 * It is also possible for this library constructor to create a thread using the
126 * raw system call. Therefore, the lazy initialization must be multi-thread safe.
128 static void *lazy_initialize(void **pfunc
)
130 void *func
= uatomic_read(pfunc
);
133 * If *pfunc != NULL, then it is assumed that some thread has already
134 * called the initialization routine.
136 if (caa_likely(func
)) {
140 pthread_mutex_lock(&initialization_guard
);
141 if (!was_initialized
) {
143 was_initialized
= true;
146 pthread_mutex_unlock(&initialization_guard
);
151 #define LAZY_INITIALIZE_OR_NOSYS(ptr) \
155 ret = lazy_initialize((void**)&(ptr)); \
164 static void lttng_ust_fork_wrapper_ctor(void)
167 * Using fork here because it is defined on all supported OS.
169 (void) lazy_initialize((void**)&plibc_fork
);
178 pid_t (*func
)(void) = LAZY_INITIALIZE_OR_NOSYS(plibc_fork
);
180 lttng_ust_before_fork(&sigset
);
181 /* Do the real fork */
186 lttng_ust_after_fork_child(&sigset
);
188 lttng_ust_after_fork_parent(&sigset
);
194 int daemon(int nochdir
, int noclose
)
200 int (*func
)(int, int) = LAZY_INITIALIZE_OR_NOSYS(plibc_daemon
);
202 lttng_ust_before_fork(&sigset
);
203 /* Do the real daemon call */
204 retval
= func(nochdir
, noclose
);
207 /* child, parent called _exit() directly */
208 lttng_ust_after_fork_child(&sigset
);
210 /* on error in the parent */
211 lttng_ust_after_fork_parent(&sigset
);
217 int setuid(uid_t uid
)
222 int (*func
)(uid_t
) = LAZY_INITIALIZE_OR_NOSYS(plibc_setuid
);
224 /* Do the real setuid */
228 lttng_ust_after_setuid();
234 int setgid(gid_t gid
)
239 int (*func
)(gid_t
) = LAZY_INITIALIZE_OR_NOSYS(plibc_setgid
);
241 /* Do the real setgid */
245 lttng_ust_after_setgid();
251 int seteuid(uid_t euid
)
256 int (*func
)(uid_t
) = LAZY_INITIALIZE_OR_NOSYS(plibc_seteuid
);
258 /* Do the real seteuid */
262 lttng_ust_after_seteuid();
268 int setegid(gid_t egid
)
273 int (*func
)(gid_t
) = LAZY_INITIALIZE_OR_NOSYS(plibc_setegid
);
275 /* Do the real setegid */
279 lttng_ust_after_setegid();
285 int setreuid(uid_t ruid
, uid_t euid
)
290 int (*func
)(uid_t
, uid_t
) =
291 LAZY_INITIALIZE_OR_NOSYS(plibc_setreuid
);
293 /* Do the real setreuid */
294 retval
= func(ruid
, euid
);
297 lttng_ust_after_setreuid();
303 int setregid(gid_t rgid
, gid_t egid
)
308 int (*func
)(gid_t
, gid_t
) = LAZY_INITIALIZE_OR_NOSYS(plibc_setregid
);
310 /* Do the real setregid */
311 retval
= func(rgid
, egid
);
314 lttng_ust_after_setregid();
322 struct ustfork_clone_info
{
328 static int clone_fn(void *arg
)
330 struct ustfork_clone_info
*info
= (struct ustfork_clone_info
*) arg
;
332 /* clone is now done and we are in child */
333 lttng_ust_after_fork_child(&info
->sigset
);
334 return info
->fn(info
->arg
);
337 int clone(int (*fn
)(void *), void *child_stack
, int flags
, void *arg
, ...)
341 struct user_desc
*tls
;
343 /* end of var args */
349 ptid
= va_arg(ap
, pid_t
*);
350 tls
= va_arg(ap
, struct user_desc
*);
351 ctid
= va_arg(ap
, pid_t
*);
354 int (*func
)(int (*)(void *), void *, int , void *, pid_t
*,
355 struct user_desc
*, pid_t
*) =
356 LAZY_INITIALIZE_OR_NOSYS(plibc_clone
);
358 if (flags
& CLONE_VM
) {
360 * Creating a thread, no need to intervene, just pass on
363 retval
= func(fn
, child_stack
, flags
, arg
, ptid
,
367 /* Creating a real process, we need to intervene. */
368 struct ustfork_clone_info info
= { .fn
= fn
, .arg
= arg
};
370 lttng_ust_before_fork(&info
.sigset
);
371 retval
= func(clone_fn
, child_stack
, flags
, &info
,
374 /* The child doesn't get here. */
375 lttng_ust_after_fork_parent(&info
.sigset
);
381 int setns(int fd
, int nstype
)
386 int (*func
)(int, int) = LAZY_INITIALIZE_OR_NOSYS(plibc_setns
);
388 /* Do the real setns */
389 retval
= func(fd
, nstype
);
392 lttng_ust_after_setns();
398 int unshare(int flags
)
403 int (*func
)(int) = LAZY_INITIALIZE_OR_NOSYS(plibc_unshare
);
405 /* Do the real setns */
406 retval
= func(flags
);
409 lttng_ust_after_unshare();
415 int setresuid(uid_t ruid
, uid_t euid
, uid_t suid
)
420 int (*func
)(uid_t
, uid_t
, uid_t
) =
421 LAZY_INITIALIZE_OR_NOSYS(plibc_setresuid
);
423 /* Do the real setresuid */
424 retval
= func(ruid
, euid
, suid
);
427 lttng_ust_after_setresuid();
433 int setresgid(gid_t rgid
, gid_t egid
, gid_t sgid
)
438 int (*func
)(gid_t
, gid_t
, gid_t
) =
439 LAZY_INITIALIZE_OR_NOSYS(plibc_setresgid
);
441 /* Do the real setresgid */
442 retval
= func(rgid
, egid
, sgid
);
445 lttng_ust_after_setresgid();
451 #elif defined (__FreeBSD__)
453 pid_t
rfork(int flags
)
459 pid_t (*func
)(int) = LAZY_INITIALIZE_OR_NOSYS(plibc_rfork
);
461 lttng_ust_before_fork(&sigset
);
462 /* Do the real rfork */
463 retval
= func(flags
);
467 lttng_ust_after_fork_child(&sigset
);
469 lttng_ust_after_fork_parent(&sigset
);
476 * On BSD, no need to override vfork, because it runs in the context of
477 * the parent, with parent waiting until execve or exit is executed in
482 #warning "Unknown OS. You might want to ensure that fork/clone/vfork/fork handling is complete."