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