Add userspace vuid/vgid contexts
[lttng-ust.git] / liblttng-ust-fork / ustfork.c
CommitLineData
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>
eb2b066f 27#include <errno.h>
2d99476b 28
4318ae1b 29#include <lttng/ust.h>
e822f505 30
2d99476b
PMF
31pid_t fork(void)
32{
33 static pid_t (*plibc_func)(void) = NULL;
7f0aeeba 34 sigset_t sigset;
2d99476b 35 pid_t retval;
111902ab 36 int saved_errno;
2d99476b 37
e822f505 38 if (plibc_func == NULL) {
2d99476b 39 plibc_func = dlsym(RTLD_NEXT, "fork");
e822f505
MD
40 if (plibc_func == NULL) {
41 fprintf(stderr, "libustfork: unable to find \"fork\" symbol\n");
3678c8aa 42 errno = ENOSYS;
2c10b7fd 43 return -1;
2d99476b
PMF
44 }
45 }
46
7f0aeeba 47 ust_before_fork(&sigset);
df793c55 48 /* Do the real fork */
2d99476b 49 retval = plibc_func();
111902ab 50 saved_errno = errno;
e822f505 51 if (retval == 0) {
df793c55 52 /* child */
7f0aeeba 53 ust_after_fork_child(&sigset);
e822f505 54 } else {
7f0aeeba 55 ust_after_fork_parent(&sigset);
df793c55 56 }
111902ab 57 errno = saved_errno;
2d99476b
PMF
58 return retval;
59}
97b042a3 60
2f6150e9
MD
61int daemon(int nochdir, int noclose)
62{
63 static int (*plibc_func)(int nochdir, int noclose) = NULL;
64 sigset_t sigset;
65 int retval;
111902ab 66 int saved_errno;
2f6150e9
MD
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);
111902ab 80 saved_errno = errno;
2f6150e9
MD
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 }
111902ab 88 errno = saved_errno;
2f6150e9
MD
89 return retval;
90}
91
fca2f191
MJ
92int 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
117int 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
142int 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
167int 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
192int 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
217int 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
939c89cb
MD
242#ifdef __linux__
243
244struct user_desc;
245
e822f505 246struct ustfork_clone_info {
616ed36a
PMF
247 int (*fn)(void *);
248 void *arg;
7f0aeeba 249 sigset_t sigset;
616ed36a
PMF
250};
251
252static int clone_fn(void *arg)
253{
e822f505 254 struct ustfork_clone_info *info = (struct ustfork_clone_info *) arg;
616ed36a
PMF
255
256 /* clone is now done and we are in child */
7f0aeeba 257 ust_after_fork_child(&info->sigset);
616ed36a
PMF
258 return info->fn(info->arg);
259}
260
261int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...)
262{
e822f505
MD
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 */
616ed36a
PMF
267 pid_t *ptid;
268 struct user_desc *tls;
269 pid_t *ctid;
e822f505 270 /* end of var args */
616ed36a 271 va_list ap;
e822f505 272 int retval;
111902ab 273 int saved_errno;
616ed36a
PMF
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
e822f505 281 if (plibc_func == NULL) {
616ed36a 282 plibc_func = dlsym(RTLD_NEXT, "clone");
e822f505
MD
283 if (plibc_func == NULL) {
284 fprintf(stderr, "libustfork: unable to find \"clone\" symbol.\n");
3678c8aa 285 errno = ENOSYS;
616ed36a
PMF
286 return -1;
287 }
288 }
289
e822f505
MD
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);
111902ab 297 saved_errno = errno;
e822f505
MD
298 } else {
299 /* Creating a real process, we need to intervene. */
3fd2b913 300 struct ustfork_clone_info info = { .fn = fn, .arg = arg };
616ed36a 301
7f0aeeba 302 ust_before_fork(&info.sigset);
e822f505
MD
303 retval = plibc_func(clone_fn, child_stack, flags, &info,
304 ptid, tls, ctid);
111902ab 305 saved_errno = errno;
e822f505 306 /* The child doesn't get here. */
7f0aeeba 307 ust_after_fork_parent(&info.sigset);
616ed36a 308 }
111902ab 309 errno = saved_errno;
616ed36a
PMF
310 return retval;
311}
939c89cb 312
735bef47
MJ
313int 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
338int 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
fca2f191
MJ
363int 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
388int 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
939c89cb
MD
413#elif defined (__FreeBSD__)
414
415pid_t rfork(int flags)
416{
417 static pid_t (*plibc_func)(void) = NULL;
418 sigset_t sigset;
419 pid_t retval;
111902ab 420 int saved_errno;
939c89cb
MD
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");
3678c8aa 426 errno = ENOSYS;
939c89cb
MD
427 return -1;
428 }
429 }
430
431 ust_before_fork(&sigset);
432 /* Do the real rfork */
433 retval = plibc_func();
111902ab 434 saved_errno = errno;
939c89cb
MD
435 if (retval == 0) {
436 /* child */
437 ust_after_fork_child(&sigset);
438 } else {
439 ust_after_fork_parent(&sigset);
440 }
111902ab 441 errno = saved_errno;
939c89cb
MD
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.048526 seconds and 4 git commands to generate.