Commit | Line | Data |
---|---|---|
e822f505 | 1 | /* |
c0c0989a MJ |
2 | * SPDX-License-Identifier: LGPL-2.1-only |
3 | * | |
e822f505 | 4 | * Copyright (C) 2009 Pierre-Marc Fournier |
3678c8aa | 5 | * Copyright (C) 2011-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
2d99476b PMF |
6 | */ |
7 | ||
ae4b659d | 8 | #include <ust-dlfcn.h> |
2d99476b PMF |
9 | #include <unistd.h> |
10 | #include <stdio.h> | |
df793c55 | 11 | #include <signal.h> |
616ed36a PMF |
12 | #include <sched.h> |
13 | #include <stdarg.h> | |
eb2b066f | 14 | #include <errno.h> |
2d99476b | 15 | |
d0c8f180 | 16 | #include <lttng/ust-fork.h> |
e822f505 | 17 | |
2d99476b PMF |
18 | pid_t fork(void) |
19 | { | |
20 | static pid_t (*plibc_func)(void) = NULL; | |
7f0aeeba | 21 | sigset_t sigset; |
2d99476b | 22 | pid_t retval; |
111902ab | 23 | int saved_errno; |
2d99476b | 24 | |
e822f505 | 25 | if (plibc_func == NULL) { |
2d99476b | 26 | plibc_func = dlsym(RTLD_NEXT, "fork"); |
e822f505 MD |
27 | if (plibc_func == NULL) { |
28 | fprintf(stderr, "libustfork: unable to find \"fork\" symbol\n"); | |
3678c8aa | 29 | errno = ENOSYS; |
2c10b7fd | 30 | return -1; |
2d99476b PMF |
31 | } |
32 | } | |
33 | ||
d0c8f180 | 34 | lttng_ust_before_fork(&sigset); |
df793c55 | 35 | /* Do the real fork */ |
2d99476b | 36 | retval = plibc_func(); |
111902ab | 37 | saved_errno = errno; |
e822f505 | 38 | if (retval == 0) { |
df793c55 | 39 | /* child */ |
d0c8f180 | 40 | lttng_ust_after_fork_child(&sigset); |
e822f505 | 41 | } else { |
d0c8f180 | 42 | lttng_ust_after_fork_parent(&sigset); |
df793c55 | 43 | } |
111902ab | 44 | errno = saved_errno; |
2d99476b PMF |
45 | return retval; |
46 | } | |
97b042a3 | 47 | |
2f6150e9 MD |
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; | |
111902ab | 53 | int saved_errno; |
2f6150e9 MD |
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 | ||
d0c8f180 | 64 | lttng_ust_before_fork(&sigset); |
2f6150e9 MD |
65 | /* Do the real daemon call */ |
66 | retval = plibc_func(nochdir, noclose); | |
111902ab | 67 | saved_errno = errno; |
2f6150e9 MD |
68 | if (retval == 0) { |
69 | /* child, parent called _exit() directly */ | |
d0c8f180 | 70 | lttng_ust_after_fork_child(&sigset); |
2f6150e9 MD |
71 | } else { |
72 | /* on error in the parent */ | |
d0c8f180 | 73 | lttng_ust_after_fork_parent(&sigset); |
2f6150e9 | 74 | } |
111902ab | 75 | errno = saved_errno; |
2f6150e9 MD |
76 | return retval; |
77 | } | |
78 | ||
fca2f191 MJ |
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 | ||
d0c8f180 | 98 | lttng_ust_after_setuid(); |
fca2f191 MJ |
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 | ||
d0c8f180 | 123 | lttng_ust_after_setgid(); |
fca2f191 MJ |
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 | ||
d0c8f180 | 148 | lttng_ust_after_seteuid(); |
fca2f191 MJ |
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 | ||
d0c8f180 | 173 | lttng_ust_after_setegid(); |
fca2f191 MJ |
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 | ||
d0c8f180 | 198 | lttng_ust_after_setreuid(); |
fca2f191 MJ |
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 | ||
d0c8f180 | 223 | lttng_ust_after_setregid(); |
fca2f191 MJ |
224 | |
225 | errno = saved_errno; | |
226 | return retval; | |
227 | } | |
228 | ||
939c89cb MD |
229 | #ifdef __linux__ |
230 | ||
231 | struct user_desc; | |
232 | ||
e822f505 | 233 | struct ustfork_clone_info { |
616ed36a PMF |
234 | int (*fn)(void *); |
235 | void *arg; | |
7f0aeeba | 236 | sigset_t sigset; |
616ed36a PMF |
237 | }; |
238 | ||
239 | static int clone_fn(void *arg) | |
240 | { | |
e822f505 | 241 | struct ustfork_clone_info *info = (struct ustfork_clone_info *) arg; |
616ed36a PMF |
242 | |
243 | /* clone is now done and we are in child */ | |
d0c8f180 | 244 | lttng_ust_after_fork_child(&info->sigset); |
616ed36a PMF |
245 | return info->fn(info->arg); |
246 | } | |
247 | ||
248 | int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...) | |
249 | { | |
e822f505 MD |
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 */ | |
616ed36a PMF |
254 | pid_t *ptid; |
255 | struct user_desc *tls; | |
256 | pid_t *ctid; | |
e822f505 | 257 | /* end of var args */ |
616ed36a | 258 | va_list ap; |
e822f505 | 259 | int retval; |
111902ab | 260 | int saved_errno; |
616ed36a PMF |
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 | ||
e822f505 | 268 | if (plibc_func == NULL) { |
616ed36a | 269 | plibc_func = dlsym(RTLD_NEXT, "clone"); |
e822f505 MD |
270 | if (plibc_func == NULL) { |
271 | fprintf(stderr, "libustfork: unable to find \"clone\" symbol.\n"); | |
3678c8aa | 272 | errno = ENOSYS; |
616ed36a PMF |
273 | return -1; |
274 | } | |
275 | } | |
276 | ||
e822f505 MD |
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); | |
111902ab | 284 | saved_errno = errno; |
e822f505 MD |
285 | } else { |
286 | /* Creating a real process, we need to intervene. */ | |
3fd2b913 | 287 | struct ustfork_clone_info info = { .fn = fn, .arg = arg }; |
616ed36a | 288 | |
d0c8f180 | 289 | lttng_ust_before_fork(&info.sigset); |
e822f505 MD |
290 | retval = plibc_func(clone_fn, child_stack, flags, &info, |
291 | ptid, tls, ctid); | |
111902ab | 292 | saved_errno = errno; |
e822f505 | 293 | /* The child doesn't get here. */ |
d0c8f180 | 294 | lttng_ust_after_fork_parent(&info.sigset); |
616ed36a | 295 | } |
111902ab | 296 | errno = saved_errno; |
616ed36a PMF |
297 | return retval; |
298 | } | |
939c89cb | 299 | |
735bef47 MJ |
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 | ||
d0c8f180 | 319 | lttng_ust_after_setns(); |
735bef47 MJ |
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 | ||
d0c8f180 | 344 | lttng_ust_after_unshare(); |
735bef47 MJ |
345 | |
346 | errno = saved_errno; | |
347 | return retval; | |
348 | } | |
349 | ||
fca2f191 MJ |
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 | ||
d0c8f180 | 369 | lttng_ust_after_setresuid(); |
fca2f191 MJ |
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 | ||
d0c8f180 | 394 | lttng_ust_after_setresgid(); |
fca2f191 MJ |
395 | |
396 | errno = saved_errno; | |
397 | return retval; | |
398 | } | |
399 | ||
939c89cb MD |
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; | |
111902ab | 407 | int saved_errno; |
939c89cb MD |
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"); | |
3678c8aa | 413 | errno = ENOSYS; |
939c89cb MD |
414 | return -1; |
415 | } | |
416 | } | |
417 | ||
d0c8f180 | 418 | lttng_ust_before_fork(&sigset); |
939c89cb MD |
419 | /* Do the real rfork */ |
420 | retval = plibc_func(); | |
111902ab | 421 | saved_errno = errno; |
939c89cb MD |
422 | if (retval == 0) { |
423 | /* child */ | |
d0c8f180 | 424 | lttng_ust_after_fork_child(&sigset); |
939c89cb | 425 | } else { |
d0c8f180 | 426 | lttng_ust_after_fork_parent(&sigset); |
939c89cb | 427 | } |
111902ab | 428 | errno = saved_errno; |
939c89cb MD |
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 |