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