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