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/>.
27 #include <sys/types.h>
30 #ifdef HAVE_SYS_SYSCALL_H
31 #include <sys/syscall.h>
41 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
42 # define UWRAP_THREAD __thread
47 # define UWRAP_LOCK(m) do { \
48 pthread_mutex_lock(&( m ## _mutex)); \
51 # define UWRAP_UNLOCK(m) do { \
52 pthread_mutex_unlock(&( m ## _mutex)); \
55 /* Add new global locks here please */
56 # define UWRAP_LOCK_ALL \
59 # define UWRAP_UNLOCK_ALL \
60 UWRAP_UNLOCK(uwrap_id)
62 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
63 #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
65 #define CONSTRUCTOR_ATTRIBUTE
66 #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
68 #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
69 #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
71 #define DESTRUCTOR_ATTRIBUTE
72 #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
74 #ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
75 #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address))
76 #else /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
77 #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
78 #endif /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
80 /* GCC have printf type attribute check. */
81 #ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
82 #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
84 #define PRINTF_ATTRIBUTE(a,b)
85 #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
88 # ifdef HAVE_FALLTHROUGH_ATTRIBUTE
89 # define FALL_THROUGH __attribute__ ((fallthrough))
90 # else /* HAVE_FALLTHROUGH_ATTRIBUTE */
92 # endif /* HAVE_FALLTHROUGH_ATTRIBUTE */
93 #endif /* FALL_THROUGH */
95 #define UWRAP_DLIST_ADD(list,item) do { \
97 (item)->prev = NULL; \
98 (item)->next = NULL; \
101 (item)->prev = NULL; \
102 (item)->next = (list); \
103 (list)->prev = (item); \
108 #define UWRAP_DLIST_REMOVE(list,item) do { \
109 if ((list) == (item)) { \
110 (list) = (item)->next; \
112 (list)->prev = NULL; \
115 if ((item)->prev) { \
116 (item)->prev->next = (item)->next; \
118 if ((item)->next) { \
119 (item)->next->prev = (item)->prev; \
122 (item)->prev = NULL; \
123 (item)->next = NULL; \
127 #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
134 enum uwrap_dbglvl_e {
141 #ifndef HAVE_GETPROGNAME
142 static const char *getprogname(void)
144 #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
145 return program_invocation_short_name;
146 #elif defined(HAVE_GETEXECNAME)
147 return getexecname();
150 #endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
152 #endif /* HAVE_GETPROGNAME */
154 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
155 # define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __func__, __VA_ARGS__)
157 static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...)
162 unsigned int lvl = 0;
163 const char *prefix = "UWRAP";
164 const char *progname = getprogname();
166 d = getenv("UID_WRAPPER_DEBUGLEVEL");
175 va_start(va, format);
176 vsnprintf(buffer, sizeof(buffer), format, va);
180 case UWRAP_LOG_ERROR:
181 prefix = "UWRAP_ERROR";
184 prefix = "UWRAP_WARN";
186 case UWRAP_LOG_DEBUG:
187 prefix = "UWRAP_DEBUG";
189 case UWRAP_LOG_TRACE:
190 prefix = "UWRAP_TRACE";
194 if (progname == NULL) {
195 progname = "<unknown>";
199 "%s[%s (%u)] - %s: %s\n",
211 #define LIBC_NAME "libc.so"
213 typedef int (*__libc_setuid)(uid_t uid);
215 typedef uid_t (*__libc_getuid)(void);
218 typedef int (*__libc_seteuid)(uid_t euid);
222 typedef int (*__libc_setreuid)(uid_t ruid, uid_t euid);
225 #ifdef HAVE_SETRESUID
226 typedef int (*__libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
229 #ifdef HAVE_GETRESUID
230 typedef int (*__libc_getresuid)(uid_t *ruid, uid_t *euid, uid_t *suid);
233 typedef uid_t (*__libc_geteuid)(void);
235 typedef int (*__libc_setgid)(gid_t gid);
237 typedef gid_t (*__libc_getgid)(void);
240 typedef int (*__libc_setegid)(uid_t egid);
244 typedef int (*__libc_setregid)(uid_t rgid, uid_t egid);
247 #ifdef HAVE_SETRESGID
248 typedef int (*__libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
251 #ifdef HAVE_GETRESGID
252 typedef int (*__libc_getresgid)(gid_t *rgid, gid_t *egid, gid_t *sgid);
255 typedef gid_t (*__libc_getegid)(void);
257 typedef int (*__libc_getgroups)(int size, gid_t list[]);
258 #ifdef HAVE___GETGROUPS_CHK
259 typedef int (*__libc___getgroups_chk)(int size, gid_t list[], size_t listlen);
262 typedef int (*__libc_setgroups)(size_t size, const gid_t *list);
265 typedef long int (*__libc_syscall)(long int sysno, ...);
268 #define UWRAP_SYMBOL_ENTRY(i) \
274 struct uwrap_libc_symbols {
275 UWRAP_SYMBOL_ENTRY(setuid);
276 UWRAP_SYMBOL_ENTRY(getuid);
278 UWRAP_SYMBOL_ENTRY(seteuid);
281 UWRAP_SYMBOL_ENTRY(setreuid);
283 #ifdef HAVE_SETRESUID
284 UWRAP_SYMBOL_ENTRY(setresuid);
286 #ifdef HAVE_GETRESUID
287 UWRAP_SYMBOL_ENTRY(getresuid);
289 UWRAP_SYMBOL_ENTRY(geteuid);
290 UWRAP_SYMBOL_ENTRY(setgid);
291 UWRAP_SYMBOL_ENTRY(getgid);
293 UWRAP_SYMBOL_ENTRY(setegid);
296 UWRAP_SYMBOL_ENTRY(setregid);
298 #ifdef HAVE_SETRESGID
299 UWRAP_SYMBOL_ENTRY(setresgid);
301 #ifdef HAVE_GETRESGID
302 UWRAP_SYMBOL_ENTRY(getresgid);
304 UWRAP_SYMBOL_ENTRY(getegid);
305 UWRAP_SYMBOL_ENTRY(getgroups);
306 #ifdef HAVE___GETGROUPS_CHK
307 UWRAP_SYMBOL_ENTRY(__getgroups_chk);
309 UWRAP_SYMBOL_ENTRY(setgroups);
311 UWRAP_SYMBOL_ENTRY(syscall);
314 #undef UWRAP_SYMBOL_ENTRY
319 /* Yeah... I'm pig. I overloading macro here... So what? */
320 #define UWRAP_SYMBOL_ENTRY(i) \
322 __libpthread_##i f; \
326 typedef int (*__libpthread_pthread_create)(pthread_t *thread,
327 const pthread_attr_t *attr,
328 void *(*start_routine) (void *),
330 typedef void (*__libpthread_pthread_exit)(void *retval);
332 struct uwrap_libpthread_symbols {
333 UWRAP_SYMBOL_ENTRY(pthread_create);
334 UWRAP_SYMBOL_ENTRY(pthread_exit);
336 #undef UWRAP_SYMBOL_ENTRY
339 * We keep the virtualised euid/egid/groups information here
341 struct uwrap_thread {
355 struct uwrap_thread *next;
356 struct uwrap_thread *prev;
362 struct uwrap_libc_symbols symbols;
367 struct uwrap_libpthread_symbols symbols;
372 /* Real uid and gid of user who run uid wrapper */
376 struct uwrap_thread *ids;
379 static struct uwrap uwrap;
381 /* Shortcut to the list item */
382 static UWRAP_THREAD struct uwrap_thread *uwrap_tls_id;
384 /* The mutex or accessing the id */
385 static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
389 /*********************************************************
391 *********************************************************/
393 bool uid_wrapper_enabled(void);
394 #if ! defined(HAVE_CONSTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_INIT)
395 /* xlC and other oldschool compilers support (only) this */
396 #pragma init (uwrap_constructor)
398 void uwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
399 #if ! defined(HAVE_DESTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_FINI)
400 #pragma fini (uwrap_destructor)
402 void uwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
404 /*********************************************************
405 * UWRAP LIBC LOADER FUNCTIONS
406 *********************************************************/
413 static void *uwrap_load_lib_handle(enum uwrap_lib lib)
415 int flags = RTLD_LAZY;
420 const char *env_preload = getenv("LD_PRELOAD");
421 const char *env_deepbind = getenv("UID_WRAPPER_DISABLE_DEEPBIND");
422 bool enable_deepbind = true;
424 /* Don't do a deepbind if we run with libasan */
425 if (env_preload != NULL && strlen(env_preload) < 1024) {
426 const char *p = strstr(env_preload, "libasan.so");
428 enable_deepbind = false;
432 if (env_deepbind != NULL && strlen(env_deepbind) >= 1) {
433 enable_deepbind = false;
436 if (enable_deepbind) {
437 flags |= RTLD_DEEPBIND;
443 handle = uwrap.libc.handle;
444 if (handle == NULL) {
445 for (i = 10; i >= 0; i--) {
446 char soname[256] = {0};
448 snprintf(soname, sizeof(soname), "libc.so.%d", i);
449 handle = dlopen(soname, flags);
450 if (handle != NULL) {
454 /* glibc on Alpha and IA64 is libc.so.6.1 */
455 snprintf(soname, sizeof(soname), "libc.so.%d.1", i);
456 handle = dlopen(soname, flags);
457 if (handle != NULL) {
462 uwrap.libc.handle = handle;
465 case UWRAP_LIBPTHREAD:
466 handle = uwrap.libpthread.handle;
467 if (handle == NULL) {
468 handle = dlopen("libpthread.so.0", flags);
469 if (handle != NULL) {
476 if (handle == NULL) {
478 handle = uwrap.libc.handle = RTLD_NEXT;
481 "Failed to dlopen library: %s\n",
490 static void *_uwrap_bind_symbol(enum uwrap_lib lib, const char *fn_name)
495 handle = uwrap_load_lib_handle(lib);
497 func = dlsym(handle, fn_name);
500 "Failed to find %s: %s\n",
508 #define uwrap_bind_symbol_libc(sym_name) \
509 if (uwrap.libc.symbols._libc_##sym_name.obj == NULL) { \
510 uwrap.libc.symbols._libc_##sym_name.obj = \
511 _uwrap_bind_symbol(UWRAP_LIBC, #sym_name); \
514 #define uwrap_bind_symbol_libpthread(sym_name) \
515 if (uwrap.libpthread.symbols._libpthread_##sym_name.obj == NULL) { \
516 uwrap.libpthread.symbols._libpthread_##sym_name.obj = \
517 _uwrap_bind_symbol(UWRAP_LIBPTHREAD, #sym_name); \
520 /* DO NOT call this function during library initialization! */
521 static void __uwrap_bind_symbol_all_once(void)
523 uwrap_bind_symbol_libc(setuid);
524 uwrap_bind_symbol_libc(getuid);
526 uwrap_bind_symbol_libc(seteuid);
529 uwrap_bind_symbol_libc(setreuid);
531 #ifdef HAVE_SETRESUID
532 uwrap_bind_symbol_libc(setresuid);
534 #ifdef HAVE_GETRESUID
535 uwrap_bind_symbol_libc(getresuid);
537 uwrap_bind_symbol_libc(geteuid);
538 uwrap_bind_symbol_libc(setgid);
539 uwrap_bind_symbol_libc(getgid);
541 uwrap_bind_symbol_libc(setegid);
544 uwrap_bind_symbol_libc(setregid);
547 #ifdef HAVE_SETRESGID
548 uwrap_bind_symbol_libc(setresgid);
550 #ifdef HAVE_GETRESGID
551 uwrap_bind_symbol_libc(setresgid);
553 uwrap_bind_symbol_libc(getegid);
554 uwrap_bind_symbol_libc(getgroups);
555 uwrap_bind_symbol_libc(setgroups);
557 uwrap_bind_symbol_libc(syscall);
559 uwrap_bind_symbol_libpthread(pthread_create);
560 uwrap_bind_symbol_libpthread(pthread_exit);
563 static void uwrap_bind_symbol_all(void)
565 static pthread_once_t all_symbol_binding_once = PTHREAD_ONCE_INIT;
567 pthread_once(&all_symbol_binding_once, __uwrap_bind_symbol_all_once);
573 * Functions expeciall from libc need to be loaded individually, you can't load
574 * all at once or gdb will segfault at startup. The same applies to valgrind and
575 * has probably something todo with with the linker.
576 * So we need load each function at the point it is called the first time.
578 static int libc_setuid(uid_t uid)
580 uwrap_bind_symbol_all();
582 return uwrap.libc.symbols._libc_setuid.f(uid);
585 static uid_t libc_getuid(void)
587 uwrap_bind_symbol_all();
589 return uwrap.libc.symbols._libc_getuid.f();
593 static int libc_seteuid(uid_t euid)
595 uwrap_bind_symbol_all();
597 return uwrap.libc.symbols._libc_seteuid.f(euid);
602 static int libc_setreuid(uid_t ruid, uid_t euid)
604 uwrap_bind_symbol_all();
606 return uwrap.libc.symbols._libc_setreuid.f(ruid, euid);
610 #ifdef HAVE_SETRESUID
611 static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
613 uwrap_bind_symbol_all();
615 return uwrap.libc.symbols._libc_setresuid.f(ruid, euid, suid);
619 #ifdef HAVE_GETRESUID
620 static int libc_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
622 uwrap_bind_symbol_all();
624 return uwrap.libc.symbols._libc_getresuid.f(ruid, euid, suid);
628 static uid_t libc_geteuid(void)
630 uwrap_bind_symbol_all();
632 return uwrap.libc.symbols._libc_geteuid.f();
635 static int libc_setgid(gid_t gid)
637 uwrap_bind_symbol_all();
639 return uwrap.libc.symbols._libc_setgid.f(gid);
642 static gid_t libc_getgid(void)
644 uwrap_bind_symbol_all();
646 return uwrap.libc.symbols._libc_getgid.f();
650 static int libc_setegid(gid_t egid)
652 uwrap_bind_symbol_all();
654 return uwrap.libc.symbols._libc_setegid.f(egid);
659 static int libc_setregid(gid_t rgid, gid_t egid)
661 uwrap_bind_symbol_all();
663 return uwrap.libc.symbols._libc_setregid.f(rgid, egid);
667 #ifdef HAVE_SETRESGID
668 static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
670 uwrap_bind_symbol_all();
672 return uwrap.libc.symbols._libc_setresgid.f(rgid, egid, sgid);
676 #ifdef HAVE_GETRESGID
677 static int libc_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
679 uwrap_bind_symbol_all();
681 return uwrap.libc.symbols._libc_getresgid.f(rgid, egid, sgid);
685 static gid_t libc_getegid(void)
687 uwrap_bind_symbol_all();
689 return uwrap.libc.symbols._libc_getegid.f();
692 static int libc_getgroups(int size, gid_t list[])
694 uwrap_bind_symbol_all();
696 return uwrap.libc.symbols._libc_getgroups.f(size, list);
699 #ifdef HAVE___GETGROUPS_CHK
700 static int libc___getgroups_chk(int size, gid_t list[], size_t listlen)
702 uwrap_bind_symbol_libc(__getgroups_chk);
704 return uwrap.libc.symbols._libc___getgroups_chk.f(size,
708 #endif /* HAVE___GETGROUPS_CHK */
710 static int libc_setgroups(size_t size, const gid_t *list)
712 uwrap_bind_symbol_all();
714 return uwrap.libc.symbols._libc_setgroups.f(size, list);
718 DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
719 static long int libc_vsyscall(long int sysno, va_list va)
725 uwrap_bind_symbol_all();
727 for (i = 0; i < 8; i++) {
728 args[i] = va_arg(va, long int);
731 rc = uwrap.libc.symbols._libc_syscall.f(sysno,
745 static int libpthread_pthread_create(pthread_t *thread,
746 const pthread_attr_t *attr,
747 void *(*start_routine) (void *),
750 uwrap_bind_symbol_all();
751 return uwrap.libpthread.symbols._libpthread_pthread_create.f(thread,
758 * This part is "optimistic".
759 * Thread can ends without pthread_exit call.
761 static void libpthread_pthread_exit(void *retval)
763 uwrap_bind_symbol_all();
765 uwrap.libpthread.symbols._libpthread_pthread_exit.f(retval);
768 static void uwrap_pthread_exit(void *retval)
770 struct uwrap_thread *id = uwrap_tls_id;
772 UWRAP_LOG(UWRAP_LOG_DEBUG, "Cleanup thread");
774 UWRAP_LOCK(uwrap_id);
776 UWRAP_UNLOCK(uwrap_id);
777 libpthread_pthread_exit(retval);
781 UWRAP_DLIST_REMOVE(uwrap.ids, id);
782 SAFE_FREE(id->groups);
786 UWRAP_UNLOCK(uwrap_id);
788 libpthread_pthread_exit(retval);
791 void pthread_exit(void *retval)
793 if (!uid_wrapper_enabled()) {
794 libpthread_pthread_exit(retval);
797 uwrap_pthread_exit(retval);
799 /* Calm down gcc warning. */
803 struct uwrap_pthread_create_args {
804 struct uwrap_thread *id;
805 void *(*start_routine) (void *);
809 static void *uwrap_pthread_create_start(void *_a)
811 struct uwrap_pthread_create_args *a =
812 (struct uwrap_pthread_create_args *)_a;
813 void *(*start_routine) (void *) = a->start_routine;
815 struct uwrap_thread *id = a->id;
821 return start_routine(arg);
824 static int uwrap_pthread_create(pthread_t *thread,
825 const pthread_attr_t *attr,
826 void *(*start_routine) (void *),
829 struct uwrap_pthread_create_args *args;
830 struct uwrap_thread *src_id = uwrap_tls_id;
833 args = malloc(sizeof(struct uwrap_pthread_create_args));
835 UWRAP_LOG(UWRAP_LOG_ERROR,
836 "uwrap_pthread_create: Unable to allocate memory");
840 args->start_routine = start_routine;
843 args->id = calloc(1, sizeof(struct uwrap_thread));
844 if (args->id == NULL) {
846 UWRAP_LOG(UWRAP_LOG_ERROR,
847 "uwrap_pthread_create: Unable to allocate memory");
852 UWRAP_LOCK(uwrap_id);
854 args->id->groups = calloc(src_id->ngroups, sizeof(gid_t));
855 if (args->id->groups == NULL) {
856 UWRAP_UNLOCK(uwrap_id);
859 UWRAP_LOG(UWRAP_LOG_ERROR,
860 "uwrap_pthread_create: Unable to allocate memory again");
865 args->id->ruid = src_id->ruid;
866 args->id->euid = src_id->euid;
867 args->id->suid = src_id->suid;
869 args->id->rgid = src_id->rgid;
870 args->id->egid = src_id->egid;
871 args->id->sgid = src_id->sgid;
873 args->id->enabled = src_id->enabled;
875 args->id->ngroups = src_id->ngroups;
876 if (src_id->groups != NULL) {
877 memcpy(args->id->groups, src_id->groups,
878 sizeof(gid_t) * src_id->ngroups);
880 SAFE_FREE(args->id->groups);
883 UWRAP_DLIST_ADD(uwrap.ids, args->id);
884 UWRAP_UNLOCK(uwrap_id);
886 ret = libpthread_pthread_create(thread, attr,
887 uwrap_pthread_create_start,
896 int pthread_create(pthread_t *thread,
897 const pthread_attr_t *attr,
898 void *(*start_routine) (void *),
901 if (!uid_wrapper_enabled()) {
902 return libpthread_pthread_create(thread,
908 return uwrap_pthread_create(thread,
914 /*********************************************************
916 *********************************************************/
918 #define GROUP_STRING_SIZE 16384
919 #define GROUP_MAX_COUNT (GROUP_STRING_SIZE / (10 + 1))
922 * This function exports all the IDs of the current user so if
923 * we fork and then exec we can setup uid_wrapper in the new process
926 static void uwrap_export_ids(struct uwrap_thread *id)
928 char groups_str[GROUP_STRING_SIZE] = {0};
929 size_t groups_str_size = sizeof(groups_str);
930 char unsigned_str[16] = {0}; /* We need 10 + 1 (+ 1) */
934 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->ruid);
935 setenv("UID_WRAPPER_INITIAL_RUID", unsigned_str, 1);
937 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->euid);
938 setenv("UID_WRAPPER_INITIAL_EUID", unsigned_str, 1);
940 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->suid);
941 setenv("UID_WRAPPER_INITIAL_SUID", unsigned_str, 1);
944 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->rgid);
945 setenv("UID_WRAPPER_INITIAL_RGID", unsigned_str, 1);
947 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->egid);
948 setenv("UID_WRAPPER_INITIAL_EGID", unsigned_str, 1);
950 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->sgid);
951 setenv("UID_WRAPPER_INITIAL_SGID", unsigned_str, 1);
953 if (id->ngroups > GROUP_MAX_COUNT) {
954 UWRAP_LOG(UWRAP_LOG_ERROR,
955 "ERROR: Number of groups (%u) exceeds maximum value "
956 "uid_wrapper can handle (%u).",
963 for (i = 0; i < id->ngroups; i++) {
964 size_t groups_str_len = strlen(groups_str);
965 size_t groups_str_avail = groups_str_size - groups_str_len - 1;
968 len = snprintf(unsigned_str, sizeof(unsigned_str), ",%u", id->groups[i]);
970 UWRAP_LOG(UWRAP_LOG_ERROR,
971 "snprintf failed for groups[%d]=%u",
976 if (((size_t)len) >= groups_str_avail) {
977 UWRAP_LOG(UWRAP_LOG_ERROR,
978 "groups env string is to small for %d groups",
983 len = snprintf(groups_str + groups_str_len,
984 groups_str_size - groups_str_len,
986 i == 0 ? unsigned_str + 1 : unsigned_str);
988 UWRAP_LOG(UWRAP_LOG_ERROR,
989 "snprintf failed to create groups string at groups[%d]=%u",
996 if (id->ngroups == i) {
997 setenv("UID_WRAPPER_INITIAL_GROUPS", groups_str, 1);
999 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->ngroups);
1000 setenv("UID_WRAPPER_INITIAL_GROUPS_COUNT", unsigned_str, 1);
1004 static void uwrap_thread_prepare(void)
1006 struct uwrap_thread *id = uwrap_tls_id;
1009 * We bind all symbols to avoid deadlocks of the fork is interrupted by
1010 * a signal handler using a symbol of this library.
1012 uwrap_bind_symbol_all();
1016 /* uid_wrapper is loaded but not enabled */
1022 * What happens if another atfork prepare functions calls a uwrap
1023 * function? So disable it in case another atfork prepare function
1024 * calls a (s)uid function. We disable uid_wrapper only for thread
1025 * (process) which called fork.
1027 id->enabled = false;
1030 static void uwrap_thread_parent(void)
1032 struct uwrap_thread *id = uwrap_tls_id;
1034 /* uid_wrapper is loaded but not enabled */
1045 static void uwrap_thread_child(void)
1047 struct uwrap_thread *id = uwrap_tls_id;
1048 struct uwrap_thread *u = uwrap.ids;
1050 /* uid_wrapper is loaded but not enabled */
1057 * "Garbage collector" - Inspired by DESTRUCTOR.
1058 * All threads (except one which called fork()) are dead now.. Dave
1059 * That's what posix said...
1063 /* Skip this item. */
1064 u = uwrap.ids->next;
1068 UWRAP_DLIST_REMOVE(uwrap.ids, u);
1070 SAFE_FREE(u->groups);
1076 uwrap_export_ids(id);
1083 static unsigned long uwrap_get_xid_from_env(const char *envname)
1086 const char *env = NULL;
1089 env = getenv(envname);
1094 if (env[0] == '\0') {
1099 xid = strtoul(env, &endp, 10);
1109 * This initializes uid_wrapper with the IDs exported to the environment. Those
1110 * are normally set after we forked and executed.
1112 static void uwrap_init_env(struct uwrap_thread *id)
1119 xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_RUID");
1120 if (xid != ULONG_MAX) {
1121 id->ruid = (uid_t)xid;
1124 xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_EUID");
1125 if (xid != ULONG_MAX) {
1126 id->euid = (uid_t)xid;
1129 xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_SUID");
1130 if (xid != ULONG_MAX) {
1131 id->suid = (uid_t)xid;
1135 xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_RGID");
1136 if (xid != ULONG_MAX) {
1137 id->rgid = (gid_t)xid;
1140 xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_EGID");
1141 if (xid != ULONG_MAX) {
1142 id->egid = (gid_t)xid;
1145 xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_SGID");
1146 if (xid != ULONG_MAX) {
1147 id->sgid = (gid_t)xid;
1150 env = getenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
1151 if (env != NULL && env[0] != '\0') {
1155 n = strtol(env, &endp, 10);
1158 } else if (n > 0 && n < GROUP_MAX_COUNT) {
1161 unsetenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
1170 id->groups = calloc(ngroups, sizeof(gid_t));
1171 if (id->groups == NULL) {
1172 UWRAP_LOG(UWRAP_LOG_ERROR,
1173 "Unable to allocate memory");
1177 env = getenv("UID_WRAPPER_INITIAL_GROUPS");
1178 if (env != NULL && env[0] != '\0') {
1179 char *groups_str = NULL;
1180 char *saveptr = NULL;
1181 const char *p = NULL;
1183 groups_str = strdup(env);
1184 if (groups_str == NULL) {
1188 p = strtok_r(groups_str, ",", &saveptr);
1190 id->groups[i] = strtol(p, (char **)NULL, 10);
1193 p = strtok_r(NULL, ",", &saveptr);
1195 SAFE_FREE(groups_str);
1199 UWRAP_LOG(UWRAP_LOG_ERROR,
1200 "ERROR: The number of groups (%u) passed, "
1201 "does not match the number of groups (%u) "
1208 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize groups with %s", env);
1209 id->ngroups = ngroups;
1213 static void uwrap_init(void)
1217 UWRAP_LOCK(uwrap_id);
1219 if (uwrap.initialised) {
1220 struct uwrap_thread *id = uwrap_tls_id;
1222 if (uwrap.ids == NULL) {
1223 UWRAP_UNLOCK(uwrap_id);
1228 UWRAP_LOG(UWRAP_LOG_ERROR,
1229 "Invalid id for thread");
1233 UWRAP_UNLOCK(uwrap_id);
1237 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize uid_wrapper");
1239 uwrap.initialised = true;
1241 env = getenv("UID_WRAPPER");
1242 if (env != NULL && env[0] == '1') {
1243 const char *root = getenv("UID_WRAPPER_ROOT");
1244 struct uwrap_thread *id;
1246 id = calloc(1, sizeof(struct uwrap_thread));
1248 UWRAP_LOG(UWRAP_LOG_ERROR,
1249 "Unable to allocate memory for main id");
1253 UWRAP_DLIST_ADD(uwrap.ids, id);
1256 uwrap.myuid = libc_geteuid();
1257 uwrap.mygid = libc_getegid();
1259 /* put us in one group */
1260 if (root != NULL && root[0] == '1') {
1261 id->ruid = id->euid = id->suid = 0;
1262 id->rgid = id->egid = id->sgid = 0;
1264 id->groups = malloc(sizeof(gid_t) * 1);
1265 if (id->groups == NULL) {
1266 UWRAP_LOG(UWRAP_LOG_ERROR,
1267 "Unable to allocate memory");
1275 id->ruid = id->euid = id->suid = uwrap.myuid;
1276 id->rgid = id->egid = id->sgid = uwrap.mygid;
1278 id->ngroups = libc_getgroups(0, NULL);
1279 if (id->ngroups == -1) {
1280 UWRAP_LOG(UWRAP_LOG_ERROR,
1281 "Unable to call libc_getgroups in uwrap_init.");
1284 id->groups = malloc(sizeof(gid_t) * id->ngroups);
1285 if (id->groups == NULL) {
1286 UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
1289 if (libc_getgroups(id->ngroups, id->groups) == -1) {
1290 UWRAP_LOG(UWRAP_LOG_ERROR,
1291 "Unable to call libc_getgroups again in uwrap_init.");
1294 * Deallocation of uwrap.groups is handled by
1295 * library destructor.
1305 UWRAP_LOG(UWRAP_LOG_DEBUG,
1306 "Enabled uid_wrapper as %s (real uid=%u)",
1307 id->ruid == 0 ? "root" : "user",
1308 (unsigned int)uwrap.myuid);
1311 UWRAP_UNLOCK(uwrap_id);
1313 UWRAP_LOG(UWRAP_LOG_DEBUG, "Successfully initialized uid_wrapper");
1316 bool uid_wrapper_enabled(void)
1318 struct uwrap_thread *id = uwrap_tls_id;
1325 UWRAP_LOCK(uwrap_id);
1326 enabled = id->enabled;
1327 UWRAP_UNLOCK(uwrap_id);
1333 * UWRAP_SETxUID FUNCTIONS
1336 static int uwrap_setresuid_args(uid_t ruid, uid_t euid, uid_t suid)
1338 struct uwrap_thread *id = uwrap_tls_id;
1340 UWRAP_LOG(UWRAP_LOG_TRACE,
1341 "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1342 id->ruid, ruid, id->euid, euid, id->suid, suid);
1344 if (id->euid != 0) {
1345 if (ruid != (uid_t)-1 &&
1352 if (euid != (uid_t)-1 &&
1359 if (suid != (uid_t)-1 &&
1371 static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
1373 struct uwrap_thread *id = uwrap_tls_id;
1376 UWRAP_LOG(UWRAP_LOG_TRACE,
1377 "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1378 id->ruid, ruid, id->euid, euid, id->suid, suid);
1380 rc = uwrap_setresuid_args(ruid, euid, suid);
1385 UWRAP_LOCK(uwrap_id);
1387 if (ruid != (uid_t)-1) {
1391 if (euid != (uid_t)-1) {
1395 if (suid != (uid_t)-1) {
1399 UWRAP_UNLOCK(uwrap_id);
1404 static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
1406 struct uwrap_thread *id = uwrap_tls_id;
1409 UWRAP_LOG(UWRAP_LOG_TRACE,
1410 "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
1411 id->ruid, ruid, id->euid, euid, id->suid, suid);
1413 rc = uwrap_setresuid_args(ruid, euid, suid);
1418 UWRAP_LOCK(uwrap_id);
1420 for (id = uwrap.ids; id; id = id->next) {
1421 if (ruid != (uid_t)-1) {
1425 if (euid != (uid_t)-1) {
1429 if (suid != (uid_t)-1) {
1434 UWRAP_UNLOCK(uwrap_id);
1439 static int uwrap_setreuid_args(uid_t ruid, uid_t euid,
1444 struct uwrap_thread *id = uwrap_tls_id;
1445 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1447 UWRAP_LOG(UWRAP_LOG_TRACE,
1448 "ruid %d -> %d, euid %d -> %d",
1449 id->ruid, ruid, id->euid, euid);
1451 if (ruid != (uid_t)-1) {
1453 if (ruid != id->ruid &&
1461 if (euid != (uid_t)-1) {
1463 if (euid != id->ruid &&
1472 if (ruid != (uid_t) -1 ||
1473 (euid != (uid_t)-1 && id->ruid != euid)) {
1474 new_suid = new_euid;
1477 *_new_ruid = new_ruid;
1478 *_new_euid = new_euid;
1479 *_new_suid = new_suid;
1484 static int uwrap_setreuid_thread(uid_t ruid, uid_t euid)
1486 struct uwrap_thread *id = uwrap_tls_id;
1487 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1490 UWRAP_LOG(UWRAP_LOG_TRACE,
1491 "ruid %d -> %d, euid %d -> %d",
1492 id->ruid, ruid, id->euid, euid);
1494 rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
1499 return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
1502 #ifdef HAVE_SETREUID
1503 static int uwrap_setreuid(uid_t ruid, uid_t euid)
1505 struct uwrap_thread *id = uwrap_tls_id;
1506 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1509 UWRAP_LOG(UWRAP_LOG_TRACE,
1510 "ruid %d -> %d, euid %d -> %d",
1511 id->ruid, ruid, id->euid, euid);
1513 rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
1518 return uwrap_setresuid(new_ruid, new_euid, new_suid);
1522 static int uwrap_setuid_args(uid_t uid,
1527 struct uwrap_thread *id = uwrap_tls_id;
1529 UWRAP_LOG(UWRAP_LOG_TRACE,
1533 if (uid == (uid_t)-1) {
1538 if (id->euid == 0) {
1539 *new_suid = *new_ruid = uid;
1540 } else if (uid != id->ruid &&
1551 static int uwrap_setuid_thread(uid_t uid)
1553 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1556 rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
1561 return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
1564 static int uwrap_setuid(uid_t uid)
1566 uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
1569 rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
1574 return uwrap_setresuid(new_ruid, new_euid, new_suid);
1578 * UWRAP_GETxUID FUNCTIONS
1581 #ifdef HAVE_GETRESUID
1582 static int uwrap_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
1584 struct uwrap_thread *id = uwrap_tls_id;
1586 UWRAP_LOCK(uwrap_id);
1592 UWRAP_UNLOCK(uwrap_id);
1598 #ifdef HAVE_GETRESGID
1599 static int uwrap_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
1601 struct uwrap_thread *id = uwrap_tls_id;
1603 UWRAP_LOCK(uwrap_id);
1609 UWRAP_UNLOCK(uwrap_id);
1616 * UWRAP_SETxGID FUNCTIONS
1619 static int uwrap_setresgid_args(gid_t rgid, gid_t egid, gid_t sgid)
1621 struct uwrap_thread *id = uwrap_tls_id;
1623 UWRAP_LOG(UWRAP_LOG_TRACE,
1624 "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1625 id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1627 if (id->euid != 0) {
1628 if (rgid != (gid_t)-1 &&
1635 if (egid != (gid_t)-1 &&
1642 if (sgid != (gid_t)-1 &&
1654 static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
1656 struct uwrap_thread *id = uwrap_tls_id;
1659 UWRAP_LOG(UWRAP_LOG_TRACE,
1660 "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1661 id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1663 rc = uwrap_setresgid_args(rgid, egid, sgid);
1668 UWRAP_LOCK(uwrap_id);
1670 if (rgid != (gid_t)-1) {
1674 if (egid != (gid_t)-1) {
1678 if (sgid != (gid_t)-1) {
1682 UWRAP_UNLOCK(uwrap_id);
1687 static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
1689 struct uwrap_thread *id = uwrap_tls_id;
1692 UWRAP_LOG(UWRAP_LOG_TRACE,
1693 "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
1694 id->rgid, rgid, id->egid, egid, id->sgid, sgid);
1696 rc = uwrap_setresgid_args(rgid, egid, sgid);
1701 UWRAP_LOCK(uwrap_id);
1703 for (id = uwrap.ids; id; id = id->next) {
1704 if (rgid != (gid_t)-1) {
1708 if (egid != (gid_t)-1) {
1712 if (sgid != (gid_t)-1) {
1717 UWRAP_UNLOCK(uwrap_id);
1722 static int uwrap_setregid_args(gid_t rgid, gid_t egid,
1727 struct uwrap_thread *id = uwrap_tls_id;
1728 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1730 UWRAP_LOG(UWRAP_LOG_TRACE,
1731 "rgid %d -> %d, egid %d -> %d",
1732 id->rgid, rgid, id->egid, egid);
1734 if (rgid != (gid_t)-1) {
1736 if (rgid != id->rgid &&
1744 if (egid != (gid_t)-1) {
1746 if (egid != id->rgid &&
1755 if (rgid != (gid_t) -1 ||
1756 (egid != (gid_t)-1 && id->rgid != egid)) {
1757 new_sgid = new_egid;
1760 *_new_rgid = new_rgid;
1761 *_new_egid = new_egid;
1762 *_new_sgid = new_sgid;
1767 static int uwrap_setregid_thread(gid_t rgid, gid_t egid)
1769 struct uwrap_thread *id = uwrap_tls_id;
1770 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1773 UWRAP_LOG(UWRAP_LOG_TRACE,
1774 "rgid %d -> %d, egid %d -> %d",
1775 id->rgid, rgid, id->egid, egid);
1777 rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
1782 return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
1785 #ifdef HAVE_SETREGID
1786 static int uwrap_setregid(gid_t rgid, gid_t egid)
1788 struct uwrap_thread *id = uwrap_tls_id;
1789 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1792 UWRAP_LOG(UWRAP_LOG_TRACE,
1793 "rgid %d -> %d, egid %d -> %d",
1794 id->rgid, rgid, id->egid, egid);
1796 rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
1801 return uwrap_setresgid(new_rgid, new_egid, new_sgid);
1805 static int uwrap_setgid_args(gid_t gid,
1810 struct uwrap_thread *id = uwrap_tls_id;
1812 UWRAP_LOG(UWRAP_LOG_TRACE,
1816 if (gid == (gid_t)-1) {
1821 if (id->euid == 0) {
1822 *new_sgid = *new_rgid = gid;
1823 } else if (gid != id->rgid &&
1834 static int uwrap_setgid_thread(gid_t gid)
1836 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1839 rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
1844 return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
1847 static int uwrap_setgid(gid_t gid)
1849 gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
1852 rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
1857 return uwrap_setresgid(new_rgid, new_egid, new_sgid);
1863 int setuid(uid_t uid)
1865 if (!uid_wrapper_enabled()) {
1866 return libc_setuid(uid);
1870 return uwrap_setuid(uid);
1874 int seteuid(uid_t euid)
1876 if (!uid_wrapper_enabled()) {
1877 return libc_seteuid(euid);
1880 /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
1881 if (euid == (uid_t)-1) {
1887 return uwrap_setresuid(-1, euid, -1);
1891 #ifdef HAVE_SETREUID
1892 int setreuid(uid_t ruid, uid_t euid)
1894 if (!uid_wrapper_enabled()) {
1895 return libc_setreuid(ruid, euid);
1899 return uwrap_setreuid(ruid, euid);
1903 #ifdef HAVE_SETRESUID
1904 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
1906 if (!uid_wrapper_enabled()) {
1907 return libc_setresuid(ruid, euid, suid);
1911 return uwrap_setresuid(ruid, euid, suid);
1915 #ifdef HAVE_GETRESUID
1916 int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
1918 if (!uid_wrapper_enabled()) {
1919 return libc_getresuid(ruid, euid, suid);
1923 return uwrap_getresuid(ruid, euid, suid);
1930 static uid_t uwrap_getuid(void)
1932 struct uwrap_thread *id = uwrap_tls_id;
1935 UWRAP_LOCK(uwrap_id);
1937 UWRAP_UNLOCK(uwrap_id);
1944 if (!uid_wrapper_enabled()) {
1945 return libc_getuid();
1949 return uwrap_getuid();
1955 static uid_t uwrap_geteuid(void)
1957 const char *env = getenv("UID_WRAPPER_MYUID");
1958 struct uwrap_thread *id = uwrap_tls_id;
1961 UWRAP_LOCK(uwrap_id);
1963 UWRAP_UNLOCK(uwrap_id);
1965 /* Disable root and return myuid */
1966 if (env != NULL && env[0] == '1') {
1975 if (!uid_wrapper_enabled()) {
1976 return libc_geteuid();
1980 return uwrap_geteuid();
1986 int setgid(gid_t gid)
1988 if (!uid_wrapper_enabled()) {
1989 return libc_setgid(gid);
1993 return uwrap_setgid(gid);
1997 int setegid(gid_t egid)
1999 if (!uid_wrapper_enabled()) {
2000 return libc_setegid(egid);
2003 /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
2004 if (egid == (gid_t)-1) {
2010 return uwrap_setresgid(-1, egid, -1);
2014 #ifdef HAVE_SETREGID
2015 int setregid(gid_t rgid, gid_t egid)
2017 if (!uid_wrapper_enabled()) {
2018 return libc_setregid(rgid, egid);
2022 return uwrap_setregid(rgid, egid);
2026 #ifdef HAVE_SETRESGID
2027 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
2029 if (!uid_wrapper_enabled()) {
2030 return libc_setresgid(rgid, egid, sgid);
2034 return uwrap_setresgid(rgid, egid, sgid);
2038 #ifdef HAVE_GETRESGID
2039 int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
2041 if (!uid_wrapper_enabled()) {
2042 return libc_getresgid(rgid, egid, sgid);
2046 return uwrap_getresgid(rgid, egid, sgid);
2053 static gid_t uwrap_getgid(void)
2055 struct uwrap_thread *id = uwrap_tls_id;
2058 UWRAP_LOCK(uwrap_id);
2060 UWRAP_UNLOCK(uwrap_id);
2067 if (!uid_wrapper_enabled()) {
2068 return libc_getgid();
2072 return uwrap_getgid();
2078 static uid_t uwrap_getegid(void)
2080 struct uwrap_thread *id = uwrap_tls_id;
2083 UWRAP_LOCK(uwrap_id);
2085 UWRAP_UNLOCK(uwrap_id);
2092 if (!uid_wrapper_enabled()) {
2093 return libc_getegid();
2097 return uwrap_getegid();
2100 static int uwrap_setgroups_thread(size_t size, const gid_t *list)
2102 struct uwrap_thread *id = uwrap_tls_id;
2105 UWRAP_LOCK(uwrap_id);
2108 SAFE_FREE(id->groups);
2110 } else if (size > 0) {
2113 tmp = realloc(id->groups, sizeof(gid_t) * size);
2120 memcpy(id->groups, list, size * sizeof(gid_t));
2125 UWRAP_UNLOCK(uwrap_id);
2130 static int uwrap_setgroups(size_t size, const gid_t *list)
2132 struct uwrap_thread *id;
2135 UWRAP_LOCK(uwrap_id);
2138 for (id = uwrap.ids; id; id = id->next) {
2139 SAFE_FREE(id->groups);
2143 } else if (size > 0) {
2146 for (id = uwrap.ids; id; id = id->next) {
2147 tmp = realloc(id->groups, sizeof(gid_t) * size);
2155 memcpy(id->groups, list, size * sizeof(gid_t));
2161 UWRAP_UNLOCK(uwrap_id);
2166 #ifdef HAVE_SETGROUPS_INT
2167 int setgroups(int size, const gid_t *list)
2169 int setgroups(size_t size, const gid_t *list)
2172 if (!uid_wrapper_enabled()) {
2173 return libc_setgroups(size, list);
2177 return uwrap_setgroups(size, list);
2180 static int uwrap_getgroups(int size, gid_t *list)
2182 struct uwrap_thread *id = uwrap_tls_id;
2185 UWRAP_LOCK(uwrap_id);
2186 ngroups = id->ngroups;
2188 if (size > ngroups) {
2194 if (size < ngroups) {
2198 memcpy(list, id->groups, size * sizeof(gid_t));
2201 UWRAP_UNLOCK(uwrap_id);
2206 int getgroups(int size, gid_t *list)
2208 if (!uid_wrapper_enabled()) {
2209 return libc_getgroups(size, list);
2213 return uwrap_getgroups(size, list);
2216 #ifdef HAVE___GETGROUPS_CHK
2217 static int uwrap___getgroups_chk(int size, gid_t *list, size_t listlen)
2219 if (size * sizeof(gid_t) > listlen) {
2220 UWRAP_LOG(UWRAP_LOG_DEBUG, "Buffer overflow detected");
2224 return uwrap_getgroups(size, list);
2227 int __getgroups_chk(int size, gid_t *list, size_t listlen);
2229 int __getgroups_chk(int size, gid_t *list, size_t listlen)
2231 if (!uid_wrapper_enabled()) {
2232 return libc___getgroups_chk(size, list, listlen);
2236 return uwrap___getgroups_chk(size, list, listlen);
2238 #endif /* HAVE___GETGROUPS_CHK */
2240 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
2241 && (defined(SYS_setreuid) || defined(SYS_setreuid32))
2242 static long int uwrap_syscall (long int sysno, va_list vp)
2253 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2257 rc = uwrap_getgid();
2262 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2266 rc = uwrap_getegid();
2269 #endif /* SYS_getegid */
2271 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2275 gid_t gid = (gid_t) va_arg(vp, gid_t);
2277 rc = uwrap_setgid_thread(gid);
2281 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2282 case SYS_setregid32:
2285 gid_t rgid = (gid_t) va_arg(vp, gid_t);
2286 gid_t egid = (gid_t) va_arg(vp, gid_t);
2288 rc = uwrap_setregid_thread(rgid, egid);
2291 #ifdef SYS_setresgid
2293 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2294 case SYS_setresgid32:
2297 gid_t rgid = (gid_t) va_arg(vp, gid_t);
2298 gid_t egid = (gid_t) va_arg(vp, gid_t);
2299 gid_t sgid = (gid_t) va_arg(vp, gid_t);
2301 rc = uwrap_setresgid_thread(rgid, egid, sgid);
2304 #endif /* SYS_setresgid */
2305 #if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
2307 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2308 case SYS_getresgid32:
2311 gid_t *rgid = (gid_t *) va_arg(vp, gid_t *);
2312 gid_t *egid = (gid_t *) va_arg(vp, gid_t *);
2313 gid_t *sgid = (gid_t *) va_arg(vp, gid_t *);
2315 rc = uwrap_getresgid(rgid, egid, sgid);
2318 #endif /* SYS_getresgid && HAVE_GETRESGID */
2326 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2330 rc = uwrap_getuid();
2335 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2339 rc = uwrap_geteuid();
2342 #endif /* SYS_geteuid */
2344 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2348 uid_t uid = (uid_t) va_arg(vp, uid_t);
2350 rc = uwrap_setuid_thread(uid);
2354 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2355 case SYS_setreuid32:
2358 uid_t ruid = (uid_t) va_arg(vp, uid_t);
2359 uid_t euid = (uid_t) va_arg(vp, uid_t);
2361 rc = uwrap_setreuid_thread(ruid, euid);
2364 #ifdef SYS_setresuid
2366 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2367 case SYS_setresuid32:
2370 uid_t ruid = (uid_t) va_arg(vp, uid_t);
2371 uid_t euid = (uid_t) va_arg(vp, uid_t);
2372 uid_t suid = (uid_t) va_arg(vp, uid_t);
2374 rc = uwrap_setresuid_thread(ruid, euid, suid);
2377 #endif /* SYS_setresuid */
2378 #if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
2380 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2381 case SYS_getresuid32:
2384 uid_t *ruid = (uid_t *) va_arg(vp, uid_t *);
2385 uid_t *euid = (uid_t *) va_arg(vp, uid_t *);
2386 uid_t *suid = (uid_t *) va_arg(vp, uid_t *);
2388 rc = uwrap_getresuid(ruid, euid, suid);
2391 #endif /* SYS_getresuid && HAVE_GETRESUID*/
2394 #ifdef HAVE_LINUX_32BIT_SYSCALLS
2395 case SYS_setgroups32:
2398 size_t size = (size_t) va_arg(vp, size_t);
2399 gid_t *list = (gid_t *) va_arg(vp, int *);
2401 rc = uwrap_setgroups_thread(size, list);
2405 UWRAP_LOG(UWRAP_LOG_DEBUG,
2406 "UID_WRAPPER calling non-wrapped syscall %lu",
2409 rc = libc_vsyscall(sysno, vp);
2417 #ifdef HAVE_SYSCALL_INT
2418 int syscall (int sysno, ...)
2420 long int syscall (long int sysno, ...)
2423 #ifdef HAVE_SYSCALL_INT
2430 va_start(va, sysno);
2432 if (!uid_wrapper_enabled()) {
2433 rc = libc_vsyscall(sysno, va);
2439 rc = uwrap_syscall(sysno, va);
2444 #endif /* HAVE_SYSCALL */
2445 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
2447 /****************************
2449 ***************************/
2451 void uwrap_constructor(void)
2453 char *glibc_malloc_lock_bug;
2456 * This is a workaround for a bug in glibc < 2.24:
2458 * The child handler for the malloc() function is called and locks the
2459 * mutex. Then our child handler is called and we try to call setenv().
2460 * setenv() wants to malloc and tries to aquire the lock for malloc and
2461 * we end up in a deadlock.
2463 * So as a workaround we need to call malloc once before we setup the
2466 * See https://sourceware.org/bugzilla/show_bug.cgi?id=16742
2468 glibc_malloc_lock_bug = malloc(1);
2469 if (glibc_malloc_lock_bug == NULL) {
2472 glibc_malloc_lock_bug[0] = '\0';
2475 * If we hold a lock and the application forks, then the child
2476 * is not able to unlock the mutex and we are in a deadlock.
2477 * This should prevent such deadlocks.
2479 pthread_atfork(&uwrap_thread_prepare,
2480 &uwrap_thread_parent,
2481 &uwrap_thread_child);
2483 free(glibc_malloc_lock_bug);
2485 /* Here is safe place to call uwrap_init() and initialize data
2491 /****************************
2493 ***************************/
2496 * This function is called when the library is unloaded and makes sure that
2497 * resources are freed.
2499 void uwrap_destructor(void)
2501 struct uwrap_thread *u = uwrap.ids;
2506 UWRAP_DLIST_REMOVE(uwrap.ids, u);
2508 SAFE_FREE(u->groups);
2515 if (uwrap.libc.handle != NULL
2517 && uwrap.libc.handle != RTLD_NEXT
2520 dlclose(uwrap.libc.handle);
2523 if (uwrap.libpthread.handle != NULL) {
2524 dlclose(uwrap.libpthread.handle);