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