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