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