9508cc7520eaeb23145814c9976cd24b6501a2a3
[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 #include <urcu/uatomic.h>
22
23 pid_t fork(void)
24 {
25 static pid_t (*plibc_func)(void) = NULL;
26 pid_t (*func)(void);
27 sigset_t sigset;
28 pid_t retval;
29 int saved_errno;
30
31 func = uatomic_read(plibc_func);
32 if (func == NULL) {
33 func = dlsym(RTLD_NEXT, "fork");
34 if (func == NULL) {
35 fprintf(stderr, "libustfork: unable to find \"fork\" symbol\n");
36 errno = ENOSYS;
37 return -1;
38 }
39 uatomic_set(&plibc_func, func);
40 }
41
42 lttng_ust_before_fork(&sigset);
43 /* Do the real fork */
44 retval = func();
45 saved_errno = errno;
46 if (retval == 0) {
47 /* child */
48 lttng_ust_after_fork_child(&sigset);
49 } else {
50 lttng_ust_after_fork_parent(&sigset);
51 }
52 errno = saved_errno;
53 return retval;
54 }
55
56 int daemon(int nochdir, int noclose)
57 {
58 static int (*plibc_func)(int nochdir, int noclose) = NULL;
59 int (*func)(int nochdir, int noclose);
60 sigset_t sigset;
61 int retval;
62 int saved_errno;
63
64 func = uatomic_read(plibc_func);
65 if (func == NULL) {
66 func = dlsym(RTLD_NEXT, "daemon");
67 if (func == NULL) {
68 fprintf(stderr, "libustfork: unable to find \"daemon\" symbol\n");
69 errno = ENOSYS;
70 return -1;
71 }
72 uatomic_set(&plibc_func, func);
73 }
74
75 lttng_ust_before_fork(&sigset);
76 /* Do the real daemon call */
77 retval = func(nochdir, noclose);
78 saved_errno = errno;
79 if (retval == 0) {
80 /* child, parent called _exit() directly */
81 lttng_ust_after_fork_child(&sigset);
82 } else {
83 /* on error in the parent */
84 lttng_ust_after_fork_parent(&sigset);
85 }
86 errno = saved_errno;
87 return retval;
88 }
89
90 int setuid(uid_t uid)
91 {
92 static int (*plibc_func)(uid_t uid) = NULL;
93 int (*func)(uid_t uid);
94 int retval;
95 int saved_errno;
96
97 func = uatomic_read(plibc_func);
98 if (func == NULL) {
99 func = dlsym(RTLD_NEXT, "setuid");
100 if (func == NULL) {
101 fprintf(stderr, "libustfork: unable to find \"setuid\" symbol\n");
102 errno = ENOSYS;
103 return -1;
104 }
105 uatomic_set(&plibc_func, func);
106 }
107
108 /* Do the real setuid */
109 retval = func(uid);
110 saved_errno = errno;
111
112 lttng_ust_after_setuid();
113
114 errno = saved_errno;
115 return retval;
116 }
117
118 int setgid(gid_t gid)
119 {
120 static int (*plibc_func)(gid_t gid) = NULL;
121 int (*func)(gid_t gid);
122 int retval;
123 int saved_errno;
124
125 func = uatomic_read(plibc_func);
126 if (func == NULL) {
127 func = dlsym(RTLD_NEXT, "setgid");
128 if (func == NULL) {
129 fprintf(stderr, "libustfork: unable to find \"setgid\" symbol\n");
130 errno = ENOSYS;
131 return -1;
132 }
133 uatomic_set(&plibc_func, func);
134 }
135
136 /* Do the real setgid */
137 retval = func(gid);
138 saved_errno = errno;
139
140 lttng_ust_after_setgid();
141
142 errno = saved_errno;
143 return retval;
144 }
145
146 int seteuid(uid_t euid)
147 {
148 static int (*plibc_func)(uid_t euid) = NULL;
149 int (*func)(uid_t euid);
150 int retval;
151 int saved_errno;
152
153 func = uatomic_read(plibc_func);
154 if (func == NULL) {
155 func = dlsym(RTLD_NEXT, "seteuid");
156 if (func == NULL) {
157 fprintf(stderr, "libustfork: unable to find \"seteuid\" symbol\n");
158 errno = ENOSYS;
159 return -1;
160 }
161 uatomic_set(&plibc_func, func);
162 }
163
164 /* Do the real seteuid */
165 retval = func(euid);
166 saved_errno = errno;
167
168 lttng_ust_after_seteuid();
169
170 errno = saved_errno;
171 return retval;
172 }
173
174 int setegid(gid_t egid)
175 {
176 static int (*plibc_func)(gid_t egid) = NULL;
177 int (*func)(gid_t egid);
178 int retval;
179 int saved_errno;
180
181 func = uatomic_read(plibc_func);
182 if (func == NULL) {
183 func = dlsym(RTLD_NEXT, "setegid");
184 if (func == NULL) {
185 fprintf(stderr, "libustfork: unable to find \"setegid\" symbol\n");
186 errno = ENOSYS;
187 return -1;
188 }
189 uatomic_set(&plibc_func, func);
190 }
191
192 /* Do the real setegid */
193 retval = func(egid);
194 saved_errno = errno;
195
196 lttng_ust_after_setegid();
197
198 errno = saved_errno;
199 return retval;
200 }
201
202 int setreuid(uid_t ruid, uid_t euid)
203 {
204 static int (*plibc_func)(uid_t ruid, uid_t euid) = NULL;
205 int (*func)(uid_t ruid, uid_t euid);
206 int retval;
207 int saved_errno;
208
209 func = uatomic_read(plibc_func);
210 if (func == NULL) {
211 func = dlsym(RTLD_NEXT, "setreuid");
212 if (func == NULL) {
213 fprintf(stderr, "libustfork: unable to find \"setreuid\" symbol\n");
214 errno = ENOSYS;
215 return -1;
216 }
217 uatomic_set(&plibc_func, func);
218 }
219
220 /* Do the real setreuid */
221 retval = func(ruid, euid);
222 saved_errno = errno;
223
224 lttng_ust_after_setreuid();
225
226 errno = saved_errno;
227 return retval;
228 }
229
230 int setregid(gid_t rgid, gid_t egid)
231 {
232 static int (*plibc_func)(gid_t rgid, gid_t egid) = NULL;
233 int (*func)(gid_t rgid, gid_t egid);
234 int retval;
235 int saved_errno;
236
237 func = uatomic_read(plibc_func);
238 if (func == NULL) {
239 func = dlsym(RTLD_NEXT, "setregid");
240 if (func == NULL) {
241 fprintf(stderr, "libustfork: unable to find \"setregid\" symbol\n");
242 errno = ENOSYS;
243 return -1;
244 }
245 uatomic_set(&plibc_func, func);
246 }
247
248 /* Do the real setregid */
249 retval = func(rgid, egid);
250 saved_errno = errno;
251
252 lttng_ust_after_setregid();
253
254 errno = saved_errno;
255 return retval;
256 }
257
258 #ifdef __linux__
259
260 struct user_desc;
261
262 struct ustfork_clone_info {
263 int (*fn)(void *);
264 void *arg;
265 sigset_t sigset;
266 };
267
268 static int clone_fn(void *arg)
269 {
270 struct ustfork_clone_info *info = (struct ustfork_clone_info *) arg;
271
272 /* clone is now done and we are in child */
273 lttng_ust_after_fork_child(&info->sigset);
274 return info->fn(info->arg);
275 }
276
277 int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...)
278 {
279 static int (*plibc_func)(int (*fn)(void *), void *child_stack,
280 int flags, void *arg, pid_t *ptid,
281 struct user_desc *tls, pid_t *ctid) = NULL;
282 int (*func)(int (*fn)(void *), void *child_stack,
283 int flags, void *arg, pid_t *ptid,
284 struct user_desc *tls, pid_t *ctid);
285 /* var args */
286 pid_t *ptid;
287 struct user_desc *tls;
288 pid_t *ctid;
289 /* end of var args */
290 va_list ap;
291 int retval;
292 int saved_errno;
293
294 va_start(ap, arg);
295 ptid = va_arg(ap, pid_t *);
296 tls = va_arg(ap, struct user_desc *);
297 ctid = va_arg(ap, pid_t *);
298 va_end(ap);
299
300 func = uatomic_read(plibc_func);
301 if (func == NULL) {
302 func = dlsym(RTLD_NEXT, "clone");
303 if (func == NULL) {
304 fprintf(stderr, "libustfork: unable to find \"clone\" symbol.\n");
305 errno = ENOSYS;
306 return -1;
307 }
308 uatomic_set(&plibc_func, func);
309 }
310
311 if (flags & CLONE_VM) {
312 /*
313 * Creating a thread, no need to intervene, just pass on
314 * the arguments.
315 */
316 retval = func(fn, child_stack, flags, arg, ptid,
317 tls, ctid);
318 saved_errno = errno;
319 } else {
320 /* Creating a real process, we need to intervene. */
321 struct ustfork_clone_info info = { .fn = fn, .arg = arg };
322
323 lttng_ust_before_fork(&info.sigset);
324 retval = func(clone_fn, child_stack, flags, &info,
325 ptid, tls, ctid);
326 saved_errno = errno;
327 /* The child doesn't get here. */
328 lttng_ust_after_fork_parent(&info.sigset);
329 }
330 errno = saved_errno;
331 return retval;
332 }
333
334 int setns(int fd, int nstype)
335 {
336 static int (*plibc_func)(int fd, int nstype) = NULL;
337 int (*func)(int fd, int nstype);
338 int retval;
339 int saved_errno;
340
341 func = uatomic_read(plibc_func);
342 if (func == NULL) {
343 func = dlsym(RTLD_NEXT, "setns");
344 if (func == NULL) {
345 fprintf(stderr, "libustfork: unable to find \"setns\" symbol\n");
346 errno = ENOSYS;
347 return -1;
348 }
349 uatomic_set(&plibc_func, func);
350 }
351
352 /* Do the real setns */
353 retval = func(fd, nstype);
354 saved_errno = errno;
355
356 lttng_ust_after_setns();
357
358 errno = saved_errno;
359 return retval;
360 }
361
362 int unshare(int flags)
363 {
364 static int (*plibc_func)(int flags) = NULL;
365 int (*func)(int flags);
366 int retval;
367 int saved_errno;
368
369 func = uatomic_read(plibc_func);
370 if (func == NULL) {
371 func = dlsym(RTLD_NEXT, "unshare");
372 if (func == NULL) {
373 fprintf(stderr, "libustfork: unable to find \"unshare\" symbol\n");
374 errno = ENOSYS;
375 return -1;
376 }
377 uatomic_set(&plibc_func, func);
378 }
379
380 /* Do the real setns */
381 retval = func(flags);
382 saved_errno = errno;
383
384 lttng_ust_after_unshare();
385
386 errno = saved_errno;
387 return retval;
388 }
389
390 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
391 {
392 static int (*plibc_func)(uid_t ruid, uid_t euid, uid_t suid) = NULL;
393 int (*func)(uid_t ruid, uid_t euid, uid_t suid);
394 int retval;
395 int saved_errno;
396
397 func = uatomic_read(plibc_func);
398 if (func == NULL) {
399 func = dlsym(RTLD_NEXT, "setresuid");
400 if (func == NULL) {
401 fprintf(stderr, "libustfork: unable to find \"setresuid\" symbol\n");
402 errno = ENOSYS;
403 return -1;
404 }
405 uatomic_set(&plibc_func, func);
406 }
407
408 /* Do the real setresuid */
409 retval = func(ruid, euid, suid);
410 saved_errno = errno;
411
412 lttng_ust_after_setresuid();
413
414 errno = saved_errno;
415 return retval;
416 }
417
418 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
419 {
420 static int (*plibc_func)(gid_t rgid, gid_t egid, gid_t sgid) = NULL;
421 int (*func)(gid_t rgid, gid_t egid, gid_t sgid);
422 int retval;
423 int saved_errno;
424
425 func = uatomic_read(plibc_func);
426 if (func == NULL) {
427 func = dlsym(RTLD_NEXT, "setresgid");
428 if (func == NULL) {
429 fprintf(stderr, "libustfork: unable to find \"setresgid\" symbol\n");
430 errno = ENOSYS;
431 return -1;
432 }
433 uatomic_set(&plibc_func, func);
434 }
435
436 /* Do the real setresgid */
437 retval = func(rgid, egid, sgid);
438 saved_errno = errno;
439
440 lttng_ust_after_setresgid();
441
442 errno = saved_errno;
443 return retval;
444 }
445
446 #elif defined (__FreeBSD__)
447
448 pid_t rfork(int flags)
449 {
450 static pid_t (*plibc_func)(int flags) = NULL;
451 pid_t (*func)(int flags);
452 sigset_t sigset;
453 pid_t retval;
454 int saved_errno;
455
456 func = uatomic_read(plibc_func);
457 if (func == NULL) {
458 func = dlsym(RTLD_NEXT, "rfork");
459 if (func == NULL) {
460 fprintf(stderr, "libustfork: unable to find \"rfork\" symbol\n");
461 errno = ENOSYS;
462 return -1;
463 }
464 uatomic_set(&plibc_func, func);
465 }
466
467 lttng_ust_before_fork(&sigset);
468 /* Do the real rfork */
469 retval = func(flags);
470 saved_errno = errno;
471 if (retval == 0) {
472 /* child */
473 lttng_ust_after_fork_child(&sigset);
474 } else {
475 lttng_ust_after_fork_parent(&sigset);
476 }
477 errno = saved_errno;
478 return retval;
479 }
480
481 /*
482 * On BSD, no need to override vfork, because it runs in the context of
483 * the parent, with parent waiting until execve or exit is executed in
484 * the child.
485 */
486
487 #else
488 #warning "Unknown OS. You might want to ensure that fork/clone/vfork/fork handling is complete."
489 #endif
This page took 0.03797 seconds and 3 git commands to generate.