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