libsecurity: Simplify struct ace_condition_script
[Samba.git] / third_party / uid_wrapper / uid_wrapper.c
blobca578e61f2e7cd7c65cf27cd2b7714566d3f2a6d
1 /*
2 * Copyright (c) 2009 Andrew Tridgell
3 * Copyright (c) 2011-2013 Andreas Schneider <asn@samba.org>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program 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
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "config.h"
21 #include <errno.h>
22 #include <stdarg.h>
23 #include <stdbool.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <grp.h>
30 #ifdef HAVE_SYS_SYSCALL_H
31 #include <sys/syscall.h>
32 #endif
33 #ifdef HAVE_SYSCALL_H
34 #include <syscall.h>
35 #endif
36 #include <dlfcn.h>
37 #include <limits.h>
39 #include <pthread.h>
41 #ifdef HAVE_GNU_LIB_NAMES_H
42 #include <gnu/lib-names.h>
43 #endif
45 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
46 # define UWRAP_THREAD __thread
47 #else
48 # define UWRAP_THREAD
49 #endif
51 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
52 #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
53 #else
54 #define CONSTRUCTOR_ATTRIBUTE
55 #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
57 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
58 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
59 #else
60 #define DESTRUCTOR_ATTRIBUTE
61 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
63 #ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
64 #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address))
65 #else /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
66 #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
67 #endif /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
69 /* GCC have printf type attribute check. */
70 #ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
71 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
72 #else
73 #define PRINTF_ATTRIBUTE(a,b)
74 #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
76 #ifndef FALL_THROUGH
77 # ifdef HAVE_FALLTHROUGH_ATTRIBUTE
78 # define FALL_THROUGH __attribute__ ((fallthrough))
79 # else /* HAVE_FALLTHROUGH_ATTRIBUTE */
80 # define FALL_THROUGH
81 # endif /* HAVE_FALLTHROUGH_ATTRIBUTE */
82 #endif /* FALL_THROUGH */
84 #define UWRAP_DLIST_ADD(list,item) do { \
85 if (!(list)) { \
86 (item)->prev = NULL; \
87 (item)->next = NULL; \
88 (list) = (item); \
89 } else { \
90 (item)->prev = NULL; \
91 (item)->next = (list); \
92 (list)->prev = (item); \
93 (list) = (item); \
94 } \
95 } while (0)
97 #define UWRAP_DLIST_REMOVE(list,item) do { \
98 if ((list) == (item)) { \
99 (list) = (item)->next; \
100 if (list) { \
101 (list)->prev = NULL; \
103 } else { \
104 if ((item)->prev) { \
105 (item)->prev->next = (item)->next; \
107 if ((item)->next) { \
108 (item)->next->prev = (item)->prev; \
111 (item)->prev = NULL; \
112 (item)->next = NULL; \
113 } while (0)
115 #ifndef SAFE_FREE
116 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
117 #endif
119 /*****************
120 * LOGGING
121 *****************/
123 enum uwrap_dbglvl_e {
124 UWRAP_LOG_ERROR = 0,
125 UWRAP_LOG_WARN,
126 UWRAP_LOG_DEBUG,
127 UWRAP_LOG_TRACE
130 #ifndef HAVE_GETPROGNAME
131 static const char *getprogname(void)
133 #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
134 return program_invocation_short_name;
135 #elif defined(HAVE_GETEXECNAME)
136 return getexecname();
137 #else
138 return NULL;
139 #endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
141 #endif /* HAVE_GETPROGNAME */
143 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
144 # define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __func__, __VA_ARGS__)
146 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...)
148 char buffer[1024];
149 va_list va;
150 const char *d;
151 unsigned int lvl = 0;
152 const char *prefix = "UWRAP";
153 const char *progname = getprogname();
155 d = getenv("UID_WRAPPER_DEBUGLEVEL");
156 if (d != NULL) {
157 lvl = atoi(d);
160 if (lvl < dbglvl) {
161 return;
164 va_start(va, format);
165 vsnprintf(buffer, sizeof(buffer), format, va);
166 va_end(va);
168 switch (dbglvl) {
169 case UWRAP_LOG_ERROR:
170 prefix = "UWRAP_ERROR";
171 break;
172 case UWRAP_LOG_WARN:
173 prefix = "UWRAP_WARN";
174 break;
175 case UWRAP_LOG_DEBUG:
176 prefix = "UWRAP_DEBUG";
177 break;
178 case UWRAP_LOG_TRACE:
179 prefix = "UWRAP_TRACE";
180 break;
183 if (progname == NULL) {
184 progname = "<unknown>";
187 fprintf(stderr,
188 "%s[%s (%u)] - %s: %s\n",
189 prefix,
190 progname,
191 (int)getpid(),
192 function,
193 buffer);
196 /*****************
197 * LIBC
198 *****************/
200 #define LIBC_NAME "libc.so"
202 typedef int (*__libc_setuid)(uid_t uid);
204 typedef uid_t (*__libc_getuid)(void);
206 #ifdef HAVE_SETEUID
207 typedef int (*__libc_seteuid)(uid_t euid);
208 #endif
210 #ifdef HAVE_SETREUID
211 typedef int (*__libc_setreuid)(uid_t ruid, uid_t euid);
212 #endif
214 #ifdef HAVE_SETRESUID
215 typedef int (*__libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
216 #endif
218 #ifdef HAVE_GETRESUID
219 typedef int (*__libc_getresuid)(uid_t *ruid, uid_t *euid, uid_t *suid);
220 #endif
222 typedef uid_t (*__libc_geteuid)(void);
224 typedef int (*__libc_setgid)(gid_t gid);
226 typedef gid_t (*__libc_getgid)(void);
228 #ifdef HAVE_SETEGID
229 typedef int (*__libc_setegid)(uid_t egid);
230 #endif
232 #ifdef HAVE_SETREGID
233 typedef int (*__libc_setregid)(uid_t rgid, uid_t egid);
234 #endif
236 #ifdef HAVE_SETRESGID
237 typedef int (*__libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
238 #endif
240 #ifdef HAVE_GETRESGID
241 typedef int (*__libc_getresgid)(gid_t *rgid, gid_t *egid, gid_t *sgid);
242 #endif
244 typedef gid_t (*__libc_getegid)(void);
246 typedef int (*__libc_getgroups)(int size, gid_t list[]);
247 #ifdef HAVE___GETGROUPS_CHK
248 typedef int (*__libc___getgroups_chk)(int size, gid_t list[], size_t listlen);
249 #endif
251 typedef int (*__libc_setgroups)(size_t size, const gid_t *list);
253 #ifdef HAVE_SYSCALL
254 typedef long int (*__libc_syscall)(long int sysno, ...);
255 #endif
257 #define UWRAP_SYMBOL_ENTRY(i) \
258 union { \
259 __libc_##i f; \
260 void *obj; \
261 } _libc_##i
263 struct uwrap_libc_symbols {
264 UWRAP_SYMBOL_ENTRY(setuid);
265 UWRAP_SYMBOL_ENTRY(getuid);
266 #ifdef HAVE_SETEUID
267 UWRAP_SYMBOL_ENTRY(seteuid);
268 #endif
269 #ifdef HAVE_SETREUID
270 UWRAP_SYMBOL_ENTRY(setreuid);
271 #endif
272 #ifdef HAVE_SETRESUID
273 UWRAP_SYMBOL_ENTRY(setresuid);
274 #endif
275 #ifdef HAVE_GETRESUID
276 UWRAP_SYMBOL_ENTRY(getresuid);
277 #endif
278 UWRAP_SYMBOL_ENTRY(geteuid);
279 UWRAP_SYMBOL_ENTRY(setgid);
280 UWRAP_SYMBOL_ENTRY(getgid);
281 #ifdef HAVE_SETEGID
282 UWRAP_SYMBOL_ENTRY(setegid);
283 #endif
284 #ifdef HAVE_SETREGID
285 UWRAP_SYMBOL_ENTRY(setregid);
286 #endif
287 #ifdef HAVE_SETRESGID
288 UWRAP_SYMBOL_ENTRY(setresgid);
289 #endif
290 #ifdef HAVE_GETRESGID
291 UWRAP_SYMBOL_ENTRY(getresgid);
292 #endif
293 UWRAP_SYMBOL_ENTRY(getegid);
294 UWRAP_SYMBOL_ENTRY(getgroups);
295 #ifdef HAVE___GETGROUPS_CHK
296 UWRAP_SYMBOL_ENTRY(__getgroups_chk);
297 #endif
298 UWRAP_SYMBOL_ENTRY(setgroups);
299 #ifdef HAVE_SYSCALL
300 UWRAP_SYMBOL_ENTRY(syscall);
301 #endif
303 #undef UWRAP_SYMBOL_ENTRY
305 #define UWRAP_SYMBOL_ENTRY(i) \
306 union { \
307 __rtld_default_##i f; \
308 void *obj; \
309 } _rtld_default_##i
311 #ifdef HAVE_SYSCALL
312 typedef bool (*__rtld_default_socket_wrapper_syscall_valid)(long int sysno);
313 typedef long int (*__rtld_default_socket_wrapper_syscall_va)(long int sysno,
314 va_list va);
315 #endif
317 struct uwrap_rtld_default_symbols {
318 #ifdef HAVE_SYSCALL
319 UWRAP_SYMBOL_ENTRY(socket_wrapper_syscall_valid);
320 UWRAP_SYMBOL_ENTRY(socket_wrapper_syscall_va);
321 #else
322 uint8_t dummy;
323 #endif
325 #undef UWRAP_SYMBOL_ENTRY
327 /*****************
328 * LIBPTHREAD
329 *****************/
330 /* Yeah... I'm pig. I overloading macro here... So what? */
331 #define UWRAP_SYMBOL_ENTRY(i) \
332 union { \
333 __libpthread_##i f; \
334 void *obj; \
335 } _libpthread_##i
337 typedef int (*__libpthread_pthread_create)(pthread_t *thread,
338 const pthread_attr_t *attr,
339 void *(*start_routine) (void *),
340 void *arg);
341 typedef void (*__libpthread_pthread_exit)(void *retval);
343 struct uwrap_libpthread_symbols {
344 UWRAP_SYMBOL_ENTRY(pthread_create);
345 UWRAP_SYMBOL_ENTRY(pthread_exit);
347 #undef UWRAP_SYMBOL_ENTRY
350 * We keep the virtualised euid/egid/groups information here
352 struct uwrap_thread {
353 bool enabled;
355 uid_t ruid;
356 uid_t euid;
357 uid_t suid;
359 gid_t rgid;
360 gid_t egid;
361 gid_t sgid;
363 int ngroups;
364 gid_t *groups;
366 struct uwrap_thread *next;
367 struct uwrap_thread *prev;
370 struct uwrap {
371 struct {
372 void *handle;
373 struct uwrap_libc_symbols symbols;
374 } libc;
376 struct {
377 struct uwrap_rtld_default_symbols symbols;
378 } rtld_default;
380 struct {
381 void *handle;
382 struct uwrap_libpthread_symbols symbols;
383 } libpthread;
385 bool initialised;
387 /* Real uid and gid of user who run uid wrapper */
388 uid_t myuid;
389 gid_t mygid;
391 struct uwrap_thread *ids;
394 static struct uwrap uwrap;
396 /* Shortcut to the list item */
397 static UWRAP_THREAD struct uwrap_thread *uwrap_tls_id;
399 /* The mutex or accessing the id */
400 static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
402 #define uwrap_init_mutex(m) _uwrap_init_mutex(m, #m)
403 static int _uwrap_init_mutex(pthread_mutex_t *m, const char *name)
405 pthread_mutexattr_t ma;
406 bool need_destroy = false;
407 int ret = 0;
409 #define __CHECK(cmd) \
410 do { \
411 ret = cmd; \
412 if (ret != 0) { \
413 UWRAP_LOG(UWRAP_LOG_ERROR, \
414 "%s: %s - failed %d", \
415 name, \
416 #cmd, \
417 ret); \
418 goto done; \
420 } while (0)
422 *m = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
423 __CHECK(pthread_mutexattr_init(&ma));
424 need_destroy = true;
425 __CHECK(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK));
426 __CHECK(pthread_mutex_init(m, &ma));
427 done:
428 if (need_destroy) {
429 pthread_mutexattr_destroy(&ma);
431 return ret;
434 #define uwrap_mutex_lock(m) _uwrap_mutex_lock(m, #m, __func__, __LINE__)
435 static void _uwrap_mutex_lock(pthread_mutex_t *mutex,
436 const char *name,
437 const char *caller,
438 unsigned line)
440 int ret;
442 ret = pthread_mutex_lock(mutex);
443 if (ret != 0) {
444 UWRAP_LOG(UWRAP_LOG_ERROR,
445 "PID(%d):PPID(%d): %s(%u): Couldn't lock pthread "
446 "mutex(%s) - %s",
447 getpid(),
448 getppid(),
449 caller,
450 line,
451 name,
452 strerror(ret));
453 abort();
457 #define uwrap_mutex_unlock(m) _uwrap_mutex_unlock(m, #m, __func__, __LINE__)
458 static void _uwrap_mutex_unlock(pthread_mutex_t *mutex,
459 const char *name,
460 const char *caller,
461 unsigned line)
463 int ret;
465 ret = pthread_mutex_unlock(mutex);
466 if (ret != 0) {
467 UWRAP_LOG(UWRAP_LOG_ERROR,
468 "PID(%d):PPID(%d): %s(%u): Couldn't unlock pthread "
469 "mutex(%s) - %s",
470 getpid(),
471 getppid(),
472 caller,
473 line,
474 name,
475 strerror(ret));
476 abort();
480 #define UWRAP_LOCK(m) \
481 do { \
482 uwrap_mutex_lock(&(m##_mutex)); \
483 } while (0)
485 #define UWRAP_UNLOCK(m) \
486 do { \
487 uwrap_mutex_unlock(&(m##_mutex)); \
488 } while (0)
490 /* Add new global locks here please */
491 #define UWRAP_REINIT_ALL \
492 do { \
493 int ret; \
494 ret = uwrap_init_mutex(&uwrap_id_mutex); \
495 if (ret != 0) \
496 exit(-1); \
497 } while (0)
499 /* Add new global locks here please */
500 #define UWRAP_LOCK_ALL \
501 do { \
502 UWRAP_LOCK(uwrap_id); \
503 } while (0)
505 #define UWRAP_UNLOCK_ALL \
506 do { \
507 UWRAP_UNLOCK(uwrap_id); \
508 } while (0)
510 /*********************************************************
511 * UWRAP PROTOTYPES
512 *********************************************************/
514 bool uid_wrapper_enabled(void);
515 #if ! defined(HAVE_CONSTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_INIT)
516 /* xlC and other oldschool compilers support (only) this */
517 #pragma init (uwrap_constructor)
518 #endif
519 void uwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
520 #if ! defined(HAVE_DESTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_FINI)
521 #pragma fini (uwrap_destructor)
522 #endif
523 void uwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
525 /*********************************************************
526 * UWRAP LIBC LOADER FUNCTIONS
527 *********************************************************/
529 enum uwrap_lib {
530 UWRAP_LIBC,
531 UWRAP_LIBPTHREAD,
534 static void *uwrap_load_lib_handle(enum uwrap_lib lib)
536 int flags = RTLD_LAZY;
537 void *handle = NULL;
538 int i;
540 #ifdef RTLD_DEEPBIND
541 const char *env_preload = getenv("LD_PRELOAD");
542 const char *env_deepbind = getenv("UID_WRAPPER_DISABLE_DEEPBIND");
543 bool enable_deepbind = true;
545 /* Don't do a deepbind if we run with libasan */
546 if (env_preload != NULL && strlen(env_preload) < 1024) {
547 const char *p = strstr(env_preload, "libasan.so");
548 if (p != NULL) {
549 enable_deepbind = false;
553 if (env_deepbind != NULL && strlen(env_deepbind) >= 1) {
554 enable_deepbind = false;
557 if (enable_deepbind) {
558 flags |= RTLD_DEEPBIND;
560 #endif
562 switch (lib) {
563 case UWRAP_LIBC:
564 handle = uwrap.libc.handle;
565 #ifdef LIBC_SO
566 if (handle == NULL) {
567 handle = dlopen(LIBC_SO, flags);
569 uwrap.libc.handle = handle;
571 #endif
572 if (handle == NULL) {
573 for (i = 10; i >= 0; i--) {
574 char soname[256] = {0};
576 snprintf(soname, sizeof(soname), "libc.so.%d", i);
577 handle = dlopen(soname, flags);
578 if (handle != NULL) {
579 break;
582 /* glibc on Alpha and IA64 is libc.so.6.1 */
583 snprintf(soname, sizeof(soname), "libc.so.%d.1", i);
584 handle = dlopen(soname, flags);
585 if (handle != NULL) {
586 break;
590 uwrap.libc.handle = handle;
592 break;
593 case UWRAP_LIBPTHREAD:
594 handle = uwrap.libpthread.handle;
595 if (handle == NULL) {
596 #ifdef RTLD_NEXT
598 * Because thread sanatizer also overloads
599 * pthread_create() and pthread_exit() we need use
600 * RTLD_NEXT instead of libpthread.so.0
602 handle = uwrap.libpthread.handle = RTLD_NEXT;
603 #else
604 handle = dlopen("libpthread.so.0", flags);
605 #endif
606 if (handle != NULL) {
607 break;
610 break;
613 if (handle == NULL) {
614 #ifdef RTLD_NEXT
615 switch (lib) {
616 case UWRAP_LIBC:
617 handle = uwrap.libc.handle = RTLD_NEXT;
618 break;
619 case UWRAP_LIBPTHREAD:
620 handle = uwrap.libpthread.handle = RTLD_NEXT;
621 break;
623 #else
624 fprintf(stderr,
625 "Failed to dlopen library: %s\n",
626 dlerror());
627 exit(-1);
628 #endif
631 return handle;
634 static void *_uwrap_bind_symbol(enum uwrap_lib lib, const char *fn_name)
636 void *handle;
637 void *func;
639 handle = uwrap_load_lib_handle(lib);
641 func = dlsym(handle, fn_name);
642 if (func == NULL) {
643 fprintf(stderr,
644 "Failed to find %s: %s\n",
645 fn_name, dlerror());
646 exit(-1);
649 return func;
652 #define uwrap_bind_symbol_libc(sym_name) \
653 if (uwrap.libc.symbols._libc_##sym_name.obj == NULL) { \
654 uwrap.libc.symbols._libc_##sym_name.obj = \
655 _uwrap_bind_symbol(UWRAP_LIBC, #sym_name); \
658 #define uwrap_bind_symbol_libpthread(sym_name) \
659 if (uwrap.libpthread.symbols._libpthread_##sym_name.obj == NULL) { \
660 uwrap.libpthread.symbols._libpthread_##sym_name.obj = \
661 _uwrap_bind_symbol(UWRAP_LIBPTHREAD, #sym_name); \
664 #define uwrap_bind_symbol_rtld_default_optional(sym_name) \
665 if (uwrap.rtld_default.symbols._rtld_default_##sym_name.obj == NULL) { \
666 uwrap.rtld_default.symbols._rtld_default_##sym_name.obj = \
667 dlsym(RTLD_DEFAULT, #sym_name); \
670 /* JEMALLOC: This tells uid_wrapper if it should handle syscall() */
671 static bool uwrap_handle_syscall;
673 /* DO NOT call this function during library initialization! */
674 static void __uwrap_bind_symbol_all_once(void)
676 uwrap_bind_symbol_libc(setuid);
677 uwrap_bind_symbol_libc(getuid);
678 #ifdef HAVE_SETEUID
679 uwrap_bind_symbol_libc(seteuid);
680 #endif
681 #ifdef HAVE_SETREUID
682 uwrap_bind_symbol_libc(setreuid);
683 #endif
684 #ifdef HAVE_SETRESUID
685 uwrap_bind_symbol_libc(setresuid);
686 #endif
687 #ifdef HAVE_GETRESUID
688 uwrap_bind_symbol_libc(getresuid);
689 #endif
690 uwrap_bind_symbol_libc(geteuid);
691 uwrap_bind_symbol_libc(setgid);
692 uwrap_bind_symbol_libc(getgid);
693 #ifdef HAVE_SETEGID
694 uwrap_bind_symbol_libc(setegid);
695 #endif
696 #ifdef HAVE_SETREGID
697 uwrap_bind_symbol_libc(setregid);
698 #endif
700 #ifdef HAVE_SETRESGID
701 uwrap_bind_symbol_libc(setresgid);
702 #endif
703 #ifdef HAVE_GETRESGID
704 uwrap_bind_symbol_libc(setresgid);
705 #endif
706 uwrap_bind_symbol_libc(getegid);
707 uwrap_bind_symbol_libc(getgroups);
708 uwrap_bind_symbol_libc(setgroups);
709 #ifdef HAVE_SYSCALL
710 uwrap_bind_symbol_libc(syscall);
711 uwrap_bind_symbol_rtld_default_optional(socket_wrapper_syscall_valid);
712 uwrap_bind_symbol_rtld_default_optional(socket_wrapper_syscall_va);
713 #endif
714 uwrap_bind_symbol_libpthread(pthread_create);
715 uwrap_bind_symbol_libpthread(pthread_exit);
717 uwrap_handle_syscall = true;
720 static void uwrap_bind_symbol_all(void)
722 static pthread_once_t all_symbol_binding_once = PTHREAD_ONCE_INIT;
724 pthread_once(&all_symbol_binding_once, __uwrap_bind_symbol_all_once);
728 * IMPORTANT
730 * Functions expeciall from libc need to be loaded individually, you can't load
731 * all at once or gdb will segfault at startup. The same applies to valgrind and
732 * has probably something todo with with the linker.
733 * So we need load each function at the point it is called the first time.
735 static int libc_setuid(uid_t uid)
737 uwrap_bind_symbol_all();
739 return uwrap.libc.symbols._libc_setuid.f(uid);
742 static uid_t libc_getuid(void)
744 uwrap_bind_symbol_all();
746 return uwrap.libc.symbols._libc_getuid.f();
749 #ifdef HAVE_SETEUID
750 static int libc_seteuid(uid_t euid)
752 uwrap_bind_symbol_all();
754 return uwrap.libc.symbols._libc_seteuid.f(euid);
756 #endif
758 #ifdef HAVE_SETREUID
759 static int libc_setreuid(uid_t ruid, uid_t euid)
761 uwrap_bind_symbol_all();
763 return uwrap.libc.symbols._libc_setreuid.f(ruid, euid);
765 #endif
767 #ifdef HAVE_SETRESUID
768 static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
770 uwrap_bind_symbol_all();
772 return uwrap.libc.symbols._libc_setresuid.f(ruid, euid, suid);
774 #endif
776 #ifdef HAVE_GETRESUID
777 static int libc_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
779 uwrap_bind_symbol_all();
781 return uwrap.libc.symbols._libc_getresuid.f(ruid, euid, suid);
783 #endif
785 static uid_t libc_geteuid(void)
787 uwrap_bind_symbol_all();
789 return uwrap.libc.symbols._libc_geteuid.f();
792 static int libc_setgid(gid_t gid)
794 uwrap_bind_symbol_all();
796 return uwrap.libc.symbols._libc_setgid.f(gid);
799 static gid_t libc_getgid(void)
801 uwrap_bind_symbol_all();
803 return uwrap.libc.symbols._libc_getgid.f();
806 #ifdef HAVE_SETEGID
807 static int libc_setegid(gid_t egid)
809 uwrap_bind_symbol_all();
811 return uwrap.libc.symbols._libc_setegid.f(egid);
813 #endif
815 #ifdef HAVE_SETREGID
816 static int libc_setregid(gid_t rgid, gid_t egid)
818 uwrap_bind_symbol_all();
820 return uwrap.libc.symbols._libc_setregid.f(rgid, egid);
822 #endif
824 #ifdef HAVE_SETRESGID
825 static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
827 uwrap_bind_symbol_all();
829 return uwrap.libc.symbols._libc_setresgid.f(rgid, egid, sgid);
831 #endif
833 #ifdef HAVE_GETRESGID
834 static int libc_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
836 uwrap_bind_symbol_all();
838 return uwrap.libc.symbols._libc_getresgid.f(rgid, egid, sgid);
840 #endif
842 static gid_t libc_getegid(void)
844 uwrap_bind_symbol_all();
846 return uwrap.libc.symbols._libc_getegid.f();
849 static int libc_getgroups(int size, gid_t list[])
851 uwrap_bind_symbol_all();
853 return uwrap.libc.symbols._libc_getgroups.f(size, list);
856 #ifdef HAVE___GETGROUPS_CHK
857 static int libc___getgroups_chk(int size, gid_t list[], size_t listlen)
859 uwrap_bind_symbol_libc(__getgroups_chk);
861 return uwrap.libc.symbols._libc___getgroups_chk.f(size,
862 list,
863 listlen);
865 #endif /* HAVE___GETGROUPS_CHK */
867 static int libc_setgroups(size_t size, const gid_t *list)
869 uwrap_bind_symbol_all();
871 return uwrap.libc.symbols._libc_setgroups.f(size, list);
874 #ifdef HAVE_SYSCALL
875 DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
876 static long int libc_vsyscall(long int sysno, va_list va)
878 long int args[8];
879 long int rc;
880 int i;
883 * JEMALLOC:
885 * This is a workaround to prevent a deadlock in jemalloc calling
886 * malloc_init() twice. The first allocation call will trigger a
887 * malloc_init() of jemalloc. The functions calls syscall(SYS_open, ...)
888 * so it goes to socket or uid wrapper. In this code path we need to
889 * avoid any allocation calls. This will prevent the deadlock.
891 * We also need to avoid dlopen() as that would trigger the recursion
892 * into malloc_init(), so we use dlsym(RTLD_NEXT), until we reached
893 * swrap_constructor() or any real socket call at that time
894 * swrap_bind_symbol_all() will replace the function pointer again after
895 * dlopen of libc.
897 if (uwrap_handle_syscall) {
898 uwrap_bind_symbol_all();
899 } else if (uwrap.libc.symbols._libc_syscall.obj == NULL) {
900 uwrap.libc.symbols._libc_syscall.obj = dlsym(RTLD_NEXT,
901 "syscall");
904 for (i = 0; i < 8; i++) {
905 args[i] = va_arg(va, long int);
908 rc = uwrap.libc.symbols._libc_syscall.f(sysno,
909 args[0],
910 args[1],
911 args[2],
912 args[3],
913 args[4],
914 args[5],
915 args[6],
916 args[7]);
918 return rc;
921 static bool uwrap_swrap_syscall_valid(long int sysno)
923 uwrap_bind_symbol_all();
925 if (uwrap.rtld_default.symbols._rtld_default_socket_wrapper_syscall_valid.f == NULL) {
926 return false;
929 return uwrap.rtld_default.symbols._rtld_default_socket_wrapper_syscall_valid.f(
930 sysno);
933 DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
934 static long int uwrap_swrap_syscall_va(long int sysno, va_list va)
936 uwrap_bind_symbol_all();
938 if (uwrap.rtld_default.symbols._rtld_default_socket_wrapper_syscall_va.f == NULL) {
940 * Fallback to libc, if socket_wrapper_vsyscall is not
941 * available.
943 return libc_vsyscall(sysno, va);
946 return uwrap.rtld_default.symbols._rtld_default_socket_wrapper_syscall_va.f(
947 sysno,
948 va);
950 #endif
952 static int libpthread_pthread_create(pthread_t *thread,
953 const pthread_attr_t *attr,
954 void *(*start_routine) (void *),
955 void *arg)
957 uwrap_bind_symbol_all();
958 return uwrap.libpthread.symbols._libpthread_pthread_create.f(thread,
959 attr,
960 start_routine,
961 arg);
965 * This part is "optimistic".
966 * Thread can ends without pthread_exit call.
968 static void libpthread_pthread_exit(void *retval)
970 uwrap_bind_symbol_all();
972 uwrap.libpthread.symbols._libpthread_pthread_exit.f(retval);
975 static void uwrap_pthread_exit(void *retval)
977 struct uwrap_thread *id = uwrap_tls_id;
979 UWRAP_LOG(UWRAP_LOG_DEBUG, "Cleanup thread");
981 UWRAP_LOCK(uwrap_id);
982 if (id == NULL) {
983 UWRAP_UNLOCK(uwrap_id);
984 libpthread_pthread_exit(retval);
985 return;
988 UWRAP_DLIST_REMOVE(uwrap.ids, id);
989 SAFE_FREE(id->groups);
990 SAFE_FREE(id);
991 uwrap_tls_id = NULL;
993 UWRAP_UNLOCK(uwrap_id);
995 libpthread_pthread_exit(retval);
998 void pthread_exit(void *retval)
1000 if (!uid_wrapper_enabled()) {
1001 libpthread_pthread_exit(retval);
1004 uwrap_pthread_exit(retval);
1006 /* Calm down gcc warning. */
1007 exit(666);
1010 struct uwrap_pthread_create_args {
1011 struct uwrap_thread *id;
1012 void *(*start_routine) (void *);
1013 void *arg;
1016 static void *uwrap_pthread_create_start(void *_a)
1018 struct uwrap_pthread_create_args *a =
1019 (struct uwrap_pthread_create_args *)_a;
1020 void *(*start_routine) (void *) = a->start_routine;
1021 void *arg = a->arg;
1022 struct uwrap_thread *id = a->id;
1024 SAFE_FREE(a);
1026 uwrap_tls_id = id;
1028 return start_routine(arg);
1031 static int uwrap_pthread_create(pthread_t *thread,
1032 const pthread_attr_t *attr,
1033 void *(*start_routine) (void *),
1034 void *arg)
1036 struct uwrap_pthread_create_args *args;
1037 struct uwrap_thread *src_id = uwrap_tls_id;
1038 int ret;
1040 args = malloc(sizeof(struct uwrap_pthread_create_args));
1041 if (args == NULL) {
1042 UWRAP_LOG(UWRAP_LOG_ERROR,
1043 "uwrap_pthread_create: Unable to allocate memory");
1044 errno = ENOMEM;
1045 return -1;
1047 args->start_routine = start_routine;
1048 args->arg = arg;
1050 args->id = calloc(1, sizeof(struct uwrap_thread));
1051 if (args->id == NULL) {
1052 SAFE_FREE(args);
1053 UWRAP_LOG(UWRAP_LOG_ERROR,
1054 "uwrap_pthread_create: Unable to allocate memory");
1055 errno = ENOMEM;
1056 return -1;
1059 UWRAP_LOCK(uwrap_id);
1061 args->id->groups = calloc(src_id->ngroups, sizeof(gid_t));
1062 if (args->id->groups == NULL) {
1063 UWRAP_UNLOCK(uwrap_id);
1064 SAFE_FREE(args->id);
1065 SAFE_FREE(args);
1066 UWRAP_LOG(UWRAP_LOG_ERROR,
1067 "uwrap_pthread_create: Unable to allocate memory again");
1068 errno = ENOMEM;
1069 return -1;
1072 args->id->ruid = src_id->ruid;
1073 args->id->euid = src_id->euid;
1074 args->id->suid = src_id->suid;
1076 args->id->rgid = src_id->rgid;
1077 args->id->egid = src_id->egid;
1078 args->id->sgid = src_id->sgid;
1080 args->id->enabled = src_id->enabled;
1082 args->id->ngroups = src_id->ngroups;
1083 if (src_id->groups != NULL) {
1084 memcpy(args->id->groups, src_id->groups,
1085 sizeof(gid_t) * src_id->ngroups);
1086 } else {
1087 SAFE_FREE(args->id->groups);
1090 UWRAP_DLIST_ADD(uwrap.ids, args->id);
1091 UWRAP_UNLOCK(uwrap_id);
1093 ret = libpthread_pthread_create(thread, attr,
1094 uwrap_pthread_create_start,
1095 args);
1096 if (ret != 0) {
1097 return ret;
1100 return ret;
1103 int pthread_create(pthread_t *thread,
1104 const pthread_attr_t *attr,
1105 void *(*start_routine) (void *),
1106 void *arg)
1108 if (!uid_wrapper_enabled()) {
1109 return libpthread_pthread_create(thread,
1110 attr,
1111 start_routine,
1112 arg);
1115 return uwrap_pthread_create(thread,
1116 attr,
1117 start_routine,
1118 arg);
1121 /*********************************************************
1122 * UWRAP ID HANDLING
1123 *********************************************************/
1125 #define GROUP_STRING_SIZE 16384
1126 #define GROUP_MAX_COUNT (GROUP_STRING_SIZE / (10 + 1))
1129 * This function exports all the IDs of the current user so if
1130 * we fork and then exec we can setup uid_wrapper in the new process
1131 * with those IDs.
1133 static void uwrap_export_ids(struct uwrap_thread *id)
1135 char groups_str[GROUP_STRING_SIZE] = {0};
1136 size_t groups_str_size = sizeof(groups_str);
1137 char unsigned_str[16] = {0}; /* We need 10 + 1 (+ 1) */
1138 int i;
1140 /* UIDS */
1141 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->ruid);
1142 setenv("UID_WRAPPER_INITIAL_RUID", unsigned_str, 1);
1144 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->euid);
1145 setenv("UID_WRAPPER_INITIAL_EUID", unsigned_str, 1);
1147 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->suid);
1148 setenv("UID_WRAPPER_INITIAL_SUID", unsigned_str, 1);
1150 /* GIDS */
1151 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->rgid);
1152 setenv("UID_WRAPPER_INITIAL_RGID", unsigned_str, 1);
1154 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->egid);
1155 setenv("UID_WRAPPER_INITIAL_EGID", unsigned_str, 1);
1157 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->sgid);
1158 setenv("UID_WRAPPER_INITIAL_SGID", unsigned_str, 1);
1160 if (id->ngroups > GROUP_MAX_COUNT) {
1161 UWRAP_LOG(UWRAP_LOG_ERROR,
1162 "ERROR: Number of groups (%u) exceeds maximum value "
1163 "uid_wrapper can handle (%u).",
1164 id->ngroups,
1165 GROUP_MAX_COUNT);
1166 exit(-1);
1169 /* GROUPS */
1170 for (i = 0; i < id->ngroups; i++) {
1171 size_t groups_str_len = strlen(groups_str);
1172 size_t groups_str_avail = groups_str_size - groups_str_len - 1;
1173 int len;
1175 len = snprintf(unsigned_str, sizeof(unsigned_str), ",%u", id->groups[i]);
1176 if (len <= 1) {
1177 UWRAP_LOG(UWRAP_LOG_ERROR,
1178 "snprintf failed for groups[%d]=%u",
1180 id->groups[i]);
1181 break;
1183 if (((size_t)len) >= groups_str_avail) {
1184 UWRAP_LOG(UWRAP_LOG_ERROR,
1185 "groups env string is to small for %d groups",
1187 break;
1190 len = snprintf(groups_str + groups_str_len,
1191 groups_str_size - groups_str_len,
1192 "%s",
1193 i == 0 ? unsigned_str + 1 : unsigned_str);
1194 if (len < 1) {
1195 UWRAP_LOG(UWRAP_LOG_ERROR,
1196 "snprintf failed to create groups string at groups[%d]=%u",
1198 id->groups[i]);
1199 break;
1203 if (id->ngroups == i) {
1204 setenv("UID_WRAPPER_INITIAL_GROUPS", groups_str, 1);
1206 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->ngroups);
1207 setenv("UID_WRAPPER_INITIAL_GROUPS_COUNT", unsigned_str, 1);
1211 static void uwrap_thread_prepare(void)
1213 struct uwrap_thread *id = uwrap_tls_id;
1216 * We bind all symbols to avoid deadlocks of the fork is interrupted by
1217 * a signal handler using a symbol of this library.
1219 uwrap_bind_symbol_all();
1221 UWRAP_LOCK_ALL;
1223 /* uid_wrapper is loaded but not enabled */
1224 if (id == NULL) {
1225 return;
1229 * What happens if another atfork prepare functions calls a uwrap
1230 * function? So disable it in case another atfork prepare function
1231 * calls a (s)uid function. We disable uid_wrapper only for thread
1232 * (process) which called fork.
1234 id->enabled = false;
1237 static void uwrap_thread_parent(void)
1239 struct uwrap_thread *id = uwrap_tls_id;
1241 /* uid_wrapper is loaded but not enabled */
1242 if (id == NULL) {
1243 UWRAP_UNLOCK_ALL;
1244 return;
1247 id->enabled = true;
1249 UWRAP_UNLOCK_ALL;
1252 static void uwrap_thread_child(void)
1254 struct uwrap_thread *id = uwrap_tls_id;
1255 struct uwrap_thread *u = uwrap.ids;
1257 UWRAP_REINIT_ALL;
1259 /* uid_wrapper is loaded but not enabled */
1260 if (id == NULL) {
1261 return;
1265 * "Garbage collector" - Inspired by DESTRUCTOR.
1266 * All threads (except one which called fork()) are dead now.. Dave
1267 * That's what posix said...
1269 while (u != NULL) {
1270 if (u == id) {
1271 /* Skip this item. */
1272 u = uwrap.ids->next;
1273 continue;
1276 UWRAP_DLIST_REMOVE(uwrap.ids, u);
1278 SAFE_FREE(u->groups);
1279 SAFE_FREE(u);
1281 u = uwrap.ids;
1284 uwrap_export_ids(id);
1286 id->enabled = true;
1289 static unsigned long uwrap_get_xid_from_env(const char *envname)
1291 unsigned long xid;
1292 const char *env = NULL;
1293 char *endp = NULL;
1295 env = getenv(envname);
1296 if (env == NULL) {
1297 return ULONG_MAX;
1300 if (env[0] == '\0') {
1301 unsetenv(envname);
1302 return ULONG_MAX;
1305 xid = strtoul(env, &endp, 10);
1306 unsetenv(envname);
1307 if (env == endp) {
1308 return ULONG_MAX;
1311 return xid;
1315 * This initializes uid_wrapper with the IDs exported to the environment. Those
1316 * are normally set after we forked and executed.
1318 static void uwrap_init_env(struct uwrap_thread *id)
1320 const char *env;
1321 int ngroups = 0;
1322 unsigned long xid;
1324 /* UIDs */
1325 xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_RUID");
1326 if (xid != ULONG_MAX) {
1327 id->ruid = (uid_t)xid;
1330 xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_EUID");
1331 if (xid != ULONG_MAX) {
1332 id->euid = (uid_t)xid;
1335 xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_SUID");
1336 if (xid != ULONG_MAX) {
1337 id->suid = (uid_t)xid;
1340 /* GIDs */
1341 xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_RGID");
1342 if (xid != ULONG_MAX) {
1343 id->rgid = (gid_t)xid;
1346 xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_EGID");
1347 if (xid != ULONG_MAX) {
1348 id->egid = (gid_t)xid;
1351 xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_SGID");
1352 if (xid != ULONG_MAX) {
1353 id->sgid = (gid_t)xid;
1356 env = getenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
1357 if (env != NULL && env[0] != '\0') {
1358 char *endp = NULL;
1359 long n;
1361 n = strtol(env, &endp, 10);
1362 if (env == endp) {
1363 ngroups = 0;
1364 } else if (n > 0 && n < GROUP_MAX_COUNT) {
1365 ngroups = (int)n;
1367 unsetenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
1370 if (ngroups > 0) {
1371 int i = 0;
1373 id->ngroups = 0;
1375 free(id->groups);
1376 id->groups = calloc(ngroups, sizeof(gid_t));
1377 if (id->groups == NULL) {
1378 UWRAP_LOG(UWRAP_LOG_ERROR,
1379 "Unable to allocate memory");
1380 exit(-1);
1383 env = getenv("UID_WRAPPER_INITIAL_GROUPS");
1384 if (env != NULL && env[0] != '\0') {
1385 char *groups_str = NULL;
1386 char *saveptr = NULL;
1387 const char *p = NULL;
1389 groups_str = strdup(env);
1390 if (groups_str == NULL) {
1391 exit(-1);
1394 p = strtok_r(groups_str, ",", &saveptr);
1395 while (p != NULL) {
1396 id->groups[i] = strtol(p, (char **)NULL, 10);
1397 i++;
1399 p = strtok_r(NULL, ",", &saveptr);
1401 SAFE_FREE(groups_str);
1404 if (i != ngroups) {
1405 UWRAP_LOG(UWRAP_LOG_ERROR,
1406 "ERROR: The number of groups (%u) passed, "
1407 "does not match the number of groups (%u) "
1408 "we parsed.",
1409 ngroups,
1411 exit(-1);
1414 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize groups with %s", env);
1415 id->ngroups = ngroups;
1419 static void uwrap_init(void)
1421 const char *env;
1423 UWRAP_LOCK(uwrap_id);
1425 if (uwrap.initialised) {
1426 struct uwrap_thread *id = uwrap_tls_id;
1428 if (uwrap.ids == NULL) {
1429 UWRAP_UNLOCK(uwrap_id);
1430 return;
1433 if (id == NULL) {
1434 UWRAP_LOG(UWRAP_LOG_ERROR,
1435 "Invalid id for thread");
1436 exit(-1);
1439 UWRAP_UNLOCK(uwrap_id);
1440 return;
1443 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize uid_wrapper");
1445 uwrap.initialised = true;
1447 env = getenv("UID_WRAPPER");
1448 if (env != NULL && env[0] == '1') {
1449 const char *root = getenv("UID_WRAPPER_ROOT");
1450 struct uwrap_thread *id;
1452 id = calloc(1, sizeof(struct uwrap_thread));
1453 if (id == NULL) {
1454 UWRAP_LOG(UWRAP_LOG_ERROR,
1455 "Unable to allocate memory for main id");
1456 exit(-1);
1459 UWRAP_DLIST_ADD(uwrap.ids, id);
1460 uwrap_tls_id = id;
1462 uwrap.myuid = libc_geteuid();
1463 uwrap.mygid = libc_getegid();
1465 /* put us in one group */
1466 if (root != NULL && root[0] == '1') {
1467 id->ruid = id->euid = id->suid = 0;
1468 id->rgid = id->egid = id->sgid = 0;
1470 id->groups = malloc(sizeof(gid_t) * 1);
1471 if (id->groups == NULL) {
1472 UWRAP_LOG(UWRAP_LOG_ERROR,
1473 "Unable to allocate memory");
1474 exit(-1);
1477 id->ngroups = 1;
1478 id->groups[0] = 0;
1480 } else {
1481 id->ruid = id->euid = id->suid = uwrap.myuid;
1482 id->rgid = id->egid = id->sgid = uwrap.mygid;
1484 id->ngroups = libc_getgroups(0, NULL);
1485 if (id->ngroups == -1) {
1486 UWRAP_LOG(UWRAP_LOG_ERROR,
1487 "Unable to call libc_getgroups in uwrap_init.");
1488 exit(-1);
1490 id->groups = malloc(sizeof(gid_t) * id->ngroups);
1491 if (id->groups == NULL) {
1492 UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
1493 exit(-1);
1495 if (libc_getgroups(id->ngroups, id->groups) == -1) {
1496 UWRAP_LOG(UWRAP_LOG_ERROR,
1497 "Unable to call libc_getgroups again in uwrap_init.");
1498 id->groups = 0;
1500 * Deallocation of uwrap.groups is handled by
1501 * library destructor.
1503 exit(-1);
1507 uwrap_init_env(id);
1509 id->enabled = true;
1511 UWRAP_LOG(UWRAP_LOG_DEBUG,
1512 "Enabled uid_wrapper as %s (real uid=%u)",
1513 id->ruid == 0 ? "root" : "user",
1514 (unsigned int)uwrap.myuid);
1517 UWRAP_UNLOCK(uwrap_id);
1519 UWRAP_LOG(UWRAP_LOG_DEBUG, "Successfully initialized uid_wrapper");
1522 bool uid_wrapper_enabled(void)
1524 struct uwrap_thread *id = uwrap_tls_id;
1525 bool enabled;
1527 if (id == NULL) {
1528 return false;
1531 UWRAP_LOCK(uwrap_id);
1532 enabled = id->enabled;
1533 UWRAP_UNLOCK(uwrap_id);
1535 return enabled;
1539 * UWRAP_SETxUID FUNCTIONS
1542 static int uwrap_setresuid_args(uid_t ruid, uid_t euid, uid_t suid)
1544 struct uwrap_thread *id = uwrap_tls_id;
1546 UWRAP_LOG(UWRAP_LOG_TRACE,
1547 "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1548 id->ruid, ruid, id->euid, euid, id->suid, suid);
1550 if (id->euid != 0) {
1551 if (ruid != (uid_t)-1 &&
1552 ruid != id->ruid &&
1553 ruid != id->euid &&
1554 ruid != id->suid) {
1555 errno = EPERM;
1556 return -1;
1558 if (euid != (uid_t)-1 &&
1559 euid != id->ruid &&
1560 euid != id->euid &&
1561 euid != id->suid) {
1562 errno = EPERM;
1563 return -1;
1565 if (suid != (uid_t)-1 &&
1566 suid != id->ruid &&
1567 suid != id->euid &&
1568 suid != id->suid) {
1569 errno = EPERM;
1570 return -1;
1574 return 0;
1577 static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
1579 struct uwrap_thread *id = uwrap_tls_id;
1580 int rc;
1582 UWRAP_LOG(UWRAP_LOG_TRACE,
1583 "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1584 id->ruid, ruid, id->euid, euid, id->suid, suid);
1586 rc = uwrap_setresuid_args(ruid, euid, suid);
1587 if (rc != 0) {
1588 return rc;
1591 UWRAP_LOCK(uwrap_id);
1593 if (ruid != (uid_t)-1) {
1594 id->ruid = ruid;
1597 if (euid != (uid_t)-1) {
1598 id->euid = euid;
1601 if (suid != (uid_t)-1) {
1602 id->suid = suid;
1605 UWRAP_UNLOCK(uwrap_id);
1607 return 0;
1610 static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
1612 struct uwrap_thread *id = uwrap_tls_id;
1613 int rc;
1615 UWRAP_LOG(UWRAP_LOG_TRACE,
1616 "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1617 id->ruid, ruid, id->euid, euid, id->suid, suid);
1619 rc = uwrap_setresuid_args(ruid, euid, suid);
1620 if (rc != 0) {
1621 return rc;
1624 UWRAP_LOCK(uwrap_id);
1626 for (id = uwrap.ids; id; id = id->next) {
1627 if (ruid != (uid_t)-1) {
1628 id->ruid = ruid;
1631 if (euid != (uid_t)-1) {
1632 id->euid = euid;
1635 if (suid != (uid_t)-1) {
1636 id->suid = suid;
1640 UWRAP_UNLOCK(uwrap_id);
1642 return 0;
1645 static int uwrap_setreuid_args(uid_t ruid, uid_t euid,
1646 uid_t *_new_ruid,
1647 uid_t *_new_euid,
1648 uid_t *_new_suid)
1650 struct uwrap_thread *id = uwrap_tls_id;
1651 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1653 UWRAP_LOG(UWRAP_LOG_TRACE,
1654 "ruid %d -> %d, euid %d -> %d",
1655 id->ruid, ruid, id->euid, euid);
1657 if (ruid != (uid_t)-1) {
1658 new_ruid = ruid;
1659 if (ruid != id->ruid &&
1660 ruid != id->euid &&
1661 id->euid != 0) {
1662 errno = EPERM;
1663 return -1;
1667 if (euid != (uid_t)-1) {
1668 new_euid = euid;
1669 if (euid != id->ruid &&
1670 euid != id->euid &&
1671 euid != id->suid &&
1672 id->euid != 0) {
1673 errno = EPERM;
1674 return -1;
1678 if (ruid != (uid_t) -1 ||
1679 (euid != (uid_t)-1 && id->ruid != euid)) {
1680 new_suid = new_euid;
1683 *_new_ruid = new_ruid;
1684 *_new_euid = new_euid;
1685 *_new_suid = new_suid;
1687 return 0;
1690 static int uwrap_setreuid_thread(uid_t ruid, uid_t euid)
1692 struct uwrap_thread *id = uwrap_tls_id;
1693 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1694 int rc;
1696 UWRAP_LOG(UWRAP_LOG_TRACE,
1697 "ruid %d -> %d, euid %d -> %d",
1698 id->ruid, ruid, id->euid, euid);
1700 rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
1701 if (rc != 0) {
1702 return rc;
1705 return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
1708 #ifdef HAVE_SETREUID
1709 static int uwrap_setreuid(uid_t ruid, uid_t euid)
1711 struct uwrap_thread *id = uwrap_tls_id;
1712 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1713 int rc;
1715 UWRAP_LOG(UWRAP_LOG_TRACE,
1716 "ruid %d -> %d, euid %d -> %d",
1717 id->ruid, ruid, id->euid, euid);
1719 rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
1720 if (rc != 0) {
1721 return rc;
1724 return uwrap_setresuid(new_ruid, new_euid, new_suid);
1726 #endif
1728 static int uwrap_setuid_args(uid_t uid,
1729 uid_t *new_ruid,
1730 uid_t *new_euid,
1731 uid_t *new_suid)
1733 struct uwrap_thread *id = uwrap_tls_id;
1735 UWRAP_LOG(UWRAP_LOG_TRACE,
1736 "uid %d -> %d",
1737 id->ruid, uid);
1739 if (uid == (uid_t)-1) {
1740 errno = EINVAL;
1741 return -1;
1744 if (id->euid == 0) {
1745 *new_suid = *new_ruid = uid;
1746 } else if (uid != id->ruid &&
1747 uid != id->suid) {
1748 errno = EPERM;
1749 return -1;
1752 *new_euid = uid;
1754 return 0;
1757 static int uwrap_setuid_thread(uid_t uid)
1759 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1760 int rc;
1762 rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
1763 if (rc != 0) {
1764 return rc;
1767 return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
1770 static int uwrap_setuid(uid_t uid)
1772 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1773 int rc;
1775 rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
1776 if (rc != 0) {
1777 return rc;
1780 return uwrap_setresuid(new_ruid, new_euid, new_suid);
1784 * UWRAP_GETxUID FUNCTIONS
1787 #ifdef HAVE_GETRESUID
1788 static int uwrap_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
1790 struct uwrap_thread *id = uwrap_tls_id;
1792 UWRAP_LOCK(uwrap_id);
1794 *ruid = id->ruid;
1795 *euid = id->euid;
1796 *suid = id->suid;
1798 UWRAP_UNLOCK(uwrap_id);
1800 return 0;
1802 #endif
1804 #ifdef HAVE_GETRESGID
1805 static int uwrap_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
1807 struct uwrap_thread *id = uwrap_tls_id;
1809 UWRAP_LOCK(uwrap_id);
1811 *rgid = id->rgid;
1812 *egid = id->egid;
1813 *sgid = id->sgid;
1815 UWRAP_UNLOCK(uwrap_id);
1817 return 0;
1819 #endif
1822 * UWRAP_SETxGID FUNCTIONS
1825 static int uwrap_setresgid_args(gid_t rgid, gid_t egid, gid_t sgid)
1827 struct uwrap_thread *id = uwrap_tls_id;
1829 UWRAP_LOG(UWRAP_LOG_TRACE,
1830 "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1831 id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1833 if (id->euid != 0) {
1834 if (rgid != (gid_t)-1 &&
1835 rgid != id->rgid &&
1836 rgid != id->egid &&
1837 rgid != id->sgid) {
1838 errno = EPERM;
1839 return -1;
1841 if (egid != (gid_t)-1 &&
1842 egid != id->rgid &&
1843 egid != id->egid &&
1844 egid != id->sgid) {
1845 errno = EPERM;
1846 return -1;
1848 if (sgid != (gid_t)-1 &&
1849 sgid != id->rgid &&
1850 sgid != id->egid &&
1851 sgid != id->sgid) {
1852 errno = EPERM;
1853 return -1;
1857 return 0;
1860 static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
1862 struct uwrap_thread *id = uwrap_tls_id;
1863 int rc;
1865 UWRAP_LOG(UWRAP_LOG_TRACE,
1866 "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1867 id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1869 rc = uwrap_setresgid_args(rgid, egid, sgid);
1870 if (rc != 0) {
1871 return rc;
1874 UWRAP_LOCK(uwrap_id);
1876 if (rgid != (gid_t)-1) {
1877 id->rgid = rgid;
1880 if (egid != (gid_t)-1) {
1881 id->egid = egid;
1884 if (sgid != (gid_t)-1) {
1885 id->sgid = sgid;
1888 UWRAP_UNLOCK(uwrap_id);
1890 return 0;
1893 static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1895 struct uwrap_thread *id = uwrap_tls_id;
1896 int rc;
1898 UWRAP_LOG(UWRAP_LOG_TRACE,
1899 "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1900 id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1902 rc = uwrap_setresgid_args(rgid, egid, sgid);
1903 if (rc != 0) {
1904 return rc;
1907 UWRAP_LOCK(uwrap_id);
1909 for (id = uwrap.ids; id; id = id->next) {
1910 if (rgid != (gid_t)-1) {
1911 id->rgid = rgid;
1914 if (egid != (gid_t)-1) {
1915 id->egid = egid;
1918 if (sgid != (gid_t)-1) {
1919 id->sgid = sgid;
1923 UWRAP_UNLOCK(uwrap_id);
1925 return 0;
1928 static int uwrap_setregid_args(gid_t rgid, gid_t egid,
1929 gid_t *_new_rgid,
1930 gid_t *_new_egid,
1931 gid_t *_new_sgid)
1933 struct uwrap_thread *id = uwrap_tls_id;
1934 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1936 UWRAP_LOG(UWRAP_LOG_TRACE,
1937 "rgid %d -> %d, egid %d -> %d",
1938 id->rgid, rgid, id->egid, egid);
1940 if (rgid != (gid_t)-1) {
1941 new_rgid = rgid;
1942 if (rgid != id->rgid &&
1943 rgid != id->egid &&
1944 id->euid != 0) {
1945 errno = EPERM;
1946 return -1;
1950 if (egid != (gid_t)-1) {
1951 new_egid = egid;
1952 if (egid != id->rgid &&
1953 egid != id->egid &&
1954 egid != id->sgid &&
1955 id->euid != 0) {
1956 errno = EPERM;
1957 return -1;
1961 if (rgid != (gid_t) -1 ||
1962 (egid != (gid_t)-1 && id->rgid != egid)) {
1963 new_sgid = new_egid;
1966 *_new_rgid = new_rgid;
1967 *_new_egid = new_egid;
1968 *_new_sgid = new_sgid;
1970 return 0;
1973 static int uwrap_setregid_thread(gid_t rgid, gid_t egid)
1975 struct uwrap_thread *id = uwrap_tls_id;
1976 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1977 int rc;
1979 UWRAP_LOG(UWRAP_LOG_TRACE,
1980 "rgid %d -> %d, egid %d -> %d",
1981 id->rgid, rgid, id->egid, egid);
1983 rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
1984 if (rc != 0) {
1985 return rc;
1988 return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
1991 #ifdef HAVE_SETREGID
1992 static int uwrap_setregid(gid_t rgid, gid_t egid)
1994 struct uwrap_thread *id = uwrap_tls_id;
1995 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1996 int rc;
1998 UWRAP_LOG(UWRAP_LOG_TRACE,
1999 "rgid %d -> %d, egid %d -> %d",
2000 id->rgid, rgid, id->egid, egid);
2002 rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
2003 if (rc != 0) {
2004 return rc;
2007 return uwrap_setresgid(new_rgid, new_egid, new_sgid);
2009 #endif
2011 static int uwrap_setgid_args(gid_t gid,
2012 gid_t *new_rgid,
2013 gid_t *new_egid,
2014 gid_t *new_sgid)
2016 struct uwrap_thread *id = uwrap_tls_id;
2018 UWRAP_LOG(UWRAP_LOG_TRACE,
2019 "gid %d -> %d",
2020 id->rgid, gid);
2022 if (gid == (gid_t)-1) {
2023 errno = EINVAL;
2024 return -1;
2027 if (id->euid == 0) {
2028 *new_sgid = *new_rgid = gid;
2029 } else if (gid != id->rgid &&
2030 gid != id->sgid) {
2031 errno = EPERM;
2032 return -1;
2035 *new_egid = gid;
2037 return 0;
2040 static int uwrap_setgid_thread(gid_t gid)
2042 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
2043 int rc;
2045 rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
2046 if (rc != 0) {
2047 return rc;
2050 return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
2053 static int uwrap_setgid(gid_t gid)
2055 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
2056 int rc;
2058 rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
2059 if (rc != 0) {
2060 return rc;
2063 return uwrap_setresgid(new_rgid, new_egid, new_sgid);
2067 * SETUID
2069 int setuid(uid_t uid)
2071 if (!uid_wrapper_enabled()) {
2072 return libc_setuid(uid);
2075 uwrap_init();
2076 return uwrap_setuid(uid);
2079 #ifdef HAVE_SETEUID
2080 int seteuid(uid_t euid)
2082 if (!uid_wrapper_enabled()) {
2083 return libc_seteuid(euid);
2086 /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
2087 if (euid == (uid_t)-1) {
2088 errno = EINVAL;
2089 return -1;
2092 uwrap_init();
2093 return uwrap_setresuid(-1, euid, -1);
2095 #endif
2097 #ifdef HAVE_SETREUID
2098 int setreuid(uid_t ruid, uid_t euid)
2100 if (!uid_wrapper_enabled()) {
2101 return libc_setreuid(ruid, euid);
2104 uwrap_init();
2105 return uwrap_setreuid(ruid, euid);
2107 #endif
2109 #ifdef HAVE_SETRESUID
2110 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
2112 if (!uid_wrapper_enabled()) {
2113 return libc_setresuid(ruid, euid, suid);
2116 uwrap_init();
2117 return uwrap_setresuid(ruid, euid, suid);
2119 #endif
2121 #ifdef HAVE_GETRESUID
2122 int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
2124 if (!uid_wrapper_enabled()) {
2125 return libc_getresuid(ruid, euid, suid);
2128 uwrap_init();
2129 return uwrap_getresuid(ruid, euid, suid);
2131 #endif
2134 * GETUID
2136 static uid_t uwrap_getuid(void)
2138 struct uwrap_thread *id = uwrap_tls_id;
2139 uid_t uid;
2141 UWRAP_LOCK(uwrap_id);
2142 uid = id->ruid;
2143 UWRAP_UNLOCK(uwrap_id);
2145 return uid;
2148 uid_t getuid(void)
2150 if (!uid_wrapper_enabled()) {
2151 return libc_getuid();
2154 uwrap_init();
2155 return uwrap_getuid();
2159 * GETEUID
2161 static uid_t uwrap_geteuid(void)
2163 const char *env = getenv("UID_WRAPPER_MYUID");
2164 struct uwrap_thread *id = uwrap_tls_id;
2165 uid_t uid;
2167 UWRAP_LOCK(uwrap_id);
2168 uid = id->euid;
2169 UWRAP_UNLOCK(uwrap_id);
2171 /* Disable root and return myuid */
2172 if (env != NULL && env[0] == '1') {
2173 uid = uwrap.myuid;
2176 return uid;
2179 uid_t geteuid(void)
2181 if (!uid_wrapper_enabled()) {
2182 return libc_geteuid();
2185 uwrap_init();
2186 return uwrap_geteuid();
2190 * SETGID
2192 int setgid(gid_t gid)
2194 if (!uid_wrapper_enabled()) {
2195 return libc_setgid(gid);
2198 uwrap_init();
2199 return uwrap_setgid(gid);
2202 #ifdef HAVE_SETEGID
2203 int setegid(gid_t egid)
2205 if (!uid_wrapper_enabled()) {
2206 return libc_setegid(egid);
2209 /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
2210 if (egid == (gid_t)-1) {
2211 errno = EINVAL;
2212 return -1;
2215 uwrap_init();
2216 return uwrap_setresgid(-1, egid, -1);
2218 #endif
2220 #ifdef HAVE_SETREGID
2221 int setregid(gid_t rgid, gid_t egid)
2223 if (!uid_wrapper_enabled()) {
2224 return libc_setregid(rgid, egid);
2227 uwrap_init();
2228 return uwrap_setregid(rgid, egid);
2230 #endif
2232 #ifdef HAVE_SETRESGID
2233 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
2235 if (!uid_wrapper_enabled()) {
2236 return libc_setresgid(rgid, egid, sgid);
2239 uwrap_init();
2240 return uwrap_setresgid(rgid, egid, sgid);
2242 #endif
2244 #ifdef HAVE_GETRESGID
2245 int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
2247 if (!uid_wrapper_enabled()) {
2248 return libc_getresgid(rgid, egid, sgid);
2251 uwrap_init();
2252 return uwrap_getresgid(rgid, egid, sgid);
2254 #endif
2257 * GETGID
2259 static gid_t uwrap_getgid(void)
2261 struct uwrap_thread *id = uwrap_tls_id;
2262 gid_t gid;
2264 UWRAP_LOCK(uwrap_id);
2265 gid = id->rgid;
2266 UWRAP_UNLOCK(uwrap_id);
2268 return gid;
2271 gid_t getgid(void)
2273 if (!uid_wrapper_enabled()) {
2274 return libc_getgid();
2277 uwrap_init();
2278 return uwrap_getgid();
2282 * GETEGID
2284 static uid_t uwrap_getegid(void)
2286 struct uwrap_thread *id = uwrap_tls_id;
2287 gid_t gid;
2289 UWRAP_LOCK(uwrap_id);
2290 gid = id->egid;
2291 UWRAP_UNLOCK(uwrap_id);
2293 return gid;
2296 uid_t getegid(void)
2298 if (!uid_wrapper_enabled()) {
2299 return libc_getegid();
2302 uwrap_init();
2303 return uwrap_getegid();
2306 static int uwrap_setgroups_thread(size_t size, const gid_t *list)
2308 struct uwrap_thread *id = uwrap_tls_id;
2309 int rc = -1;
2311 UWRAP_LOCK(uwrap_id);
2313 if (size == 0) {
2314 SAFE_FREE(id->groups);
2315 id->ngroups = 0;
2316 } else if (size > 0) {
2317 gid_t *tmp;
2319 tmp = realloc(id->groups, sizeof(gid_t) * size);
2320 if (tmp == NULL) {
2321 errno = ENOMEM;
2322 goto out;
2324 id->groups = tmp;
2325 id->ngroups = size;
2326 memcpy(id->groups, list, size * sizeof(gid_t));
2329 rc = 0;
2330 out:
2331 UWRAP_UNLOCK(uwrap_id);
2333 return rc;
2336 static int uwrap_setgroups(size_t size, const gid_t *list)
2338 struct uwrap_thread *id;
2339 int rc = -1;
2341 UWRAP_LOCK(uwrap_id);
2343 if (size == 0) {
2344 for (id = uwrap.ids; id; id = id->next) {
2345 SAFE_FREE(id->groups);
2346 id->ngroups = 0;
2349 } else if (size > 0) {
2350 gid_t *tmp;
2352 for (id = uwrap.ids; id; id = id->next) {
2353 tmp = realloc(id->groups, sizeof(gid_t) * size);
2354 if (tmp == NULL) {
2355 errno = ENOMEM;
2356 goto out;
2358 id->groups = tmp;
2360 id->ngroups = size;
2361 memcpy(id->groups, list, size * sizeof(gid_t));
2365 rc = 0;
2366 out:
2367 UWRAP_UNLOCK(uwrap_id);
2369 return rc;
2372 #ifdef HAVE_SETGROUPS_INT
2373 int setgroups(int size, const gid_t *list)
2374 #else
2375 int setgroups(size_t size, const gid_t *list)
2376 #endif
2378 if (!uid_wrapper_enabled()) {
2379 return libc_setgroups(size, list);
2382 uwrap_init();
2383 return uwrap_setgroups(size, list);
2386 static int uwrap_getgroups(int size, gid_t *list)
2388 struct uwrap_thread *id = uwrap_tls_id;
2389 int ngroups;
2391 UWRAP_LOCK(uwrap_id);
2392 ngroups = id->ngroups;
2394 if (size > ngroups) {
2395 size = ngroups;
2397 if (size == 0) {
2398 goto out;
2400 if (size < ngroups) {
2401 errno = EINVAL;
2402 ngroups = -1;
2404 memcpy(list, id->groups, size * sizeof(gid_t));
2406 out:
2407 UWRAP_UNLOCK(uwrap_id);
2409 return ngroups;
2412 int getgroups(int size, gid_t *list)
2414 if (!uid_wrapper_enabled()) {
2415 return libc_getgroups(size, list);
2418 uwrap_init();
2419 return uwrap_getgroups(size, list);
2422 #ifdef HAVE___GETGROUPS_CHK
2423 static int uwrap___getgroups_chk(int size, gid_t *list, size_t listlen)
2425 if (size * sizeof(gid_t) > listlen) {
2426 UWRAP_LOG(UWRAP_LOG_DEBUG, "Buffer overflow detected");
2427 abort();
2430 return uwrap_getgroups(size, list);
2433 int __getgroups_chk(int size, gid_t *list, size_t listlen);
2435 int __getgroups_chk(int size, gid_t *list, size_t listlen)
2437 if (!uid_wrapper_enabled()) {
2438 return libc___getgroups_chk(size, list, listlen);
2441 uwrap_init();
2442 return uwrap___getgroups_chk(size, list, listlen);
2444 #endif /* HAVE___GETGROUPS_CHK */
2446 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
2447 && (defined(SYS_setreuid) || defined(SYS_setreuid32))
2448 static bool uwrap_is_uwrap_related_syscall(long int sysno)
2450 switch (sysno) {
2451 /* gid */
2452 #ifdef __alpha__
2453 case SYS_getxgid:
2454 return true;
2455 #else
2456 case SYS_getgid:
2457 return true;
2458 #endif
2459 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2460 case SYS_getgid32:
2461 return true;
2462 #endif
2463 #ifdef SYS_getegid
2464 case SYS_getegid:
2465 return true;
2466 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2467 case SYS_getegid32:
2468 return true;
2469 #endif
2470 #endif /* SYS_getegid */
2471 case SYS_setgid:
2472 return true;
2473 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2474 case SYS_setgid32:
2475 return true;
2476 #endif
2477 case SYS_setregid:
2478 return true;
2479 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2480 case SYS_setregid32:
2481 return true;
2482 #endif
2483 #ifdef SYS_setresgid
2484 case SYS_setresgid:
2485 return true;
2486 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2487 case SYS_setresgid32:
2488 return true;
2489 #endif
2490 #endif /* SYS_setresgid */
2491 #if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
2492 case SYS_getresgid:
2493 return true;
2494 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2495 case SYS_getresgid32:
2496 return true;
2497 #endif
2498 #endif /* SYS_getresgid && HAVE_GETRESGID */
2500 /* uid */
2501 #ifdef __alpha__
2502 case SYS_getxuid:
2503 return true;
2504 #else
2505 case SYS_getuid:
2506 return true;
2507 #endif
2508 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2509 case SYS_getuid32:
2510 return true;
2511 #endif
2512 #ifdef SYS_geteuid
2513 case SYS_geteuid:
2514 return true;
2515 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2516 case SYS_geteuid32:
2517 return true;
2518 #endif
2519 #endif /* SYS_geteuid */
2520 case SYS_setuid:
2521 return true;
2522 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2523 case SYS_setuid32:
2524 return true;
2525 #endif
2526 case SYS_setreuid:
2527 return true;
2528 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2529 case SYS_setreuid32:
2530 return true;
2531 #endif
2532 #ifdef SYS_setresuid
2533 case SYS_setresuid:
2534 return true;
2535 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2536 case SYS_setresuid32:
2537 return true;
2538 #endif
2539 #endif /* SYS_setresuid */
2540 #if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
2541 case SYS_getresuid:
2542 return true;
2543 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2544 case SYS_getresuid32:
2545 return true;
2546 #endif
2547 #endif /* SYS_getresuid && HAVE_GETRESUID*/
2548 /* groups */
2549 case SYS_setgroups:
2550 return true;
2551 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2552 case SYS_setgroups32:
2553 return true;
2554 #endif
2555 default:
2556 return false;
2560 static long int uwrap_syscall (long int sysno, va_list vp)
2562 long int rc;
2564 switch (sysno) {
2565 /* gid */
2566 #ifdef __alpha__
2567 case SYS_getxgid:
2568 #else
2569 case SYS_getgid:
2570 #endif
2571 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2572 case SYS_getgid32:
2573 #endif
2575 rc = uwrap_getgid();
2577 break;
2578 #ifdef SYS_getegid
2579 case SYS_getegid:
2580 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2581 case SYS_getegid32:
2582 #endif
2584 rc = uwrap_getegid();
2586 break;
2587 #endif /* SYS_getegid */
2588 case SYS_setgid:
2589 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2590 case SYS_setgid32:
2591 #endif
2593 gid_t gid = (gid_t) va_arg(vp, gid_t);
2595 rc = uwrap_setgid_thread(gid);
2597 break;
2598 case SYS_setregid:
2599 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2600 case SYS_setregid32:
2601 #endif
2603 gid_t rgid = (gid_t) va_arg(vp, gid_t);
2604 gid_t egid = (gid_t) va_arg(vp, gid_t);
2606 rc = uwrap_setregid_thread(rgid, egid);
2608 break;
2609 #ifdef SYS_setresgid
2610 case SYS_setresgid:
2611 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2612 case SYS_setresgid32:
2613 #endif
2615 gid_t rgid = (gid_t) va_arg(vp, gid_t);
2616 gid_t egid = (gid_t) va_arg(vp, gid_t);
2617 gid_t sgid = (gid_t) va_arg(vp, gid_t);
2619 rc = uwrap_setresgid_thread(rgid, egid, sgid);
2621 break;
2622 #endif /* SYS_setresgid */
2623 #if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
2624 case SYS_getresgid:
2625 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2626 case SYS_getresgid32:
2627 #endif
2629 gid_t *rgid = (gid_t *) va_arg(vp, gid_t *);
2630 gid_t *egid = (gid_t *) va_arg(vp, gid_t *);
2631 gid_t *sgid = (gid_t *) va_arg(vp, gid_t *);
2633 rc = uwrap_getresgid(rgid, egid, sgid);
2635 break;
2636 #endif /* SYS_getresgid && HAVE_GETRESGID */
2638 /* uid */
2639 #ifdef __alpha__
2640 case SYS_getxuid:
2641 #else
2642 case SYS_getuid:
2643 #endif
2644 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2645 case SYS_getuid32:
2646 #endif
2648 rc = uwrap_getuid();
2650 break;
2651 #ifdef SYS_geteuid
2652 case SYS_geteuid:
2653 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2654 case SYS_geteuid32:
2655 #endif
2657 rc = uwrap_geteuid();
2659 break;
2660 #endif /* SYS_geteuid */
2661 case SYS_setuid:
2662 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2663 case SYS_setuid32:
2664 #endif
2666 uid_t uid = (uid_t) va_arg(vp, uid_t);
2668 rc = uwrap_setuid_thread(uid);
2670 break;
2671 case SYS_setreuid:
2672 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2673 case SYS_setreuid32:
2674 #endif
2676 uid_t ruid = (uid_t) va_arg(vp, uid_t);
2677 uid_t euid = (uid_t) va_arg(vp, uid_t);
2679 rc = uwrap_setreuid_thread(ruid, euid);
2681 break;
2682 #ifdef SYS_setresuid
2683 case SYS_setresuid:
2684 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2685 case SYS_setresuid32:
2686 #endif
2688 uid_t ruid = (uid_t) va_arg(vp, uid_t);
2689 uid_t euid = (uid_t) va_arg(vp, uid_t);
2690 uid_t suid = (uid_t) va_arg(vp, uid_t);
2692 rc = uwrap_setresuid_thread(ruid, euid, suid);
2694 break;
2695 #endif /* SYS_setresuid */
2696 #if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
2697 case SYS_getresuid:
2698 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2699 case SYS_getresuid32:
2700 #endif
2702 uid_t *ruid = (uid_t *) va_arg(vp, uid_t *);
2703 uid_t *euid = (uid_t *) va_arg(vp, uid_t *);
2704 uid_t *suid = (uid_t *) va_arg(vp, uid_t *);
2706 rc = uwrap_getresuid(ruid, euid, suid);
2708 break;
2709 #endif /* SYS_getresuid && HAVE_GETRESUID*/
2710 /* groups */
2711 case SYS_setgroups:
2712 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2713 case SYS_setgroups32:
2714 #endif
2716 size_t size = (size_t) va_arg(vp, size_t);
2717 gid_t *list = (gid_t *) va_arg(vp, int *);
2719 rc = uwrap_setgroups_thread(size, list);
2721 break;
2722 default:
2723 rc = -1;
2724 errno = ENOSYS;
2725 break;
2728 return rc;
2731 #ifdef HAVE_SYSCALL
2732 #ifdef HAVE_SYSCALL_INT
2733 int syscall (int sysno, ...)
2734 #else
2735 long int syscall (long int sysno, ...)
2736 #endif
2738 #ifdef HAVE_SYSCALL_INT
2739 int rc;
2740 #else
2741 long int rc;
2742 #endif
2743 va_list va;
2745 va_start(va, sysno);
2748 * JEMALLOC:
2750 * This is a workaround to prevent a deadlock in jemalloc calling
2751 * malloc_init() twice. The first allocation call will trigger a
2752 * malloc_init() of jemalloc. The functions calls syscall(SYS_open, ...)
2753 * so it goes to socket or uid wrapper. In this code path we need to
2754 * avoid any allocation calls. This will prevent the deadlock.
2756 if (!uwrap_handle_syscall) {
2757 rc = libc_vsyscall(sysno, va);
2758 va_end(va);
2759 return rc;
2763 * We need to check for uwrap related syscall numbers before calling
2764 * uid_wrapper_enabled() otherwise we'd deadlock during the freebsd libc
2765 * fork() which calls syscall() after invoking uwrap_thread_prepare().
2767 if (!uwrap_is_uwrap_related_syscall(sysno)) {
2769 * We need to give socket_wrapper a
2770 * chance to take over...
2772 if (uwrap_swrap_syscall_valid(sysno)) {
2773 rc = uwrap_swrap_syscall_va(sysno, va);
2774 va_end(va);
2775 return rc;
2778 rc = libc_vsyscall(sysno, va);
2779 va_end(va);
2780 return rc;
2783 if (!uid_wrapper_enabled()) {
2784 rc = libc_vsyscall(sysno, va);
2785 va_end(va);
2786 return rc;
2789 uwrap_init();
2790 rc = uwrap_syscall(sysno, va);
2791 va_end(va);
2793 return rc;
2796 /* used by socket_wrapper */
2797 bool uid_wrapper_syscall_valid(long int sysno);
2798 bool uid_wrapper_syscall_valid(long int sysno)
2800 if (!uwrap_is_uwrap_related_syscall(sysno)) {
2801 return false;
2804 if (!uid_wrapper_enabled()) {
2805 return false;
2808 return true;
2811 /* used by socket_wrapper */
2812 long int uid_wrapper_syscall_va(long int sysno, va_list va);
2813 long int uid_wrapper_syscall_va(long int sysno, va_list va)
2815 if (!uwrap_is_uwrap_related_syscall(sysno)) {
2816 errno = ENOSYS;
2817 return -1;
2820 if (!uid_wrapper_enabled()) {
2821 return libc_vsyscall(sysno, va);
2824 uwrap_init();
2826 return uwrap_syscall(sysno, va);
2828 #endif /* HAVE_SYSCALL */
2829 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
2831 /****************************
2832 * CONSTRUCTOR
2833 ***************************/
2835 void uwrap_constructor(void)
2837 char *glibc_malloc_lock_bug;
2840 * This is a workaround for a bug in glibc < 2.24:
2842 * The child handler for the malloc() function is called and locks the
2843 * mutex. Then our child handler is called and we try to call setenv().
2844 * setenv() wants to malloc and tries to aquire the lock for malloc and
2845 * we end up in a deadlock.
2847 * So as a workaround we need to call malloc once before we setup the
2848 * handlers.
2850 * See https://sourceware.org/bugzilla/show_bug.cgi?id=16742
2852 glibc_malloc_lock_bug = malloc(1);
2853 if (glibc_malloc_lock_bug == NULL) {
2854 exit(-1);
2856 glibc_malloc_lock_bug[0] = '\0';
2858 UWRAP_REINIT_ALL;
2861 * If we hold a lock and the application forks, then the child
2862 * is not able to unlock the mutex and we are in a deadlock.
2863 * This should prevent such deadlocks.
2865 pthread_atfork(&uwrap_thread_prepare,
2866 &uwrap_thread_parent,
2867 &uwrap_thread_child);
2869 free(glibc_malloc_lock_bug);
2871 /* Here is safe place to call uwrap_init() and initialize data
2872 * for main process.
2874 uwrap_init();
2876 /* Let socket_wrapper handle syscall() */
2877 uwrap_handle_syscall = true;
2880 /****************************
2881 * DESTRUCTOR
2882 ***************************/
2885 * This function is called when the library is unloaded and makes sure that
2886 * resources are freed.
2888 void uwrap_destructor(void)
2890 struct uwrap_thread *u = uwrap.ids;
2892 UWRAP_LOCK_ALL;
2894 while (u != NULL) {
2895 UWRAP_DLIST_REMOVE(uwrap.ids, u);
2897 SAFE_FREE(u->groups);
2898 SAFE_FREE(u);
2900 u = uwrap.ids;
2904 if (uwrap.libc.handle != NULL
2905 #ifdef RTLD_NEXT
2906 && uwrap.libc.handle != RTLD_NEXT
2907 #endif
2909 dlclose(uwrap.libc.handle);
2912 if (uwrap.libpthread.handle != NULL
2913 #ifdef RTLD_NEXT
2914 && uwrap.libpthread.handle != RTLD_NEXT
2915 #endif
2917 dlclose(uwrap.libpthread.handle);
2920 UWRAP_UNLOCK_ALL;