ustfork: Initialize libc pointers in constructor
[lttng-ust.git] / src / lib / lttng-ust-fork / ustfork.c
CommitLineData
e822f505 1/*
c0c0989a
MJ
2 * SPDX-License-Identifier: LGPL-2.1-only
3 *
e822f505 4 * Copyright (C) 2009 Pierre-Marc Fournier
3678c8aa 5 * Copyright (C) 2011-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
2d99476b
PMF
6 */
7
9d315d6d
MJ
8/* Has to be included first to override dlfcn.h */
9#include <common/compat/dlfcn.h>
10
2d99476b 11#include <unistd.h>
8b27b287 12#include <stdbool.h>
2d99476b 13#include <stdio.h>
df793c55 14#include <signal.h>
616ed36a
PMF
15#include <sched.h>
16#include <stdarg.h>
e2a195a6 17#include <stdlib.h>
eb2b066f 18#include <errno.h>
2d99476b 19
8b27b287
OD
20#include <pthread.h>
21
d0c8f180 22#include <lttng/ust-fork.h>
e822f505 23
cf54f06a
OD
24#include <urcu/uatomic.h>
25
8b27b287
OD
26#include "common/macros.h"
27
28struct libc_pointer {
29 void **procedure;
30 const char *symbol;
31};
32
33#define DEFINE_LIBC_POINTER(name) { (void**)&plibc_## name, #name }
34
35#ifdef __linux__
36
37struct user_desc;
38
39static 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;
42
43static int (*plibc_setns)(int fd, int nstype) = NULL;
44
45static int (*plibc_setresgid)(gid_t rgid, gid_t egid, gid_t sgid) = NULL;
46
47static int (*plibc_setresuid)(uid_t ruid, uid_t euid, uid_t suid) = NULL;
48
49static int (*plibc_unshare)(int flags) = NULL;
50
51#elif defined (__FreeBSD__)
52
53static pid_t (*plibc_rfork)(int flags) = NULL;
54
55#endif
56
57static int (*plibc_daemon)(int nochdir, int noclose) = NULL;
58
59static pid_t (*plibc_fork)(void) = NULL;
60
61static int (*plibc_setegid)(gid_t egid) = NULL;
62
63static int (*plibc_seteuid)(uid_t euid) = NULL;
64
65static int (*plibc_setgid)(gid_t gid) = NULL;
66
67static int (*plibc_setregid)(gid_t rgid, gid_t egid) = NULL;
68
69static int (*plibc_setreuid)(uid_t ruid, uid_t euid) = NULL;
70
71static int (*plibc_setuid)(uid_t uid) = NULL;
72
73static void lttng_ust_fork_wrapper_ctor(void)
74 __attribute__((constructor));
75
76static pthread_mutex_t initialization_guard = PTHREAD_MUTEX_INITIALIZER;
77static bool was_initialized = false;
78
79/*
80 * Must be called with initialization_guard held.
81 */
82static void initialize(void)
83{
84 const struct libc_pointer libc_pointers[] = {
85#ifdef __linux__
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),
93#endif
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),
102 };
103
104 size_t k;
105
106 for (k = 0; k < LTTNG_ARRAY_SIZE(libc_pointers); ++k) {
107 void *procedure = dlsym(RTLD_NEXT, libc_pointers[k].symbol);
108
109 if (NULL == procedure) {
110 fprintf(stderr,
111 "libustfork: unable to find \"%s\" symbol\n",
112 libc_pointers[k].symbol);
113 continue;
114 }
115
116 uatomic_set(libc_pointers[k].procedure, procedure);
117 }
118}
119
120/*
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.
124 *
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.
127 */
128static void *lazy_initialize(void **pfunc)
129{
130 void *func = uatomic_read(pfunc);
131
132 /*
133 * If *pfunc != NULL, then it is assumed that some thread has already
134 * called the initialization routine.
135 */
136 if (caa_likely(func)) {
137 goto out;
138 }
139
140 pthread_mutex_lock(&initialization_guard);
141 if (!was_initialized) {
142 initialize();
143 was_initialized = true;
144 }
145 func = *pfunc;
146 pthread_mutex_unlock(&initialization_guard);
147out:
148 return func;
149}
150
151#define LAZY_INITIALIZE_OR_NOSYS(ptr) \
152 ({ \
153 void *ret; \
154 \
155 ret = lazy_initialize((void**)&(ptr)); \
156 if (NULL == ret) { \
157 errno = ENOSYS; \
158 return -1; \
159 } \
160 \
161 ret; \
162 })
163
164static void lttng_ust_fork_wrapper_ctor(void)
165{
166 /*
167 * Using fork here because it is defined on all supported OS.
168 */
169 (void) lazy_initialize((void**)&plibc_fork);
170}
171
2d99476b
PMF
172pid_t fork(void)
173{
7f0aeeba 174 sigset_t sigset;
2d99476b 175 pid_t retval;
111902ab 176 int saved_errno;
2d99476b 177
8b27b287 178 pid_t (*func)(void) = LAZY_INITIALIZE_OR_NOSYS(plibc_fork);
2d99476b 179
d0c8f180 180 lttng_ust_before_fork(&sigset);
df793c55 181 /* Do the real fork */
cf54f06a 182 retval = func();
111902ab 183 saved_errno = errno;
e822f505 184 if (retval == 0) {
df793c55 185 /* child */
d0c8f180 186 lttng_ust_after_fork_child(&sigset);
e822f505 187 } else {
d0c8f180 188 lttng_ust_after_fork_parent(&sigset);
df793c55 189 }
111902ab 190 errno = saved_errno;
2d99476b
PMF
191 return retval;
192}
97b042a3 193
2f6150e9
MD
194int daemon(int nochdir, int noclose)
195{
2f6150e9
MD
196 sigset_t sigset;
197 int retval;
111902ab 198 int saved_errno;
2f6150e9 199
8b27b287 200 int (*func)(int, int) = LAZY_INITIALIZE_OR_NOSYS(plibc_daemon);
2f6150e9 201
d0c8f180 202 lttng_ust_before_fork(&sigset);
2f6150e9 203 /* Do the real daemon call */
cf54f06a 204 retval = func(nochdir, noclose);
111902ab 205 saved_errno = errno;
2f6150e9
MD
206 if (retval == 0) {
207 /* child, parent called _exit() directly */
d0c8f180 208 lttng_ust_after_fork_child(&sigset);
2f6150e9
MD
209 } else {
210 /* on error in the parent */
d0c8f180 211 lttng_ust_after_fork_parent(&sigset);
2f6150e9 212 }
111902ab 213 errno = saved_errno;
2f6150e9
MD
214 return retval;
215}
216
fca2f191
MJ
217int setuid(uid_t uid)
218{
fca2f191
MJ
219 int retval;
220 int saved_errno;
221
8b27b287 222 int (*func)(uid_t) = LAZY_INITIALIZE_OR_NOSYS(plibc_setuid);
fca2f191
MJ
223
224 /* Do the real setuid */
cf54f06a 225 retval = func(uid);
fca2f191
MJ
226 saved_errno = errno;
227
d0c8f180 228 lttng_ust_after_setuid();
fca2f191
MJ
229
230 errno = saved_errno;
231 return retval;
232}
233
234int setgid(gid_t gid)
235{
fca2f191
MJ
236 int retval;
237 int saved_errno;
238
8b27b287 239 int (*func)(gid_t) = LAZY_INITIALIZE_OR_NOSYS(plibc_setgid);
fca2f191
MJ
240
241 /* Do the real setgid */
cf54f06a 242 retval = func(gid);
fca2f191
MJ
243 saved_errno = errno;
244
d0c8f180 245 lttng_ust_after_setgid();
fca2f191
MJ
246
247 errno = saved_errno;
248 return retval;
249}
250
251int seteuid(uid_t euid)
252{
fca2f191
MJ
253 int retval;
254 int saved_errno;
255
8b27b287 256 int (*func)(uid_t) = LAZY_INITIALIZE_OR_NOSYS(plibc_seteuid);
fca2f191
MJ
257
258 /* Do the real seteuid */
cf54f06a 259 retval = func(euid);
fca2f191
MJ
260 saved_errno = errno;
261
d0c8f180 262 lttng_ust_after_seteuid();
fca2f191
MJ
263
264 errno = saved_errno;
265 return retval;
266}
267
268int setegid(gid_t egid)
269{
fca2f191
MJ
270 int retval;
271 int saved_errno;
272
8b27b287 273 int (*func)(gid_t) = LAZY_INITIALIZE_OR_NOSYS(plibc_setegid);
fca2f191
MJ
274
275 /* Do the real setegid */
cf54f06a 276 retval = func(egid);
fca2f191
MJ
277 saved_errno = errno;
278
d0c8f180 279 lttng_ust_after_setegid();
fca2f191
MJ
280
281 errno = saved_errno;
282 return retval;
283}
284
285int setreuid(uid_t ruid, uid_t euid)
286{
fca2f191
MJ
287 int retval;
288 int saved_errno;
289
8b27b287
OD
290 int (*func)(uid_t, uid_t) =
291 LAZY_INITIALIZE_OR_NOSYS(plibc_setreuid);
fca2f191
MJ
292
293 /* Do the real setreuid */
cf54f06a 294 retval = func(ruid, euid);
fca2f191
MJ
295 saved_errno = errno;
296
d0c8f180 297 lttng_ust_after_setreuid();
fca2f191
MJ
298
299 errno = saved_errno;
300 return retval;
301}
302
303int setregid(gid_t rgid, gid_t egid)
304{
fca2f191
MJ
305 int retval;
306 int saved_errno;
307
8b27b287 308 int (*func)(gid_t, gid_t) = LAZY_INITIALIZE_OR_NOSYS(plibc_setregid);
fca2f191
MJ
309
310 /* Do the real setregid */
cf54f06a 311 retval = func(rgid, egid);
fca2f191
MJ
312 saved_errno = errno;
313
d0c8f180 314 lttng_ust_after_setregid();
fca2f191
MJ
315
316 errno = saved_errno;
317 return retval;
318}
319
939c89cb
MD
320#ifdef __linux__
321
e822f505 322struct ustfork_clone_info {
616ed36a
PMF
323 int (*fn)(void *);
324 void *arg;
7f0aeeba 325 sigset_t sigset;
616ed36a
PMF
326};
327
328static int clone_fn(void *arg)
329{
e822f505 330 struct ustfork_clone_info *info = (struct ustfork_clone_info *) arg;
616ed36a
PMF
331
332 /* clone is now done and we are in child */
d0c8f180 333 lttng_ust_after_fork_child(&info->sigset);
616ed36a
PMF
334 return info->fn(info->arg);
335}
336
337int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...)
338{
e822f505 339 /* var args */
616ed36a
PMF
340 pid_t *ptid;
341 struct user_desc *tls;
342 pid_t *ctid;
e822f505 343 /* end of var args */
616ed36a 344 va_list ap;
e822f505 345 int retval;
111902ab 346 int saved_errno;
616ed36a
PMF
347
348 va_start(ap, arg);
349 ptid = va_arg(ap, pid_t *);
350 tls = va_arg(ap, struct user_desc *);
351 ctid = va_arg(ap, pid_t *);
352 va_end(ap);
353
8b27b287
OD
354 int (*func)(int (*)(void *), void *, int , void *, pid_t *,
355 struct user_desc *, pid_t *) =
356 LAZY_INITIALIZE_OR_NOSYS(plibc_clone);
616ed36a 357
e822f505
MD
358 if (flags & CLONE_VM) {
359 /*
360 * Creating a thread, no need to intervene, just pass on
361 * the arguments.
362 */
cf54f06a
OD
363 retval = func(fn, child_stack, flags, arg, ptid,
364 tls, ctid);
111902ab 365 saved_errno = errno;
e822f505
MD
366 } else {
367 /* Creating a real process, we need to intervene. */
3fd2b913 368 struct ustfork_clone_info info = { .fn = fn, .arg = arg };
616ed36a 369
d0c8f180 370 lttng_ust_before_fork(&info.sigset);
cf54f06a
OD
371 retval = func(clone_fn, child_stack, flags, &info,
372 ptid, tls, ctid);
111902ab 373 saved_errno = errno;
e822f505 374 /* The child doesn't get here. */
d0c8f180 375 lttng_ust_after_fork_parent(&info.sigset);
616ed36a 376 }
111902ab 377 errno = saved_errno;
616ed36a
PMF
378 return retval;
379}
939c89cb 380
735bef47
MJ
381int setns(int fd, int nstype)
382{
735bef47
MJ
383 int retval;
384 int saved_errno;
385
8b27b287 386 int (*func)(int, int) = LAZY_INITIALIZE_OR_NOSYS(plibc_setns);
735bef47
MJ
387
388 /* Do the real setns */
cf54f06a 389 retval = func(fd, nstype);
735bef47
MJ
390 saved_errno = errno;
391
d0c8f180 392 lttng_ust_after_setns();
735bef47
MJ
393
394 errno = saved_errno;
395 return retval;
396}
397
398int unshare(int flags)
399{
735bef47
MJ
400 int retval;
401 int saved_errno;
402
8b27b287 403 int (*func)(int) = LAZY_INITIALIZE_OR_NOSYS(plibc_unshare);
735bef47
MJ
404
405 /* Do the real setns */
cf54f06a 406 retval = func(flags);
735bef47
MJ
407 saved_errno = errno;
408
d0c8f180 409 lttng_ust_after_unshare();
735bef47
MJ
410
411 errno = saved_errno;
412 return retval;
413}
414
fca2f191
MJ
415int setresuid(uid_t ruid, uid_t euid, uid_t suid)
416{
fca2f191
MJ
417 int retval;
418 int saved_errno;
419
8b27b287
OD
420 int (*func)(uid_t, uid_t, uid_t) =
421 LAZY_INITIALIZE_OR_NOSYS(plibc_setresuid);
fca2f191
MJ
422
423 /* Do the real setresuid */
cf54f06a 424 retval = func(ruid, euid, suid);
fca2f191
MJ
425 saved_errno = errno;
426
d0c8f180 427 lttng_ust_after_setresuid();
fca2f191
MJ
428
429 errno = saved_errno;
430 return retval;
431}
432
433int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
434{
fca2f191
MJ
435 int retval;
436 int saved_errno;
437
8b27b287
OD
438 int (*func)(gid_t, gid_t, gid_t) =
439 LAZY_INITIALIZE_OR_NOSYS(plibc_setresgid);
fca2f191
MJ
440
441 /* Do the real setresgid */
cf54f06a 442 retval = func(rgid, egid, sgid);
fca2f191
MJ
443 saved_errno = errno;
444
d0c8f180 445 lttng_ust_after_setresgid();
fca2f191
MJ
446
447 errno = saved_errno;
448 return retval;
449}
450
939c89cb
MD
451#elif defined (__FreeBSD__)
452
453pid_t rfork(int flags)
454{
939c89cb
MD
455 sigset_t sigset;
456 pid_t retval;
111902ab 457 int saved_errno;
939c89cb 458
8b27b287 459 pid_t (*func)(int) = LAZY_INITIALIZE_OR_NOSYS(plibc_rfork);
939c89cb 460
d0c8f180 461 lttng_ust_before_fork(&sigset);
939c89cb 462 /* Do the real rfork */
cf54f06a 463 retval = func(flags);
111902ab 464 saved_errno = errno;
939c89cb
MD
465 if (retval == 0) {
466 /* child */
d0c8f180 467 lttng_ust_after_fork_child(&sigset);
939c89cb 468 } else {
d0c8f180 469 lttng_ust_after_fork_parent(&sigset);
939c89cb 470 }
111902ab 471 errno = saved_errno;
939c89cb
MD
472 return retval;
473}
474
475/*
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
478 * the child.
479 */
480
481#else
482#warning "Unknown OS. You might want to ensure that fork/clone/vfork/fork handling is complete."
483#endif
This page took 0.061464 seconds and 4 git commands to generate.