LCOV - code coverage report
Current view: top level - third_party/uid_wrapper - uid_wrapper.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 603 1090 55.3 %
Date: 2024-02-28 12:06:22 Functions: 44 74 59.5 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2009      Andrew Tridgell
       3             :  * Copyright (c) 2011-2013 Andreas Schneider <asn@samba.org>
       4             :  *
       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.
       9             :  *
      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.
      14             :  *
      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/>.
      17             :  */
      18             : 
      19             : #include "config.h"
      20             : 
      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>
      38             : 
      39             : #include <pthread.h>
      40             : 
      41             : #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
      42             : # define UWRAP_THREAD __thread
      43             : #else
      44             : # define UWRAP_THREAD
      45             : #endif
      46             : 
      47             : #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
      48             : #define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
      49             : #else
      50             : #define CONSTRUCTOR_ATTRIBUTE
      51             : #endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
      52             : 
      53             : #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
      54             : #define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
      55             : #else
      56             : #define DESTRUCTOR_ATTRIBUTE
      57             : #endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
      58             : 
      59             : #ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
      60             : #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address))
      61             : #else /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
      62             : #define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
      63             : #endif /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
      64             : 
      65             : /* GCC have printf type attribute check. */
      66             : #ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
      67             : #define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
      68             : #else
      69             : #define PRINTF_ATTRIBUTE(a,b)
      70             : #endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
      71             : 
      72             : #ifndef FALL_THROUGH
      73             : # ifdef HAVE_FALLTHROUGH_ATTRIBUTE
      74             : #  define FALL_THROUGH __attribute__ ((fallthrough))
      75             : # else /* HAVE_FALLTHROUGH_ATTRIBUTE */
      76             : #  define FALL_THROUGH
      77             : # endif /* HAVE_FALLTHROUGH_ATTRIBUTE */
      78             : #endif /* FALL_THROUGH */
      79             : 
      80             : #define UWRAP_DLIST_ADD(list,item) do { \
      81             :         if (!(list)) { \
      82             :                 (item)->prev = NULL; \
      83             :                 (item)->next = NULL; \
      84             :                 (list)          = (item); \
      85             :         } else { \
      86             :                 (item)->prev = NULL; \
      87             :                 (item)->next = (list); \
      88             :                 (list)->prev = (item); \
      89             :                 (list)          = (item); \
      90             :         } \
      91             : } while (0)
      92             : 
      93             : #define UWRAP_DLIST_REMOVE(list,item) do { \
      94             :         if ((list) == (item)) { \
      95             :                 (list)          = (item)->next; \
      96             :                 if (list) { \
      97             :                         (list)->prev = NULL; \
      98             :                 } \
      99             :         } else { \
     100             :                 if ((item)->prev) { \
     101             :                         (item)->prev->next        = (item)->next; \
     102             :                 } \
     103             :                 if ((item)->next) { \
     104             :                         (item)->next->prev        = (item)->prev; \
     105             :                 } \
     106             :         } \
     107             :         (item)->prev = NULL; \
     108             :         (item)->next = NULL; \
     109             : } while (0)
     110             : 
     111             : #ifndef SAFE_FREE
     112             : #define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
     113             : #endif
     114             : 
     115             : /*****************
     116             :  * LOGGING
     117             :  *****************/
     118             : 
     119             : enum uwrap_dbglvl_e {
     120             :         UWRAP_LOG_ERROR = 0,
     121             :         UWRAP_LOG_WARN,
     122             :         UWRAP_LOG_DEBUG,
     123             :         UWRAP_LOG_TRACE
     124             : };
     125             : 
     126             : #ifndef HAVE_GETPROGNAME
     127    52183530 : static const char *getprogname(void)
     128             : {
     129             : #if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
     130    52183530 :         return program_invocation_short_name;
     131             : #elif defined(HAVE_GETEXECNAME)
     132             :         return getexecname();
     133             : #else
     134             :         return NULL;
     135             : #endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
     136             : }
     137             : #endif /* HAVE_GETPROGNAME */
     138             : 
     139             : static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
     140             : # define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __func__, __VA_ARGS__)
     141             : 
     142    52183530 : static void uwrap_log(enum uwrap_dbglvl_e dbglvl, const char *function, const char *format, ...)
     143             : {
     144      122195 :         char buffer[1024];
     145      122195 :         va_list va;
     146      122195 :         const char *d;
     147    52183530 :         unsigned int lvl = 0;
     148    52183530 :         const char *prefix = "UWRAP";
     149    52183530 :         const char *progname = getprogname();
     150             : 
     151    52183530 :         d = getenv("UID_WRAPPER_DEBUGLEVEL");
     152    52183530 :         if (d != NULL) {
     153           0 :                 lvl = atoi(d);
     154             :         }
     155             : 
     156    52183530 :         if (lvl < dbglvl) {
     157    52183530 :                 return;
     158             :         }
     159             : 
     160           0 :         va_start(va, format);
     161           0 :         vsnprintf(buffer, sizeof(buffer), format, va);
     162           0 :         va_end(va);
     163             : 
     164           0 :         switch (dbglvl) {
     165           0 :                 case UWRAP_LOG_ERROR:
     166           0 :                         prefix = "UWRAP_ERROR";
     167           0 :                         break;
     168           0 :                 case UWRAP_LOG_WARN:
     169           0 :                         prefix = "UWRAP_WARN";
     170           0 :                         break;
     171           0 :                 case UWRAP_LOG_DEBUG:
     172           0 :                         prefix = "UWRAP_DEBUG";
     173           0 :                         break;
     174           0 :                 case UWRAP_LOG_TRACE:
     175           0 :                         prefix = "UWRAP_TRACE";
     176           0 :                         break;
     177             :         }
     178             : 
     179           0 :         if (progname == NULL) {
     180           0 :                 progname = "<unknown>";
     181             :         }
     182             : 
     183           0 :         fprintf(stderr,
     184             :                 "%s[%s (%u)] - %s: %s\n",
     185             :                 prefix,
     186             :                 progname,
     187           0 :                 (int)getpid(),
     188             :                 function,
     189             :                 buffer);
     190             : }
     191             : 
     192             : /*****************
     193             :  * LIBC
     194             :  *****************/
     195             : 
     196             : #define LIBC_NAME "libc.so"
     197             : 
     198             : typedef int (*__libc_setuid)(uid_t uid);
     199             : 
     200             : typedef uid_t (*__libc_getuid)(void);
     201             : 
     202             : #ifdef HAVE_SETEUID
     203             : typedef int (*__libc_seteuid)(uid_t euid);
     204             : #endif
     205             : 
     206             : #ifdef HAVE_SETREUID
     207             : typedef int (*__libc_setreuid)(uid_t ruid, uid_t euid);
     208             : #endif
     209             : 
     210             : #ifdef HAVE_SETRESUID
     211             : typedef int (*__libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
     212             : #endif
     213             : 
     214             : #ifdef HAVE_GETRESUID
     215             : typedef int (*__libc_getresuid)(uid_t *ruid, uid_t *euid, uid_t *suid);
     216             : #endif
     217             : 
     218             : typedef uid_t (*__libc_geteuid)(void);
     219             : 
     220             : typedef int (*__libc_setgid)(gid_t gid);
     221             : 
     222             : typedef gid_t (*__libc_getgid)(void);
     223             : 
     224             : #ifdef HAVE_SETEGID
     225             : typedef int (*__libc_setegid)(uid_t egid);
     226             : #endif
     227             : 
     228             : #ifdef HAVE_SETREGID
     229             : typedef int (*__libc_setregid)(uid_t rgid, uid_t egid);
     230             : #endif
     231             : 
     232             : #ifdef HAVE_SETRESGID
     233             : typedef int (*__libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
     234             : #endif
     235             : 
     236             : #ifdef HAVE_GETRESGID
     237             : typedef int (*__libc_getresgid)(gid_t *rgid, gid_t *egid, gid_t *sgid);
     238             : #endif
     239             : 
     240             : typedef gid_t (*__libc_getegid)(void);
     241             : 
     242             : typedef int (*__libc_getgroups)(int size, gid_t list[]);
     243             : #ifdef HAVE___GETGROUPS_CHK
     244             : typedef int (*__libc___getgroups_chk)(int size, gid_t list[], size_t listlen);
     245             : #endif
     246             : 
     247             : typedef int (*__libc_setgroups)(size_t size, const gid_t *list);
     248             : 
     249             : #ifdef HAVE_SYSCALL
     250             : typedef long int (*__libc_syscall)(long int sysno, ...);
     251             : #endif
     252             : 
     253             : #define UWRAP_SYMBOL_ENTRY(i) \
     254             :         union { \
     255             :                 __libc_##i f; \
     256             :                 void *obj; \
     257             :         } _libc_##i
     258             : 
     259             : struct uwrap_libc_symbols {
     260             :         UWRAP_SYMBOL_ENTRY(setuid);
     261             :         UWRAP_SYMBOL_ENTRY(getuid);
     262             : #ifdef HAVE_SETEUID
     263             :         UWRAP_SYMBOL_ENTRY(seteuid);
     264             : #endif
     265             : #ifdef HAVE_SETREUID
     266             :         UWRAP_SYMBOL_ENTRY(setreuid);
     267             : #endif
     268             : #ifdef HAVE_SETRESUID
     269             :         UWRAP_SYMBOL_ENTRY(setresuid);
     270             : #endif
     271             : #ifdef HAVE_GETRESUID
     272             :         UWRAP_SYMBOL_ENTRY(getresuid);
     273             : #endif
     274             :         UWRAP_SYMBOL_ENTRY(geteuid);
     275             :         UWRAP_SYMBOL_ENTRY(setgid);
     276             :         UWRAP_SYMBOL_ENTRY(getgid);
     277             : #ifdef HAVE_SETEGID
     278             :         UWRAP_SYMBOL_ENTRY(setegid);
     279             : #endif
     280             : #ifdef HAVE_SETREGID
     281             :         UWRAP_SYMBOL_ENTRY(setregid);
     282             : #endif
     283             : #ifdef HAVE_SETRESGID
     284             :         UWRAP_SYMBOL_ENTRY(setresgid);
     285             : #endif
     286             : #ifdef HAVE_GETRESGID
     287             :         UWRAP_SYMBOL_ENTRY(getresgid);
     288             : #endif
     289             :         UWRAP_SYMBOL_ENTRY(getegid);
     290             :         UWRAP_SYMBOL_ENTRY(getgroups);
     291             : #ifdef HAVE___GETGROUPS_CHK
     292             :         UWRAP_SYMBOL_ENTRY(__getgroups_chk);
     293             : #endif
     294             :         UWRAP_SYMBOL_ENTRY(setgroups);
     295             : #ifdef HAVE_SYSCALL
     296             :         UWRAP_SYMBOL_ENTRY(syscall);
     297             : #endif
     298             : };
     299             : #undef UWRAP_SYMBOL_ENTRY
     300             : 
     301             : #define UWRAP_SYMBOL_ENTRY(i)         \
     302             :         union {                       \
     303             :                 __rtld_default_##i f; \
     304             :                 void *obj;            \
     305             :         } _rtld_default_##i
     306             : 
     307             : #ifdef HAVE_SYSCALL
     308             : typedef bool (*__rtld_default_socket_wrapper_syscall_valid)(long int sysno);
     309             : typedef long int (*__rtld_default_socket_wrapper_syscall_va)(long int sysno,
     310             :                                                              va_list va);
     311             : #endif
     312             : 
     313             : struct uwrap_rtld_default_symbols {
     314             : #ifdef HAVE_SYSCALL
     315             :         UWRAP_SYMBOL_ENTRY(socket_wrapper_syscall_valid);
     316             :         UWRAP_SYMBOL_ENTRY(socket_wrapper_syscall_va);
     317             : #else
     318             :         uint8_t dummy;
     319             : #endif
     320             : };
     321             : #undef UWRAP_SYMBOL_ENTRY
     322             : 
     323             : /*****************
     324             :  * LIBPTHREAD
     325             :  *****************/
     326             : /* Yeah... I'm pig. I overloading macro here... So what? */
     327             : #define UWRAP_SYMBOL_ENTRY(i) \
     328             :         union { \
     329             :                 __libpthread_##i f; \
     330             :                 void *obj; \
     331             :         } _libpthread_##i
     332             : 
     333             : typedef int (*__libpthread_pthread_create)(pthread_t *thread,
     334             :                                     const pthread_attr_t *attr,
     335             :                                     void *(*start_routine) (void *),
     336             :                                     void *arg);
     337             : typedef void (*__libpthread_pthread_exit)(void *retval);
     338             : 
     339             : struct uwrap_libpthread_symbols {
     340             :         UWRAP_SYMBOL_ENTRY(pthread_create);
     341             :         UWRAP_SYMBOL_ENTRY(pthread_exit);
     342             : };
     343             : #undef UWRAP_SYMBOL_ENTRY
     344             : 
     345             : /*
     346             :  * We keep the virtualised euid/egid/groups information here
     347             :  */
     348             : struct uwrap_thread {
     349             :         bool enabled;
     350             : 
     351             :         uid_t ruid;
     352             :         uid_t euid;
     353             :         uid_t suid;
     354             : 
     355             :         gid_t rgid;
     356             :         gid_t egid;
     357             :         gid_t sgid;
     358             : 
     359             :         int ngroups;
     360             :         gid_t *groups;
     361             : 
     362             :         struct uwrap_thread *next;
     363             :         struct uwrap_thread *prev;
     364             : };
     365             : 
     366             : struct uwrap {
     367             :         struct {
     368             :                 void *handle;
     369             :                 struct uwrap_libc_symbols symbols;
     370             :         } libc;
     371             : 
     372             :         struct {
     373             :                 struct uwrap_rtld_default_symbols symbols;
     374             :         } rtld_default;
     375             : 
     376             :         struct {
     377             :                 void *handle;
     378             :                 struct uwrap_libpthread_symbols symbols;
     379             :         } libpthread;
     380             : 
     381             :         bool initialised;
     382             : 
     383             :         /* Real uid and gid of user who run uid wrapper */
     384             :         uid_t myuid;
     385             :         gid_t mygid;
     386             : 
     387             :         struct uwrap_thread *ids;
     388             : };
     389             : 
     390             : static struct uwrap uwrap;
     391             : 
     392             : /* Shortcut to the list item */
     393             : static UWRAP_THREAD struct uwrap_thread *uwrap_tls_id;
     394             : 
     395             : /* The mutex or accessing the id */
     396             : static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
     397             : 
     398             : #define uwrap_init_mutex(m) _uwrap_init_mutex(m, #m)
     399      189264 : static int _uwrap_init_mutex(pthread_mutex_t *m, const char *name)
     400             : {
     401        4918 :         pthread_mutexattr_t ma;
     402      189264 :         bool need_destroy = false;
     403      189264 :         int ret = 0;
     404             : 
     405             : #define __CHECK(cmd)                                    \
     406             :         do {                                            \
     407             :                 ret = cmd;                              \
     408             :                 if (ret != 0) {                         \
     409             :                         UWRAP_LOG(UWRAP_LOG_ERROR,      \
     410             :                                   "%s: %s - failed %d", \
     411             :                                   name,                 \
     412             :                                   #cmd,                 \
     413             :                                   ret);                 \
     414             :                         goto done;                      \
     415             :                 }                                       \
     416             :         } while (0)
     417             : 
     418      189264 :         *m = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
     419      189264 :         __CHECK(pthread_mutexattr_init(&ma));
     420      189264 :         need_destroy = true;
     421      189264 :         __CHECK(pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_ERRORCHECK));
     422      189264 :         __CHECK(pthread_mutex_init(m, &ma));
     423      189264 : done:
     424      184346 :         if (need_destroy) {
     425      189264 :                 pthread_mutexattr_destroy(&ma);
     426             :         }
     427      189264 :         return ret;
     428             : }
     429             : 
     430             : #define uwrap_mutex_lock(m) _uwrap_mutex_lock(m, #m, __func__, __LINE__)
     431   289100808 : static void _uwrap_mutex_lock(pthread_mutex_t *mutex,
     432             :                               const char *name,
     433             :                               const char *caller,
     434             :                               unsigned line)
     435             : {
     436      729721 :         int ret;
     437             : 
     438   289100808 :         ret = pthread_mutex_lock(mutex);
     439   289100809 :         if (ret != 0) {
     440           0 :                 UWRAP_LOG(UWRAP_LOG_ERROR,
     441             :                           "PID(%d):PPID(%d): %s(%u): Couldn't lock pthread "
     442             :                           "mutex(%s) - %s",
     443             :                           getpid(),
     444             :                           getppid(),
     445             :                           caller,
     446             :                           line,
     447             :                           name,
     448             :                           strerror(ret));
     449           0 :                 abort();
     450             :         }
     451   289100809 : }
     452             : 
     453             : #define uwrap_mutex_unlock(m) _uwrap_mutex_unlock(m, #m, __func__, __LINE__)
     454   289091384 : static void _uwrap_mutex_unlock(pthread_mutex_t *mutex,
     455             :                                 const char *name,
     456             :                                 const char *caller,
     457             :                                 unsigned line)
     458             : {
     459      729645 :         int ret;
     460             : 
     461   289091384 :         ret = pthread_mutex_unlock(mutex);
     462   289091384 :         if (ret != 0) {
     463           0 :                 UWRAP_LOG(UWRAP_LOG_ERROR,
     464             :                           "PID(%d):PPID(%d): %s(%u): Couldn't unlock pthread "
     465             :                           "mutex(%s) - %s",
     466             :                           getpid(),
     467             :                           getppid(),
     468             :                           caller,
     469             :                           line,
     470             :                           name,
     471             :                           strerror(ret));
     472           0 :                 abort();
     473             :         }
     474   289091384 : }
     475             : 
     476             : #define UWRAP_LOCK(m)                           \
     477             :         do {                                    \
     478             :                 uwrap_mutex_lock(&(m##_mutex)); \
     479             :         } while (0)
     480             : 
     481             : #define UWRAP_UNLOCK(m)                           \
     482             :         do {                                      \
     483             :                 uwrap_mutex_unlock(&(m##_mutex)); \
     484             :         } while (0)
     485             : 
     486             : /* Add new global locks here please */
     487             : #define UWRAP_REINIT_ALL                                 \
     488             :         do {                                             \
     489             :                 int ret;                                 \
     490             :                 ret = uwrap_init_mutex(&uwrap_id_mutex); \
     491             :                 if (ret != 0)                            \
     492             :                         exit(-1);                        \
     493             :         } while (0)
     494             : 
     495             : /* Add new global locks here please */
     496             : #define UWRAP_LOCK_ALL                \
     497             :         do {                          \
     498             :                 UWRAP_LOCK(uwrap_id); \
     499             :         } while (0)
     500             : 
     501             : #define UWRAP_UNLOCK_ALL                \
     502             :         do {                            \
     503             :                 UWRAP_UNLOCK(uwrap_id); \
     504             :         } while (0)
     505             : 
     506             : /*********************************************************
     507             :  * UWRAP PROTOTYPES
     508             :  *********************************************************/
     509             : 
     510             : bool uid_wrapper_enabled(void);
     511             : #if ! defined(HAVE_CONSTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_INIT)
     512             : /* xlC and other oldschool compilers support (only) this */
     513             : #pragma init (uwrap_constructor)
     514             : #endif
     515             : void uwrap_constructor(void) CONSTRUCTOR_ATTRIBUTE;
     516             : #if ! defined(HAVE_DESTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_FINI)
     517             : #pragma fini (uwrap_destructor)
     518             : #endif
     519             : void uwrap_destructor(void) DESTRUCTOR_ATTRIBUTE;
     520             : 
     521             : /*********************************************************
     522             :  * UWRAP LIBC LOADER FUNCTIONS
     523             :  *********************************************************/
     524             : 
     525             : enum uwrap_lib {
     526             :     UWRAP_LIBC,
     527             :     UWRAP_LIBPTHREAD,
     528             : };
     529             : 
     530     3237102 : static void *uwrap_load_lib_handle(enum uwrap_lib lib)
     531             : {
     532     3237102 :         int flags = RTLD_LAZY;
     533     3237102 :         void *handle = NULL;
     534       87156 :         int i;
     535             : 
     536             : #ifdef RTLD_DEEPBIND
     537     3237102 :         const char *env_preload = getenv("LD_PRELOAD");
     538     3237102 :         const char *env_deepbind = getenv("UID_WRAPPER_DISABLE_DEEPBIND");
     539     3237102 :         bool enable_deepbind = true;
     540             : 
     541             :         /* Don't do a deepbind if we run with libasan */
     542     3237102 :         if (env_preload != NULL && strlen(env_preload) < 1024) {
     543     3237102 :                 const char *p = strstr(env_preload, "libasan.so");
     544     3237102 :                 if (p != NULL) {
     545           0 :                         enable_deepbind = false;
     546             :                 }
     547             :         }
     548             : 
     549     3237102 :         if (env_deepbind != NULL && strlen(env_deepbind) >= 1) {
     550           0 :                 enable_deepbind = false;
     551             :         }
     552             : 
     553     3237102 :         if (enable_deepbind) {
     554     3237102 :                 flags |= RTLD_DEEPBIND;
     555             :         }
     556             : #endif
     557             : 
     558     3237102 :         switch (lib) {
     559     2877424 :         case UWRAP_LIBC:
     560     2877424 :                 handle = uwrap.libc.handle;
     561     2877424 :                 if (handle == NULL) {
     562      899195 :                         for (i = 10; i >= 0; i--) {
     563      899195 :                                 char soname[256] = {0};
     564             : 
     565      899195 :                                 snprintf(soname, sizeof(soname), "libc.so.%d", i);
     566      899195 :                                 handle = dlopen(soname, flags);
     567      899195 :                                 if (handle != NULL) {
     568      174997 :                                         break;
     569             :                                 }
     570             : 
     571             :                                 /* glibc on Alpha and IA64 is libc.so.6.1 */
     572      719356 :                                 snprintf(soname, sizeof(soname), "libc.so.%d.1", i);
     573      719356 :                                 handle = dlopen(soname, flags);
     574      719356 :                                 if (handle != NULL) {
     575           0 :                                         break;
     576             :                                 }
     577             :                         }
     578             : 
     579      179839 :                         uwrap.libc.handle = handle;
     580             :                 }
     581     2799952 :                 break;
     582      359678 :         case UWRAP_LIBPTHREAD:
     583      359678 :                 handle = uwrap.libpthread.handle;
     584      359678 :                 if (handle == NULL) {
     585             : #ifdef RTLD_NEXT
     586             :                         /*
     587             :                          * Because thread sanatizer also overloads
     588             :                          * pthread_create() and pthread_exit() we need use
     589             :                          * RTLD_NEXT instead of libpthread.so.0
     590             :                          */
     591      179839 :                         handle = uwrap.libpthread.handle = RTLD_NEXT;
     592             : #else
     593             :                         handle = dlopen("libpthread.so.0", flags);
     594             : #endif
     595      179839 :                         if (handle != NULL) {
     596      174997 :                                 break;
     597             :                         }
     598             :                 }
     599      174997 :                 break;
     600             :         }
     601             : 
     602     3237102 :         if (handle == NULL) {
     603             : #ifdef RTLD_NEXT
     604           0 :                 switch (lib) {
     605           0 :                 case UWRAP_LIBC:
     606           0 :                         handle = uwrap.libc.handle = RTLD_NEXT;
     607           0 :                         break;
     608           0 :                 case UWRAP_LIBPTHREAD:
     609           0 :                         handle = uwrap.libpthread.handle = RTLD_NEXT;
     610           0 :                         break;
     611             :                 }
     612             : #else
     613             :                 fprintf(stderr,
     614             :                         "Failed to dlopen library: %s\n",
     615             :                         dlerror());
     616             :                 exit(-1);
     617             : #endif
     618             :         }
     619             : 
     620     3237102 :         return handle;
     621             : }
     622             : 
     623     3237102 : static void *_uwrap_bind_symbol(enum uwrap_lib lib, const char *fn_name)
     624             : {
     625       87156 :         void *handle;
     626       87156 :         void *func;
     627             : 
     628     3237102 :         handle = uwrap_load_lib_handle(lib);
     629             : 
     630     3237102 :         func = dlsym(handle, fn_name);
     631     3237102 :         if (func == NULL) {
     632           0 :                 fprintf(stderr,
     633             :                         "Failed to find %s: %s\n",
     634             :                         fn_name, dlerror());
     635           0 :                 exit(-1);
     636             :         }
     637             : 
     638     3237102 :         return func;
     639             : }
     640             : 
     641             : #define uwrap_bind_symbol_libc(sym_name) \
     642             :         if (uwrap.libc.symbols._libc_##sym_name.obj == NULL) { \
     643             :                 uwrap.libc.symbols._libc_##sym_name.obj = \
     644             :                         _uwrap_bind_symbol(UWRAP_LIBC, #sym_name); \
     645             :         }
     646             : 
     647             : #define uwrap_bind_symbol_libpthread(sym_name) \
     648             :         if (uwrap.libpthread.symbols._libpthread_##sym_name.obj == NULL) { \
     649             :                 uwrap.libpthread.symbols._libpthread_##sym_name.obj = \
     650             :                         _uwrap_bind_symbol(UWRAP_LIBPTHREAD, #sym_name); \
     651             :         }
     652             : 
     653             : #define uwrap_bind_symbol_rtld_default_optional(sym_name)                      \
     654             :         if (uwrap.rtld_default.symbols._rtld_default_##sym_name.obj == NULL) { \
     655             :                 uwrap.rtld_default.symbols._rtld_default_##sym_name.obj =      \
     656             :                         dlsym(RTLD_DEFAULT, #sym_name);                        \
     657             :         }
     658             : 
     659             : /* DO NOT call this function during library initialization! */
     660      179839 : static void __uwrap_bind_symbol_all_once(void)
     661             : {
     662      179839 :         uwrap_bind_symbol_libc(setuid);
     663      179839 :         uwrap_bind_symbol_libc(getuid);
     664             : #ifdef HAVE_SETEUID
     665      179839 :         uwrap_bind_symbol_libc(seteuid);
     666             : #endif
     667             : #ifdef HAVE_SETREUID
     668      179839 :         uwrap_bind_symbol_libc(setreuid);
     669             : #endif
     670             : #ifdef HAVE_SETRESUID
     671      179839 :         uwrap_bind_symbol_libc(setresuid);
     672             : #endif
     673             : #ifdef HAVE_GETRESUID
     674      179839 :         uwrap_bind_symbol_libc(getresuid);
     675             : #endif
     676      179839 :         uwrap_bind_symbol_libc(geteuid);
     677      179839 :         uwrap_bind_symbol_libc(setgid);
     678      179839 :         uwrap_bind_symbol_libc(getgid);
     679             : #ifdef HAVE_SETEGID
     680      179839 :         uwrap_bind_symbol_libc(setegid);
     681             : #endif
     682             : #ifdef HAVE_SETREGID
     683      179839 :         uwrap_bind_symbol_libc(setregid);
     684             : #endif
     685             : 
     686             : #ifdef HAVE_SETRESGID
     687      179839 :         uwrap_bind_symbol_libc(setresgid);
     688             : #endif
     689             : #ifdef HAVE_GETRESGID
     690      179839 :         uwrap_bind_symbol_libc(setresgid);
     691             : #endif
     692      179839 :         uwrap_bind_symbol_libc(getegid);
     693      179839 :         uwrap_bind_symbol_libc(getgroups);
     694      179839 :         uwrap_bind_symbol_libc(setgroups);
     695             : #ifdef HAVE_SYSCALL
     696      179839 :         uwrap_bind_symbol_libc(syscall);
     697      179839 :         uwrap_bind_symbol_rtld_default_optional(socket_wrapper_syscall_valid);
     698      179839 :         uwrap_bind_symbol_rtld_default_optional(socket_wrapper_syscall_va);
     699             : #endif
     700      179839 :         uwrap_bind_symbol_libpthread(pthread_create);
     701      179839 :         uwrap_bind_symbol_libpthread(pthread_exit);
     702      179839 : }
     703             : 
     704     2146138 : static void uwrap_bind_symbol_all(void)
     705             : {
     706       22677 :         static pthread_once_t all_symbol_binding_once = PTHREAD_ONCE_INIT;
     707             : 
     708     2146138 :         pthread_once(&all_symbol_binding_once, __uwrap_bind_symbol_all_once);
     709     2123461 : }
     710             : 
     711             : /*
     712             :  * IMPORTANT
     713             :  *
     714             :  * Functions expeciall from libc need to be loaded individually, you can't load
     715             :  * all at once or gdb will segfault at startup. The same applies to valgrind and
     716             :  * has probably something todo with with the linker.
     717             :  * So we need load each function at the point it is called the first time.
     718             :  */
     719           0 : static int libc_setuid(uid_t uid)
     720             : {
     721           0 :         uwrap_bind_symbol_all();
     722             : 
     723           0 :         return uwrap.libc.symbols._libc_setuid.f(uid);
     724             : }
     725             : 
     726           0 : static uid_t libc_getuid(void)
     727             : {
     728           0 :         uwrap_bind_symbol_all();
     729             : 
     730           0 :         return uwrap.libc.symbols._libc_getuid.f();
     731             : }
     732             : 
     733             : #ifdef HAVE_SETEUID
     734           0 : static int libc_seteuid(uid_t euid)
     735             : {
     736           0 :         uwrap_bind_symbol_all();
     737             : 
     738           0 :         return uwrap.libc.symbols._libc_seteuid.f(euid);
     739             : }
     740             : #endif
     741             : 
     742             : #ifdef HAVE_SETREUID
     743           0 : static int libc_setreuid(uid_t ruid, uid_t euid)
     744             : {
     745           0 :         uwrap_bind_symbol_all();
     746             : 
     747           0 :         return uwrap.libc.symbols._libc_setreuid.f(ruid, euid);
     748             : }
     749             : #endif
     750             : 
     751             : #ifdef HAVE_SETRESUID
     752           0 : static int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid)
     753             : {
     754           0 :         uwrap_bind_symbol_all();
     755             : 
     756           0 :         return uwrap.libc.symbols._libc_setresuid.f(ruid, euid, suid);
     757             : }
     758             : #endif
     759             : 
     760             : #ifdef HAVE_GETRESUID
     761           0 : static int libc_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
     762             : {
     763           0 :         uwrap_bind_symbol_all();
     764             : 
     765           0 :         return uwrap.libc.symbols._libc_getresuid.f(ruid, euid, suid);
     766             : }
     767             : #endif
     768             : 
     769      179839 : static uid_t libc_geteuid(void)
     770             : {
     771      179839 :         uwrap_bind_symbol_all();
     772             : 
     773      179839 :         return uwrap.libc.symbols._libc_geteuid.f();
     774             : }
     775             : 
     776           0 : static int libc_setgid(gid_t gid)
     777             : {
     778           0 :         uwrap_bind_symbol_all();
     779             : 
     780           0 :         return uwrap.libc.symbols._libc_setgid.f(gid);
     781             : }
     782             : 
     783           0 : static gid_t libc_getgid(void)
     784             : {
     785           0 :         uwrap_bind_symbol_all();
     786             : 
     787           0 :         return uwrap.libc.symbols._libc_getgid.f();
     788             : }
     789             : 
     790             : #ifdef HAVE_SETEGID
     791           0 : static int libc_setegid(gid_t egid)
     792             : {
     793           0 :         uwrap_bind_symbol_all();
     794             : 
     795           0 :         return uwrap.libc.symbols._libc_setegid.f(egid);
     796             : }
     797             : #endif
     798             : 
     799             : #ifdef HAVE_SETREGID
     800           0 : static int libc_setregid(gid_t rgid, gid_t egid)
     801             : {
     802           0 :         uwrap_bind_symbol_all();
     803             : 
     804           0 :         return uwrap.libc.symbols._libc_setregid.f(rgid, egid);
     805             : }
     806             : #endif
     807             : 
     808             : #ifdef HAVE_SETRESGID
     809           0 : static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
     810             : {
     811           0 :         uwrap_bind_symbol_all();
     812             : 
     813           0 :         return uwrap.libc.symbols._libc_setresgid.f(rgid, egid, sgid);
     814             : }
     815             : #endif
     816             : 
     817             : #ifdef HAVE_GETRESGID
     818           0 : static int libc_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
     819             : {
     820           0 :         uwrap_bind_symbol_all();
     821             : 
     822           0 :         return uwrap.libc.symbols._libc_getresgid.f(rgid, egid, sgid);
     823             : }
     824             : #endif
     825             : 
     826      179839 : static gid_t libc_getegid(void)
     827             : {
     828      179839 :         uwrap_bind_symbol_all();
     829             : 
     830      179839 :         return uwrap.libc.symbols._libc_getegid.f();
     831             : }
     832             : 
     833      294600 : static int libc_getgroups(int size, gid_t list[])
     834             : {
     835      294600 :         uwrap_bind_symbol_all();
     836             : 
     837      294600 :         return uwrap.libc.symbols._libc_getgroups.f(size, list);
     838             : }
     839             : 
     840             : #ifdef HAVE___GETGROUPS_CHK
     841             : static int libc___getgroups_chk(int size, gid_t list[], size_t listlen)
     842             : {
     843             :         uwrap_bind_symbol_libc(__getgroups_chk);
     844             : 
     845             :         return uwrap.libc.symbols._libc___getgroups_chk.f(size,
     846             :                                                           list,
     847             :                                                           listlen);
     848             : }
     849             : #endif /* HAVE___GETGROUPS_CHK */
     850             : 
     851           0 : static int libc_setgroups(size_t size, const gid_t *list)
     852             : {
     853           0 :         uwrap_bind_symbol_all();
     854             : 
     855           0 :         return uwrap.libc.symbols._libc_setgroups.f(size, list);
     856             : }
     857             : 
     858             : #ifdef HAVE_SYSCALL
     859             : DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
     860           0 : static long int libc_vsyscall(long int sysno, va_list va)
     861             : {
     862           0 :         long int args[8];
     863           0 :         long int rc;
     864           0 :         int i;
     865             : 
     866           0 :         uwrap_bind_symbol_all();
     867             : 
     868           0 :         for (i = 0; i < 8; i++) {
     869           0 :                 args[i] = va_arg(va, long int);
     870             :         }
     871             : 
     872           0 :         rc = uwrap.libc.symbols._libc_syscall.f(sysno,
     873             :                                           args[0],
     874             :                                           args[1],
     875             :                                           args[2],
     876             :                                           args[3],
     877             :                                           args[4],
     878             :                                           args[5],
     879             :                                           args[6],
     880             :                                           args[7]);
     881             : 
     882           0 :         return rc;
     883             : }
     884             : 
     885           0 : static bool uwrap_swrap_syscall_valid(long int sysno)
     886             : {
     887           0 :         uwrap_bind_symbol_all();
     888             : 
     889           0 :         if (uwrap.rtld_default.symbols._rtld_default_socket_wrapper_syscall_valid.f == NULL) {
     890           0 :                 return false;
     891             :         }
     892             : 
     893           0 :         return uwrap.rtld_default.symbols._rtld_default_socket_wrapper_syscall_valid.f(
     894             :                                                 sysno);
     895             : }
     896             : 
     897             : DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
     898           0 : static long int uwrap_swrap_syscall_va(long int sysno, va_list va)
     899             : {
     900           0 :         uwrap_bind_symbol_all();
     901             : 
     902           0 :         if (uwrap.rtld_default.symbols._rtld_default_socket_wrapper_syscall_va.f == NULL) {
     903             :                 /*
     904             :                  * Fallback to libc, if socket_wrapper_vsyscall is not
     905             :                  * available.
     906             :                  */
     907           0 :                 return libc_vsyscall(sysno, va);
     908             :         }
     909             : 
     910           0 :         return uwrap.rtld_default.symbols._rtld_default_socket_wrapper_syscall_va.f(
     911             :                                                 sysno,
     912             :                                                 va);
     913             : }
     914             : #endif
     915             : 
     916        4859 : static int libpthread_pthread_create(pthread_t *thread,
     917             :                                 const pthread_attr_t *attr,
     918             :                                 void *(*start_routine) (void *),
     919             :                                 void *arg)
     920             : {
     921        4859 :         uwrap_bind_symbol_all();
     922        4859 :         return uwrap.libpthread.symbols._libpthread_pthread_create.f(thread,
     923             :                                                                      attr,
     924             :                                                                      start_routine,
     925             :                                                                      arg);
     926             : }
     927             : 
     928             : /*
     929             :  * This part is "optimistic".
     930             :  * Thread can ends without pthread_exit call.
     931             :  */
     932          64 : static void libpthread_pthread_exit(void *retval)
     933             : {
     934          64 :         uwrap_bind_symbol_all();
     935             : 
     936          64 :         uwrap.libpthread.symbols._libpthread_pthread_exit.f(retval);
     937           0 : }
     938             : 
     939          64 : static void uwrap_pthread_exit(void *retval)
     940             : {
     941          64 :         struct uwrap_thread *id = uwrap_tls_id;
     942             : 
     943          64 :         UWRAP_LOG(UWRAP_LOG_DEBUG, "Cleanup thread");
     944             : 
     945          64 :         UWRAP_LOCK(uwrap_id);
     946          64 :         if (id == NULL) {
     947           0 :                 UWRAP_UNLOCK(uwrap_id);
     948           0 :                 libpthread_pthread_exit(retval);
     949           0 :                 return;
     950             :         }
     951             : 
     952          64 :         UWRAP_DLIST_REMOVE(uwrap.ids, id);
     953          64 :         SAFE_FREE(id->groups);
     954          64 :         SAFE_FREE(id);
     955          64 :         uwrap_tls_id = NULL;
     956             : 
     957          64 :         UWRAP_UNLOCK(uwrap_id);
     958             : 
     959          64 :         libpthread_pthread_exit(retval);
     960             : }
     961             : 
     962             : void pthread_exit(void *retval)
     963             : {
     964          64 :         if (!uid_wrapper_enabled()) {
     965           0 :                 libpthread_pthread_exit(retval);
     966          64 :         };
     967             : 
     968          64 :         uwrap_pthread_exit(retval);
     969             : 
     970             :         /* Calm down gcc warning. */
     971           0 :         exit(666);
     972             : }
     973             : 
     974             : struct uwrap_pthread_create_args {
     975             :         struct uwrap_thread *id;
     976             :         void *(*start_routine) (void *);
     977             :         void *arg;
     978             : };
     979             : 
     980        4850 : static void *uwrap_pthread_create_start(void *_a)
     981             : {
     982        4850 :         struct uwrap_pthread_create_args *a =
     983             :                 (struct uwrap_pthread_create_args *)_a;
     984        4850 :         void *(*start_routine) (void *) = a->start_routine;
     985        4850 :         void *arg = a->arg;
     986        4850 :         struct uwrap_thread *id = a->id;
     987             : 
     988        4850 :         SAFE_FREE(a);
     989             : 
     990        4850 :         uwrap_tls_id = id;
     991             : 
     992        4850 :         return start_routine(arg);
     993             : }
     994             : 
     995        4859 : static int uwrap_pthread_create(pthread_t *thread,
     996             :                                  const pthread_attr_t *attr,
     997             :                                  void *(*start_routine) (void *),
     998             :                                  void *arg)
     999             : {
    1000         701 :         struct uwrap_pthread_create_args *args;
    1001        4859 :         struct uwrap_thread *src_id = uwrap_tls_id;
    1002         701 :         int ret;
    1003             : 
    1004        4859 :         args = malloc(sizeof(struct uwrap_pthread_create_args));
    1005        4859 :         if (args == NULL) {
    1006           0 :                 UWRAP_LOG(UWRAP_LOG_ERROR,
    1007             :                           "uwrap_pthread_create: Unable to allocate memory");
    1008           0 :                 errno = ENOMEM;
    1009           0 :                 return -1;
    1010             :         }
    1011        4859 :         args->start_routine = start_routine;
    1012        4859 :         args->arg = arg;
    1013             : 
    1014        4859 :         args->id = calloc(1, sizeof(struct uwrap_thread));
    1015        4859 :         if (args->id == NULL) {
    1016           0 :                 SAFE_FREE(args);
    1017           0 :                 UWRAP_LOG(UWRAP_LOG_ERROR,
    1018             :                           "uwrap_pthread_create: Unable to allocate memory");
    1019           0 :                 errno = ENOMEM;
    1020           0 :                 return -1;
    1021             :         }
    1022             : 
    1023        4859 :         UWRAP_LOCK(uwrap_id);
    1024             : 
    1025        4859 :         args->id->groups = calloc(src_id->ngroups, sizeof(gid_t));
    1026        4859 :         if (args->id->groups == NULL) {
    1027           0 :                 UWRAP_UNLOCK(uwrap_id);
    1028           0 :                 SAFE_FREE(args->id);
    1029           0 :                 SAFE_FREE(args);
    1030           0 :                 UWRAP_LOG(UWRAP_LOG_ERROR,
    1031             :                           "uwrap_pthread_create: Unable to allocate memory again");
    1032           0 :                 errno = ENOMEM;
    1033           0 :                 return -1;
    1034             :         }
    1035             : 
    1036        4859 :         args->id->ruid = src_id->ruid;
    1037        4859 :         args->id->euid = src_id->euid;
    1038        4859 :         args->id->suid = src_id->suid;
    1039             : 
    1040        4859 :         args->id->rgid = src_id->rgid;
    1041        4859 :         args->id->egid = src_id->egid;
    1042        4859 :         args->id->sgid = src_id->sgid;
    1043             : 
    1044        4859 :         args->id->enabled = src_id->enabled;
    1045             : 
    1046        4859 :         args->id->ngroups = src_id->ngroups;
    1047        4859 :         if (src_id->groups != NULL) {
    1048        5511 :                 memcpy(args->id->groups, src_id->groups,
    1049        4810 :                        sizeof(gid_t) * src_id->ngroups);
    1050             :         } else {
    1051          49 :                 SAFE_FREE(args->id->groups);
    1052             :         }
    1053             : 
    1054        4859 :         UWRAP_DLIST_ADD(uwrap.ids, args->id);
    1055        4859 :         UWRAP_UNLOCK(uwrap_id);
    1056             : 
    1057        4859 :         ret = libpthread_pthread_create(thread, attr,
    1058             :                                         uwrap_pthread_create_start,
    1059             :                                         args);
    1060        4859 :         if (ret != 0) {
    1061           0 :                 return ret;
    1062             :         }
    1063             : 
    1064        4158 :         return ret;
    1065             : }
    1066             : 
    1067             : int pthread_create(pthread_t *thread,
    1068             :                     const pthread_attr_t *attr,
    1069             :                     void *(*start_routine) (void *),
    1070             :                     void *arg)
    1071             : {
    1072        4859 :         if (!uid_wrapper_enabled()) {
    1073           0 :                 return libpthread_pthread_create(thread,
    1074             :                                            attr,
    1075             :                                            start_routine,
    1076             :                                            arg);
    1077         701 :         };
    1078             : 
    1079        4859 :         return uwrap_pthread_create(thread,
    1080             :                                     attr,
    1081             :                                     start_routine,
    1082             :                                     arg);
    1083             : }
    1084             : 
    1085             : /*********************************************************
    1086             :  * UWRAP ID HANDLING
    1087             :  *********************************************************/
    1088             : 
    1089             : #define GROUP_STRING_SIZE 16384
    1090             : #define GROUP_MAX_COUNT (GROUP_STRING_SIZE / (10 + 1))
    1091             : 
    1092             : /**
    1093             :  * This function exports all the IDs of the current user so if
    1094             :  * we fork and then exec we can setup uid_wrapper in the new process
    1095             :  * with those IDs.
    1096             :  */
    1097        9425 : static void uwrap_export_ids(struct uwrap_thread *id)
    1098             : {
    1099        9425 :         char groups_str[GROUP_STRING_SIZE] = {0};
    1100        9425 :         size_t groups_str_size = sizeof(groups_str);
    1101        9425 :         char unsigned_str[16] = {0}; /* We need 10 + 1 (+ 1) */
    1102          76 :         int i;
    1103             : 
    1104             :         /* UIDS */
    1105        9425 :         snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->ruid);
    1106        9425 :         setenv("UID_WRAPPER_INITIAL_RUID", unsigned_str, 1);
    1107             : 
    1108        9425 :         snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->euid);
    1109        9425 :         setenv("UID_WRAPPER_INITIAL_EUID", unsigned_str, 1);
    1110             : 
    1111        9425 :         snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->suid);
    1112        9425 :         setenv("UID_WRAPPER_INITIAL_SUID", unsigned_str, 1);
    1113             : 
    1114             :         /* GIDS */
    1115        9425 :         snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->rgid);
    1116        9425 :         setenv("UID_WRAPPER_INITIAL_RGID", unsigned_str, 1);
    1117             : 
    1118        9425 :         snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->egid);
    1119        9425 :         setenv("UID_WRAPPER_INITIAL_EGID", unsigned_str, 1);
    1120             : 
    1121        9425 :         snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->sgid);
    1122        9425 :         setenv("UID_WRAPPER_INITIAL_SGID", unsigned_str, 1);
    1123             : 
    1124        9425 :         if (id->ngroups > GROUP_MAX_COUNT) {
    1125           0 :                 UWRAP_LOG(UWRAP_LOG_ERROR,
    1126             :                           "ERROR: Number of groups (%u) exceeds maximum value "
    1127             :                           "uid_wrapper can handle (%u).",
    1128             :                           id->ngroups,
    1129             :                           GROUP_MAX_COUNT);
    1130           0 :                 exit(-1);
    1131             :         }
    1132             : 
    1133             :         /* GROUPS */
    1134       18643 :         for (i = 0; i < id->ngroups; i++) {
    1135        9218 :                 size_t groups_str_len = strlen(groups_str);
    1136        9218 :                 size_t groups_str_avail = groups_str_size - groups_str_len - 1;
    1137           0 :                 int len;
    1138             : 
    1139        9218 :                 len = snprintf(unsigned_str, sizeof(unsigned_str), ",%u", id->groups[i]);
    1140        9218 :                 if (len <= 1) {
    1141           0 :                         UWRAP_LOG(UWRAP_LOG_ERROR,
    1142             :                                   "snprintf failed for groups[%d]=%u",
    1143             :                                   i,
    1144             :                                   id->groups[i]);
    1145           0 :                         break;
    1146             :                 }
    1147        9218 :                 if (((size_t)len) >= groups_str_avail) {
    1148           0 :                         UWRAP_LOG(UWRAP_LOG_ERROR,
    1149             :                                   "groups env string is to small for %d groups",
    1150             :                                   i);
    1151           0 :                         break;
    1152             :                 }
    1153             : 
    1154        9218 :                 len = snprintf(groups_str + groups_str_len,
    1155             :                                groups_str_size - groups_str_len,
    1156             :                                "%s",
    1157             :                                i == 0 ? unsigned_str + 1 : unsigned_str);
    1158        9218 :                 if (len < 1) {
    1159           0 :                         UWRAP_LOG(UWRAP_LOG_ERROR,
    1160             :                                   "snprintf failed to create groups string at groups[%d]=%u",
    1161             :                                   i,
    1162             :                                   id->groups[i]);
    1163           0 :                         break;
    1164             :                 }
    1165             :         }
    1166             : 
    1167        9425 :         if (id->ngroups == i) {
    1168        9425 :                 setenv("UID_WRAPPER_INITIAL_GROUPS", groups_str, 1);
    1169             : 
    1170        9425 :                 snprintf(unsigned_str, sizeof(unsigned_str), "%u", id->ngroups);
    1171        9425 :                 setenv("UID_WRAPPER_INITIAL_GROUPS_COUNT", unsigned_str, 1);
    1172             :         }
    1173        9425 : }
    1174             : 
    1175     1486937 : static void uwrap_thread_prepare(void)
    1176             : {
    1177     1486937 :         struct uwrap_thread *id = uwrap_tls_id;
    1178             : 
    1179             :         /*
    1180             :          * We bind all symbols to avoid deadlocks of the fork is interrupted by
    1181             :          * a signal handler using a symbol of this library.
    1182             :          */
    1183     1486937 :         uwrap_bind_symbol_all();
    1184             : 
    1185     1486937 :         UWRAP_LOCK_ALL;
    1186             : 
    1187             :         /* uid_wrapper is loaded but not enabled */
    1188     1486937 :         if (id == NULL) {
    1189           0 :                 return;
    1190             :         }
    1191             : 
    1192             :         /*
    1193             :          * What happens if another atfork prepare functions calls a uwrap
    1194             :          * function? So disable it in case another atfork prepare function
    1195             :          * calls a (s)uid function. We disable uid_wrapper only for thread
    1196             :          * (process) which called fork.
    1197             :          */
    1198     1486937 :         id->enabled = false;
    1199             : }
    1200             : 
    1201     1477512 : static void uwrap_thread_parent(void)
    1202             : {
    1203     1477512 :         struct uwrap_thread *id = uwrap_tls_id;
    1204             : 
    1205             :         /* uid_wrapper is loaded but not enabled */
    1206     1477512 :         if (id == NULL) {
    1207           0 :                 UWRAP_UNLOCK_ALL;
    1208           0 :                 return;
    1209             :         }
    1210             : 
    1211     1477512 :         id->enabled = true;
    1212             : 
    1213     1477512 :         UWRAP_UNLOCK_ALL;
    1214             : }
    1215             : 
    1216        9425 : static void uwrap_thread_child(void)
    1217             : {
    1218        9425 :         struct uwrap_thread *id = uwrap_tls_id;
    1219        9425 :         struct uwrap_thread *u = uwrap.ids;
    1220             : 
    1221        9425 :         UWRAP_REINIT_ALL;
    1222             : 
    1223             :         /* uid_wrapper is loaded but not enabled */
    1224        9425 :         if (id == NULL) {
    1225           0 :                 return;
    1226             :         }
    1227             : 
    1228             :         /*
    1229             :          * "Garbage collector" - Inspired by DESTRUCTOR.
    1230             :          * All threads (except one which called fork()) are dead now.. Dave
    1231             :          * That's what posix said...
    1232             :          */
    1233       18850 :         while (u != NULL) {
    1234        9425 :                 if (u == id) {
    1235             :                         /* Skip this item. */
    1236        9425 :                         u = uwrap.ids->next;
    1237        9425 :                         continue;
    1238             :                 }
    1239             : 
    1240           0 :                 UWRAP_DLIST_REMOVE(uwrap.ids, u);
    1241             : 
    1242           0 :                 SAFE_FREE(u->groups);
    1243           0 :                 SAFE_FREE(u);
    1244             : 
    1245           0 :                 u = uwrap.ids;
    1246             :         }
    1247             : 
    1248        9425 :         uwrap_export_ids(id);
    1249             : 
    1250        9425 :         id->enabled = true;
    1251             : }
    1252             : 
    1253     1079034 : static unsigned long uwrap_get_xid_from_env(const char *envname)
    1254             : {
    1255       29052 :         unsigned long xid;
    1256     1079034 :         const char *env = NULL;
    1257     1079034 :         char *endp = NULL;
    1258             : 
    1259     1079034 :         env = getenv(envname);
    1260     1079034 :         if (env == NULL) {
    1261      683478 :                 return ULONG_MAX;
    1262             :         }
    1263             : 
    1264      373554 :         if (env[0] == '\0') {
    1265           0 :                 unsetenv(envname);
    1266           0 :                 return ULONG_MAX;
    1267             :         }
    1268             : 
    1269      373554 :         xid = strtoul(env, &endp, 10);
    1270      373554 :         unsetenv(envname);
    1271      373554 :         if (env == endp) {
    1272           0 :                 return ULONG_MAX;
    1273             :         }
    1274             : 
    1275      366504 :         return xid;
    1276             : }
    1277             : 
    1278             : /*
    1279             :  * This initializes uid_wrapper with the IDs exported to the environment. Those
    1280             :  * are normally set after we forked and executed.
    1281             :  */
    1282      179839 : static void uwrap_init_env(struct uwrap_thread *id)
    1283             : {
    1284        4842 :         const char *env;
    1285      179839 :         int ngroups = 0;
    1286        4842 :         unsigned long xid;
    1287             : 
    1288             :         /* UIDs */
    1289      179839 :         xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_RUID");
    1290      179839 :         if (xid != ULONG_MAX) {
    1291       62285 :                 id->ruid = (uid_t)xid;
    1292             :         }
    1293             : 
    1294      179839 :         xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_EUID");
    1295      179839 :         if (xid != ULONG_MAX) {
    1296       62285 :                 id->euid = (uid_t)xid;
    1297             :         }
    1298             : 
    1299      179839 :         xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_SUID");
    1300      179839 :         if (xid != ULONG_MAX) {
    1301       62246 :                 id->suid = (uid_t)xid;
    1302             :         }
    1303             : 
    1304             :         /* GIDs */
    1305      179839 :         xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_RGID");
    1306      179839 :         if (xid != ULONG_MAX) {
    1307       62246 :                 id->rgid = (gid_t)xid;
    1308             :         }
    1309             : 
    1310      179839 :         xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_EGID");
    1311      179839 :         if (xid != ULONG_MAX) {
    1312       62246 :                 id->egid = (gid_t)xid;
    1313             :         }
    1314             : 
    1315      179839 :         xid = uwrap_get_xid_from_env("UID_WRAPPER_INITIAL_SGID");
    1316      179839 :         if (xid != ULONG_MAX) {
    1317       62246 :                 id->sgid = (gid_t)xid;
    1318             :         }
    1319             : 
    1320      179839 :         env = getenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
    1321      179839 :         if (env != NULL && env[0] != '\0') {
    1322       62246 :                 char *endp = NULL;
    1323        1175 :                 long n;
    1324             : 
    1325       62246 :                 n = strtol(env, &endp, 10);
    1326       62246 :                 if (env == endp) {
    1327           0 :                         ngroups = 0;
    1328       62246 :                 } else if (n > 0 && n < GROUP_MAX_COUNT) {
    1329       57163 :                         ngroups = (int)n;
    1330             :                 }
    1331       62246 :                 unsetenv("UID_WRAPPER_INITIAL_GROUPS_COUNT");
    1332             :         }
    1333             : 
    1334      176172 :         if (ngroups > 0) {
    1335       57163 :                 int i = 0;
    1336             : 
    1337       57163 :                 id->ngroups = 0;
    1338             : 
    1339       57163 :                 free(id->groups);
    1340       57163 :                 id->groups = calloc(ngroups, sizeof(gid_t));
    1341       57163 :                 if (id->groups == NULL) {
    1342           0 :                         UWRAP_LOG(UWRAP_LOG_ERROR,
    1343             :                                   "Unable to allocate memory");
    1344           0 :                         exit(-1);
    1345             :                 }
    1346             : 
    1347       57163 :                 env = getenv("UID_WRAPPER_INITIAL_GROUPS");
    1348       57163 :                 if (env != NULL && env[0] != '\0') {
    1349       57163 :                         char *groups_str = NULL;
    1350       57163 :                         char *saveptr = NULL;
    1351       57163 :                         const char *p = NULL;
    1352             : 
    1353       57163 :                         groups_str = strdup(env);
    1354       57163 :                         if (groups_str == NULL) {
    1355           0 :                                 exit(-1);
    1356             :                         }
    1357             : 
    1358       57163 :                         p = strtok_r(groups_str, ",", &saveptr);
    1359      123182 :                         while (p != NULL) {
    1360       66019 :                                 id->groups[i] = strtol(p, (char **)NULL, 10);
    1361       66019 :                                 i++;
    1362             : 
    1363       66019 :                                 p = strtok_r(NULL, ",", &saveptr);
    1364             :                         }
    1365       57163 :                         SAFE_FREE(groups_str);
    1366             :                 }
    1367             : 
    1368       57163 :                 if (i != ngroups) {
    1369           0 :                         UWRAP_LOG(UWRAP_LOG_ERROR,
    1370             :                                   "ERROR: The number of groups (%u) passed, "
    1371             :                                   "does not match the number of groups (%u) "
    1372             :                                   "we parsed.",
    1373             :                                   ngroups,
    1374             :                                   i);
    1375           0 :                         exit(-1);
    1376             :                 }
    1377             : 
    1378       57163 :                 UWRAP_LOG(UWRAP_LOG_DEBUG, "Initalize groups with %s", env);
    1379       57163 :                 id->ngroups = ngroups;
    1380             :         }
    1381      179839 : }
    1382             : 
    1383    82583815 : static void uwrap_init(void)
    1384             : {
    1385      203864 :         const char *env;
    1386             : 
    1387    82583815 :         UWRAP_LOCK(uwrap_id);
    1388             : 
    1389    82583815 :         if (uwrap.initialised) {
    1390    82403976 :                 struct uwrap_thread *id = uwrap_tls_id;
    1391             : 
    1392    82403976 :                 if (uwrap.ids == NULL) {
    1393           0 :                         UWRAP_UNLOCK(uwrap_id);
    1394           0 :                         return;
    1395             :                 }
    1396             : 
    1397    82403976 :                 if (id == NULL) {
    1398           0 :                         UWRAP_LOG(UWRAP_LOG_ERROR,
    1399             :                                   "Invalid id for thread");
    1400           0 :                         exit(-1);
    1401             :                 }
    1402             : 
    1403    82403976 :                 UWRAP_UNLOCK(uwrap_id);
    1404    82403976 :                 return;
    1405             :         }
    1406             : 
    1407      179839 :         UWRAP_LOG(UWRAP_LOG_DEBUG, "Initialize uid_wrapper");
    1408             : 
    1409      179839 :         uwrap.initialised = true;
    1410             : 
    1411      179839 :         env = getenv("UID_WRAPPER");
    1412      179839 :         if (env != NULL && env[0] == '1') {
    1413      179839 :                 const char *root = getenv("UID_WRAPPER_ROOT");
    1414        4842 :                 struct uwrap_thread *id;
    1415             : 
    1416      179839 :                 id = calloc(1, sizeof(struct uwrap_thread));
    1417      179839 :                 if (id == NULL) {
    1418           0 :                         UWRAP_LOG(UWRAP_LOG_ERROR,
    1419             :                                   "Unable to allocate memory for main id");
    1420           0 :                         exit(-1);
    1421             :                 }
    1422             : 
    1423      179839 :                 UWRAP_DLIST_ADD(uwrap.ids, id);
    1424      179839 :                 uwrap_tls_id = id;
    1425             : 
    1426      179839 :                 uwrap.myuid = libc_geteuid();
    1427      179839 :                 uwrap.mygid = libc_getegid();
    1428             : 
    1429             :                 /* put us in one group */
    1430      179839 :                 if (root != NULL && root[0] == '1') {
    1431       32539 :                         id->ruid = id->euid = id->suid = 0;
    1432       32539 :                         id->rgid = id->egid = id->sgid = 0;
    1433             : 
    1434       32539 :                         id->groups = malloc(sizeof(gid_t) * 1);
    1435       32539 :                         if (id->groups == NULL) {
    1436           0 :                                 UWRAP_LOG(UWRAP_LOG_ERROR,
    1437             :                                           "Unable to allocate memory");
    1438           0 :                                 exit(-1);
    1439             :                         }
    1440             : 
    1441       32539 :                         id->ngroups = 1;
    1442       32539 :                         id->groups[0] = 0;
    1443             : 
    1444             :                 } else {
    1445      147300 :                         id->ruid = id->euid = id->suid = uwrap.myuid;
    1446      147300 :                         id->rgid = id->egid = id->sgid = uwrap.mygid;
    1447             : 
    1448      147300 :                         id->ngroups = libc_getgroups(0, NULL);
    1449      147300 :                         if (id->ngroups == -1) {
    1450           0 :                                 UWRAP_LOG(UWRAP_LOG_ERROR,
    1451             :                                           "Unable to call libc_getgroups in uwrap_init.");
    1452           0 :                                 exit(-1);
    1453             :                         }
    1454      147300 :                         id->groups = malloc(sizeof(gid_t) * id->ngroups);
    1455      147300 :                         if (id->groups == NULL) {
    1456           0 :                                 UWRAP_LOG(UWRAP_LOG_ERROR, "Unable to allocate memory");
    1457           0 :                                 exit(-1);
    1458             :                         }
    1459      151823 :                         if (libc_getgroups(id->ngroups, id->groups) == -1) {
    1460           0 :                                 UWRAP_LOG(UWRAP_LOG_ERROR,
    1461             :                                           "Unable to call libc_getgroups again in uwrap_init.");
    1462           0 :                                 id->groups = 0;
    1463             :                                 /*
    1464             :                                  * Deallocation of uwrap.groups is handled by
    1465             :                                  * library destructor.
    1466             :                                  */
    1467           0 :                                 exit(-1);
    1468             :                         }
    1469             :                 }
    1470             : 
    1471      179839 :                 uwrap_init_env(id);
    1472             : 
    1473      179839 :                 id->enabled = true;
    1474             : 
    1475      184362 :                 UWRAP_LOG(UWRAP_LOG_DEBUG,
    1476             :                           "Enabled uid_wrapper as %s (real uid=%u)",
    1477             :                           id->ruid == 0 ? "root" : "user",
    1478             :                           (unsigned int)uwrap.myuid);
    1479             :         }
    1480             : 
    1481      179839 :         UWRAP_UNLOCK(uwrap_id);
    1482             : 
    1483      179839 :         UWRAP_LOG(UWRAP_LOG_DEBUG, "Successfully initialized uid_wrapper");
    1484             : }
    1485             : 
    1486   122389196 : bool uid_wrapper_enabled(void)
    1487             : {
    1488   122389196 :         struct uwrap_thread *id = uwrap_tls_id;
    1489      317114 :         bool enabled;
    1490             : 
    1491   122389196 :         if (id == NULL) {
    1492           0 :                 return false;
    1493             :         }
    1494             : 
    1495   122389196 :         UWRAP_LOCK(uwrap_id);
    1496   122389196 :         enabled = id->enabled;
    1497   122389196 :         UWRAP_UNLOCK(uwrap_id);
    1498             : 
    1499   122389196 :         return enabled;
    1500             : }
    1501             : 
    1502             : /*
    1503             :  * UWRAP_SETxUID FUNCTIONS
    1504             :  */
    1505             : 
    1506    13591561 : static int uwrap_setresuid_args(uid_t ruid, uid_t euid, uid_t suid)
    1507             : {
    1508    13591561 :         struct uwrap_thread *id = uwrap_tls_id;
    1509             : 
    1510    13591561 :         UWRAP_LOG(UWRAP_LOG_TRACE,
    1511             :                   "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
    1512             :                   id->ruid, ruid, id->euid, euid, id->suid, suid);
    1513             : 
    1514    13591561 :         if (id->euid != 0) {
    1515     4712966 :                 if (ruid != (uid_t)-1 &&
    1516     4011568 :                     ruid != id->ruid &&
    1517     4010694 :                     ruid != id->euid &&
    1518     4010694 :                     ruid != id->suid) {
    1519          23 :                         errno = EPERM;
    1520          23 :                         return -1;
    1521             :                 }
    1522     4712943 :                 if (euid != (uid_t)-1 &&
    1523     4712943 :                     euid != id->ruid &&
    1524     4010671 :                     euid != id->euid &&
    1525     4010671 :                     euid != id->suid) {
    1526           0 :                         errno = EPERM;
    1527           0 :                         return -1;
    1528             :                 }
    1529     4712943 :                 if (suid != (uid_t)-1 &&
    1530        1876 :                     suid != id->ruid &&
    1531        1876 :                     suid != id->euid &&
    1532        1876 :                     suid != id->suid) {
    1533           0 :                         errno = EPERM;
    1534           0 :                         return -1;
    1535             :                 }
    1536             :         }
    1537             : 
    1538    13564716 :         return 0;
    1539             : }
    1540             : 
    1541    13591561 : static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
    1542             : {
    1543    13591561 :         struct uwrap_thread *id = uwrap_tls_id;
    1544       26822 :         int rc;
    1545             : 
    1546    13591561 :         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);
    1549             : 
    1550    13591561 :         rc = uwrap_setresuid_args(ruid, euid, suid);
    1551    13591561 :         if (rc != 0) {
    1552          23 :                 return rc;
    1553             :         }
    1554             : 
    1555    13591538 :         UWRAP_LOCK(uwrap_id);
    1556             : 
    1557    13591538 :         if (ruid != (uid_t)-1) {
    1558    10794802 :                 id->ruid = ruid;
    1559             :         }
    1560             : 
    1561    13591538 :         if (euid != (uid_t)-1) {
    1562    13591538 :                 id->euid = euid;
    1563             :         }
    1564             : 
    1565    13591538 :         if (suid != (uid_t)-1) {
    1566       14772 :                 id->suid = suid;
    1567             :         }
    1568             : 
    1569    13591538 :         UWRAP_UNLOCK(uwrap_id);
    1570             : 
    1571    13591538 :         return 0;
    1572             : }
    1573             : 
    1574           0 : static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
    1575             : {
    1576           0 :         struct uwrap_thread *id = uwrap_tls_id;
    1577           0 :         int rc;
    1578             : 
    1579           0 :         UWRAP_LOG(UWRAP_LOG_TRACE,
    1580             :                   "ruid %d -> %d, euid %d -> %d, suid %d -> %d",
    1581             :                   id->ruid, ruid, id->euid, euid, id->suid, suid);
    1582             : 
    1583           0 :         rc = uwrap_setresuid_args(ruid, euid, suid);
    1584           0 :         if (rc != 0) {
    1585           0 :                 return rc;
    1586             :         }
    1587             : 
    1588           0 :         UWRAP_LOCK(uwrap_id);
    1589             : 
    1590           0 :         for (id = uwrap.ids; id; id = id->next) {
    1591           0 :                 if (ruid != (uid_t)-1) {
    1592           0 :                         id->ruid = ruid;
    1593             :                 }
    1594             : 
    1595           0 :                 if (euid != (uid_t)-1) {
    1596           0 :                         id->euid = euid;
    1597             :                 }
    1598             : 
    1599           0 :                 if (suid != (uid_t)-1) {
    1600           0 :                         id->suid = suid;
    1601             :                 }
    1602             :         }
    1603             : 
    1604           0 :         UWRAP_UNLOCK(uwrap_id);
    1605             : 
    1606           0 :         return 0;
    1607             : }
    1608             : 
    1609           0 : static int uwrap_setreuid_args(uid_t ruid, uid_t euid,
    1610             :                                uid_t *_new_ruid,
    1611             :                                uid_t *_new_euid,
    1612             :                                uid_t *_new_suid)
    1613             : {
    1614           0 :         struct uwrap_thread *id = uwrap_tls_id;
    1615           0 :         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
    1616             : 
    1617           0 :         UWRAP_LOG(UWRAP_LOG_TRACE,
    1618             :                   "ruid %d -> %d, euid %d -> %d",
    1619             :                   id->ruid, ruid, id->euid, euid);
    1620             : 
    1621           0 :         if (ruid != (uid_t)-1) {
    1622           0 :                 new_ruid = ruid;
    1623           0 :                 if (ruid != id->ruid &&
    1624           0 :                     ruid != id->euid &&
    1625           0 :                     id->euid != 0) {
    1626           0 :                         errno = EPERM;
    1627           0 :                         return -1;
    1628             :                 }
    1629             :         }
    1630             : 
    1631           0 :         if (euid != (uid_t)-1) {
    1632           0 :                 new_euid = euid;
    1633           0 :                 if (euid != id->ruid &&
    1634           0 :                     euid != id->euid &&
    1635           0 :                     euid != id->suid &&
    1636           0 :                     id->euid != 0) {
    1637           0 :                         errno = EPERM;
    1638           0 :                         return -1;
    1639             :                 }
    1640             :         }
    1641             : 
    1642           0 :         if (ruid != (uid_t) -1 ||
    1643           0 :             (euid != (uid_t)-1 && id->ruid != euid)) {
    1644           0 :                 new_suid = new_euid;
    1645             :         }
    1646             : 
    1647           0 :         *_new_ruid = new_ruid;
    1648           0 :         *_new_euid = new_euid;
    1649           0 :         *_new_suid = new_suid;
    1650             : 
    1651           0 :         return 0;
    1652             : }
    1653             : 
    1654           0 : static int uwrap_setreuid_thread(uid_t ruid, uid_t euid)
    1655             : {
    1656           0 :         struct uwrap_thread *id = uwrap_tls_id;
    1657           0 :         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
    1658           0 :         int rc;
    1659             : 
    1660           0 :         UWRAP_LOG(UWRAP_LOG_TRACE,
    1661             :                   "ruid %d -> %d, euid %d -> %d",
    1662             :                   id->ruid, ruid, id->euid, euid);
    1663             : 
    1664           0 :         rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
    1665           0 :         if (rc != 0) {
    1666           0 :                 return rc;
    1667             :         }
    1668             : 
    1669           0 :         return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
    1670             : }
    1671             : 
    1672             : #ifdef HAVE_SETREUID
    1673           0 : static int uwrap_setreuid(uid_t ruid, uid_t euid)
    1674             : {
    1675           0 :         struct uwrap_thread *id = uwrap_tls_id;
    1676           0 :         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
    1677           0 :         int rc;
    1678             : 
    1679           0 :         UWRAP_LOG(UWRAP_LOG_TRACE,
    1680             :                   "ruid %d -> %d, euid %d -> %d",
    1681             :                   id->ruid, ruid, id->euid, euid);
    1682             : 
    1683           0 :         rc = uwrap_setreuid_args(ruid, euid, &new_ruid, &new_euid, &new_suid);
    1684           0 :         if (rc != 0) {
    1685           0 :                 return rc;
    1686             :         }
    1687             : 
    1688           0 :         return uwrap_setresuid(new_ruid, new_euid, new_suid);
    1689             : }
    1690             : #endif
    1691             : 
    1692        8340 : static int uwrap_setuid_args(uid_t uid,
    1693             :                              uid_t *new_ruid,
    1694             :                              uid_t *new_euid,
    1695             :                              uid_t *new_suid)
    1696             : {
    1697        8340 :         struct uwrap_thread *id = uwrap_tls_id;
    1698             : 
    1699        8340 :         UWRAP_LOG(UWRAP_LOG_TRACE,
    1700             :                   "uid %d -> %d",
    1701             :                   id->ruid, uid);
    1702             : 
    1703        8340 :         if (uid == (uid_t)-1) {
    1704           0 :                 errno = EINVAL;
    1705           0 :                 return -1;
    1706             :         }
    1707             : 
    1708        8340 :         if (id->euid == 0) {
    1709        6448 :                 *new_suid = *new_ruid = uid;
    1710        1892 :         } else if (uid != id->ruid &&
    1711          16 :                    uid != id->suid) {
    1712          16 :                 errno = EPERM;
    1713          16 :                 return -1;
    1714             :         }
    1715             : 
    1716        8324 :         *new_euid = uid;
    1717             : 
    1718        8324 :         return 0;
    1719             : }
    1720             : 
    1721        8340 : static int uwrap_setuid_thread(uid_t uid)
    1722             : {
    1723        8340 :         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
    1724           0 :         int rc;
    1725             : 
    1726        8340 :         rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
    1727        8340 :         if (rc != 0) {
    1728          16 :                 return rc;
    1729             :         }
    1730             : 
    1731        8324 :         return uwrap_setresuid_thread(new_ruid, new_euid, new_suid);
    1732             : }
    1733             : 
    1734           0 : static int uwrap_setuid(uid_t uid)
    1735             : {
    1736           0 :         uid_t new_ruid = -1, new_euid = -1, new_suid = -1;
    1737           0 :         int rc;
    1738             : 
    1739           0 :         rc = uwrap_setuid_args(uid, &new_ruid, &new_euid, &new_suid);
    1740           0 :         if (rc != 0) {
    1741           0 :                 return rc;
    1742             :         }
    1743             : 
    1744           0 :         return uwrap_setresuid(new_ruid, new_euid, new_suid);
    1745             : }
    1746             : 
    1747             : /*
    1748             :  * UWRAP_GETxUID FUNCTIONS
    1749             :  */
    1750             : 
    1751             : #ifdef HAVE_GETRESUID
    1752           0 : static int uwrap_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
    1753             : {
    1754           0 :         struct uwrap_thread *id = uwrap_tls_id;
    1755             : 
    1756           0 :         UWRAP_LOCK(uwrap_id);
    1757             : 
    1758           0 :         *ruid = id->ruid;
    1759           0 :         *euid = id->euid;
    1760           0 :         *suid = id->suid;
    1761             : 
    1762           0 :         UWRAP_UNLOCK(uwrap_id);
    1763             : 
    1764           0 :         return 0;
    1765             : }
    1766             : #endif
    1767             : 
    1768             : #ifdef HAVE_GETRESGID
    1769           0 : static int uwrap_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
    1770             : {
    1771           0 :         struct uwrap_thread *id = uwrap_tls_id;
    1772             : 
    1773           0 :         UWRAP_LOCK(uwrap_id);
    1774             : 
    1775           0 :         *rgid = id->rgid;
    1776           0 :         *egid = id->egid;
    1777           0 :         *sgid = id->sgid;
    1778             : 
    1779           0 :         UWRAP_UNLOCK(uwrap_id);
    1780             : 
    1781           0 :         return 0;
    1782             : }
    1783             : #endif
    1784             : 
    1785             : /*
    1786             :  * UWRAP_SETxGID FUNCTIONS
    1787             :  */
    1788             : 
    1789    12193492 : static int uwrap_setresgid_args(gid_t rgid, gid_t egid, gid_t sgid)
    1790             : {
    1791    12193492 :         struct uwrap_thread *id = uwrap_tls_id;
    1792             : 
    1793    12193492 :         UWRAP_LOG(UWRAP_LOG_TRACE,
    1794             :                   "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
    1795             :                   id->rgid, rgid, id->egid, egid, id->sgid, sgid);
    1796             : 
    1797    12193492 :         if (id->euid != 0) {
    1798     4009669 :                 if (rgid != (gid_t)-1 &&
    1799          16 :                     rgid != id->rgid &&
    1800          16 :                     rgid != id->egid &&
    1801          16 :                     rgid != id->sgid) {
    1802          16 :                         errno = EPERM;
    1803          16 :                         return -1;
    1804             :                 }
    1805     4009653 :                 if (egid != (gid_t)-1 &&
    1806     4009653 :                     egid != id->rgid &&
    1807         875 :                     egid != id->egid &&
    1808           7 :                     egid != id->sgid) {
    1809           7 :                         errno = EPERM;
    1810           7 :                         return -1;
    1811             :                 }
    1812     4009646 :                 if (sgid != (gid_t)-1 &&
    1813           0 :                     sgid != id->rgid &&
    1814           0 :                     sgid != id->egid &&
    1815           0 :                     sgid != id->sgid) {
    1816           0 :                         errno = EPERM;
    1817           0 :                         return -1;
    1818             :                 }
    1819             :         }
    1820             : 
    1821    12166647 :         return 0;
    1822             : }
    1823             : 
    1824    12193492 : static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
    1825             : {
    1826    12193492 :         struct uwrap_thread *id = uwrap_tls_id;
    1827       26822 :         int rc;
    1828             : 
    1829    12193492 :         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);
    1832             : 
    1833    12193492 :         rc = uwrap_setresgid_args(rgid, egid, sgid);
    1834    12193492 :         if (rc != 0) {
    1835          23 :                 return rc;
    1836             :         }
    1837             : 
    1838    12193469 :         UWRAP_LOCK(uwrap_id);
    1839             : 
    1840    12193469 :         if (rgid != (gid_t)-1) {
    1841       16673 :                 id->rgid = rgid;
    1842             :         }
    1843             : 
    1844    12193469 :         if (egid != (gid_t)-1) {
    1845    12193469 :                 id->egid = egid;
    1846             :         }
    1847             : 
    1848    12193469 :         if (sgid != (gid_t)-1) {
    1849       16648 :                 id->sgid = sgid;
    1850             :         }
    1851             : 
    1852    12193469 :         UWRAP_UNLOCK(uwrap_id);
    1853             : 
    1854    12193469 :         return 0;
    1855             : }
    1856             : 
    1857           0 : static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
    1858             : {
    1859           0 :         struct uwrap_thread *id = uwrap_tls_id;
    1860           0 :         int rc;
    1861             : 
    1862           0 :         UWRAP_LOG(UWRAP_LOG_TRACE,
    1863             :                   "rgid %d -> %d, egid %d -> %d, sgid %d -> %d",
    1864             :                   id->rgid, rgid, id->egid, egid, id->sgid, sgid);
    1865             : 
    1866           0 :         rc = uwrap_setresgid_args(rgid, egid, sgid);
    1867           0 :         if (rc != 0) {
    1868           0 :                 return rc;
    1869             :         }
    1870             : 
    1871           0 :         UWRAP_LOCK(uwrap_id);
    1872             : 
    1873           0 :         for (id = uwrap.ids; id; id = id->next) {
    1874           0 :                 if (rgid != (gid_t)-1) {
    1875           0 :                         id->rgid = rgid;
    1876             :                 }
    1877             : 
    1878           0 :                 if (egid != (gid_t)-1) {
    1879           0 :                         id->egid = egid;
    1880             :                 }
    1881             : 
    1882           0 :                 if (sgid != (gid_t)-1) {
    1883           0 :                         id->sgid = sgid;
    1884             :                 }
    1885             :         }
    1886             : 
    1887           0 :         UWRAP_UNLOCK(uwrap_id);
    1888             : 
    1889           0 :         return 0;
    1890             : }
    1891             : 
    1892           0 : static int uwrap_setregid_args(gid_t rgid, gid_t egid,
    1893             :                                gid_t *_new_rgid,
    1894             :                                gid_t *_new_egid,
    1895             :                                gid_t *_new_sgid)
    1896             : {
    1897           0 :         struct uwrap_thread *id = uwrap_tls_id;
    1898           0 :         gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
    1899             : 
    1900           0 :         UWRAP_LOG(UWRAP_LOG_TRACE,
    1901             :                   "rgid %d -> %d, egid %d -> %d",
    1902             :                   id->rgid, rgid, id->egid, egid);
    1903             : 
    1904           0 :         if (rgid != (gid_t)-1) {
    1905           0 :                 new_rgid = rgid;
    1906           0 :                 if (rgid != id->rgid &&
    1907           0 :                     rgid != id->egid &&
    1908           0 :                     id->euid != 0) {
    1909           0 :                         errno = EPERM;
    1910           0 :                         return -1;
    1911             :                 }
    1912             :         }
    1913             : 
    1914           0 :         if (egid != (gid_t)-1) {
    1915           0 :                 new_egid = egid;
    1916           0 :                 if (egid != id->rgid &&
    1917           0 :                     egid != id->egid &&
    1918           0 :                     egid != id->sgid &&
    1919           0 :                     id->euid != 0) {
    1920           0 :                         errno = EPERM;
    1921           0 :                         return -1;
    1922             :                 }
    1923             :         }
    1924             : 
    1925           0 :         if (rgid != (gid_t) -1 ||
    1926           0 :             (egid != (gid_t)-1 && id->rgid != egid)) {
    1927           0 :                 new_sgid = new_egid;
    1928             :         }
    1929             : 
    1930           0 :         *_new_rgid = new_rgid;
    1931           0 :         *_new_egid = new_egid;
    1932           0 :         *_new_sgid = new_sgid;
    1933             : 
    1934           0 :         return 0;
    1935             : }
    1936             : 
    1937           0 : static int uwrap_setregid_thread(gid_t rgid, gid_t egid)
    1938             : {
    1939           0 :         struct uwrap_thread *id = uwrap_tls_id;
    1940           0 :         gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
    1941           0 :         int rc;
    1942             : 
    1943           0 :         UWRAP_LOG(UWRAP_LOG_TRACE,
    1944             :                   "rgid %d -> %d, egid %d -> %d",
    1945             :                   id->rgid, rgid, id->egid, egid);
    1946             : 
    1947           0 :         rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
    1948           0 :         if (rc != 0) {
    1949           0 :                 return rc;
    1950             :         }
    1951             : 
    1952           0 :         return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
    1953             : }
    1954             : 
    1955             : #ifdef HAVE_SETREGID
    1956           0 : static int uwrap_setregid(gid_t rgid, gid_t egid)
    1957             : {
    1958           0 :         struct uwrap_thread *id = uwrap_tls_id;
    1959           0 :         gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
    1960           0 :         int rc;
    1961             : 
    1962           0 :         UWRAP_LOG(UWRAP_LOG_TRACE,
    1963             :                   "rgid %d -> %d, egid %d -> %d",
    1964             :                   id->rgid, rgid, id->egid, egid);
    1965             : 
    1966           0 :         rc = uwrap_setregid_args(rgid, egid, &new_rgid, &new_egid, &new_sgid);
    1967           0 :         if (rc != 0) {
    1968           0 :                 return rc;
    1969             :         }
    1970             : 
    1971           0 :         return uwrap_setresgid(new_rgid, new_egid, new_sgid);
    1972             : }
    1973             : #endif
    1974             : 
    1975        8340 : static int uwrap_setgid_args(gid_t gid,
    1976             :                              gid_t *new_rgid,
    1977             :                              gid_t *new_egid,
    1978             :                              gid_t *new_sgid)
    1979             : {
    1980        8340 :         struct uwrap_thread *id = uwrap_tls_id;
    1981             : 
    1982        8340 :         UWRAP_LOG(UWRAP_LOG_TRACE,
    1983             :                   "gid %d -> %d",
    1984             :                   id->rgid, gid);
    1985             : 
    1986        8340 :         if (gid == (gid_t)-1) {
    1987           0 :                 errno = EINVAL;
    1988           0 :                 return -1;
    1989             :         }
    1990             : 
    1991        8340 :         if (id->euid == 0) {
    1992        8324 :                 *new_sgid = *new_rgid = gid;
    1993          16 :         } else if (gid != id->rgid &&
    1994          16 :                    gid != id->sgid) {
    1995          16 :                 errno = EPERM;
    1996          16 :                 return -1;
    1997             :         }
    1998             : 
    1999        8324 :         *new_egid = gid;
    2000             : 
    2001        8324 :         return 0;
    2002             : }
    2003             : 
    2004        8340 : static int uwrap_setgid_thread(gid_t gid)
    2005             : {
    2006        8340 :         gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
    2007           0 :         int rc;
    2008             : 
    2009        8340 :         rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
    2010        8340 :         if (rc != 0) {
    2011          16 :                 return rc;
    2012             :         }
    2013             : 
    2014        8324 :         return uwrap_setresgid_thread(new_rgid, new_egid, new_sgid);
    2015             : }
    2016             : 
    2017           0 : static int uwrap_setgid(gid_t gid)
    2018             : {
    2019           0 :         gid_t new_rgid = -1, new_egid = -1, new_sgid = -1;
    2020           0 :         int rc;
    2021             : 
    2022           0 :         rc = uwrap_setgid_args(gid, &new_rgid, &new_egid, &new_sgid);
    2023           0 :         if (rc != 0) {
    2024           0 :                 return rc;
    2025             :         }
    2026             : 
    2027           0 :         return uwrap_setresgid(new_rgid, new_egid, new_sgid);
    2028             : }
    2029             : 
    2030             : /*
    2031             :  * SETUID
    2032             :  */
    2033             : int setuid(uid_t uid)
    2034             : {
    2035           0 :         if (!uid_wrapper_enabled()) {
    2036           0 :                 return libc_setuid(uid);
    2037             :         }
    2038             : 
    2039           0 :         uwrap_init();
    2040           0 :         return uwrap_setuid(uid);
    2041             : }
    2042             : 
    2043             : #ifdef HAVE_SETEUID
    2044             : int seteuid(uid_t euid)
    2045             : {
    2046           0 :         if (!uid_wrapper_enabled()) {
    2047           0 :                 return libc_seteuid(euid);
    2048             :         }
    2049             : 
    2050             :         /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
    2051           0 :         if (euid == (uid_t)-1) {
    2052           0 :                 errno = EINVAL;
    2053           0 :                 return -1;
    2054             :         }
    2055             : 
    2056           0 :         uwrap_init();
    2057           0 :         return uwrap_setresuid(-1, euid, -1);
    2058             : }
    2059             : #endif
    2060             : 
    2061             : #ifdef HAVE_SETREUID
    2062             : int setreuid(uid_t ruid, uid_t euid)
    2063             : {
    2064           0 :         if (!uid_wrapper_enabled()) {
    2065           0 :                 return libc_setreuid(ruid, euid);
    2066             :         }
    2067             : 
    2068           0 :         uwrap_init();
    2069           0 :         return uwrap_setreuid(ruid, euid);
    2070             : }
    2071             : #endif
    2072             : 
    2073             : #ifdef HAVE_SETRESUID
    2074             : int setresuid(uid_t ruid, uid_t euid, uid_t suid)
    2075             : {
    2076           0 :         if (!uid_wrapper_enabled()) {
    2077           0 :                 return libc_setresuid(ruid, euid, suid);
    2078             :         }
    2079             : 
    2080           0 :         uwrap_init();
    2081           0 :         return uwrap_setresuid(ruid, euid, suid);
    2082             : }
    2083             : #endif
    2084             : 
    2085             : #ifdef HAVE_GETRESUID
    2086             : int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
    2087             : {
    2088           0 :         if (!uid_wrapper_enabled()) {
    2089           0 :                 return libc_getresuid(ruid, euid, suid);
    2090             :         }
    2091             : 
    2092           0 :         uwrap_init();
    2093           0 :         return uwrap_getresuid(ruid, euid, suid);
    2094             : }
    2095             : #endif
    2096             : 
    2097             : /*
    2098             :  * GETUID
    2099             :  */
    2100      227445 : static uid_t uwrap_getuid(void)
    2101             : {
    2102      227445 :         struct uwrap_thread *id = uwrap_tls_id;
    2103        4058 :         uid_t uid;
    2104             : 
    2105      227445 :         UWRAP_LOCK(uwrap_id);
    2106      227445 :         uid = id->ruid;
    2107      227445 :         UWRAP_UNLOCK(uwrap_id);
    2108             : 
    2109      227445 :         return uid;
    2110             : }
    2111             : 
    2112             : uid_t getuid(void)
    2113             : {
    2114      227445 :         if (!uid_wrapper_enabled()) {
    2115           0 :                 return libc_getuid();
    2116             :         }
    2117             : 
    2118      227445 :         uwrap_init();
    2119      227445 :         return uwrap_getuid();
    2120             : }
    2121             : 
    2122             : /*
    2123             :  * GETEUID
    2124             :  */
    2125    18160246 : static uid_t uwrap_geteuid(void)
    2126             : {
    2127    18160246 :         const char *env = getenv("UID_WRAPPER_MYUID");
    2128    18160246 :         struct uwrap_thread *id = uwrap_tls_id;
    2129       73780 :         uid_t uid;
    2130             : 
    2131    18160246 :         UWRAP_LOCK(uwrap_id);
    2132    18160246 :         uid = id->euid;
    2133    18160246 :         UWRAP_UNLOCK(uwrap_id);
    2134             : 
    2135             :         /* Disable root and return myuid */
    2136    18160246 :         if (env != NULL && env[0] == '1') {
    2137      375616 :                 uid = uwrap.myuid;
    2138             :         }
    2139             : 
    2140    18160246 :         return uid;
    2141             : }
    2142             : 
    2143             : uid_t geteuid(void)
    2144             : {
    2145    18160246 :         if (!uid_wrapper_enabled()) {
    2146           0 :                 return libc_geteuid();
    2147             :         }
    2148             : 
    2149    18160246 :         uwrap_init();
    2150    18160246 :         return uwrap_geteuid();
    2151             : }
    2152             : 
    2153             : /*
    2154             :  * SETGID
    2155             :  */
    2156             : int setgid(gid_t gid)
    2157             : {
    2158           0 :         if (!uid_wrapper_enabled()) {
    2159           0 :                 return libc_setgid(gid);
    2160             :         }
    2161             : 
    2162           0 :         uwrap_init();
    2163           0 :         return uwrap_setgid(gid);
    2164             : }
    2165             : 
    2166             : #ifdef HAVE_SETEGID
    2167             : int setegid(gid_t egid)
    2168             : {
    2169           0 :         if (!uid_wrapper_enabled()) {
    2170           0 :                 return libc_setegid(egid);
    2171             :         }
    2172             : 
    2173             :         /* On FreeBSD the uid_t -1 is set and doesn't produce and error */
    2174           0 :         if (egid == (gid_t)-1) {
    2175           0 :                 errno = EINVAL;
    2176           0 :                 return -1;
    2177             :         }
    2178             : 
    2179           0 :         uwrap_init();
    2180           0 :         return uwrap_setresgid(-1, egid, -1);
    2181             : }
    2182             : #endif
    2183             : 
    2184             : #ifdef HAVE_SETREGID
    2185             : int setregid(gid_t rgid, gid_t egid)
    2186             : {
    2187           0 :         if (!uid_wrapper_enabled()) {
    2188           0 :                 return libc_setregid(rgid, egid);
    2189             :         }
    2190             : 
    2191           0 :         uwrap_init();
    2192           0 :         return uwrap_setregid(rgid, egid);
    2193             : }
    2194             : #endif
    2195             : 
    2196             : #ifdef HAVE_SETRESGID
    2197             : int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
    2198             : {
    2199           0 :         if (!uid_wrapper_enabled()) {
    2200           0 :                 return libc_setresgid(rgid, egid, sgid);
    2201             :         }
    2202             : 
    2203           0 :         uwrap_init();
    2204           0 :         return uwrap_setresgid(rgid, egid, sgid);
    2205             : }
    2206             : #endif
    2207             : 
    2208             : #ifdef HAVE_GETRESGID
    2209             : int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
    2210             : {
    2211           0 :         if (!uid_wrapper_enabled()) {
    2212           0 :                 return libc_getresgid(rgid, egid, sgid);
    2213             :         }
    2214             : 
    2215           0 :         uwrap_init();
    2216           0 :         return uwrap_getresgid(rgid, egid, sgid);
    2217             : }
    2218             : #endif
    2219             : 
    2220             : /*
    2221             :  * GETGID
    2222             :  */
    2223       51622 : static gid_t uwrap_getgid(void)
    2224             : {
    2225       51622 :         struct uwrap_thread *id = uwrap_tls_id;
    2226        2733 :         gid_t gid;
    2227             : 
    2228       51622 :         UWRAP_LOCK(uwrap_id);
    2229       51622 :         gid = id->rgid;
    2230       51622 :         UWRAP_UNLOCK(uwrap_id);
    2231             : 
    2232       51622 :         return gid;
    2233             : }
    2234             : 
    2235             : gid_t getgid(void)
    2236             : {
    2237       51622 :         if (!uid_wrapper_enabled()) {
    2238           0 :                 return libc_getgid();
    2239             :         }
    2240             : 
    2241       51622 :         uwrap_init();
    2242       51622 :         return uwrap_getgid();
    2243             : }
    2244             : 
    2245             : /*
    2246             :  * GETEGID
    2247             :  */
    2248    16480066 : static uid_t uwrap_getegid(void)
    2249             : {
    2250    16480066 :         struct uwrap_thread *id = uwrap_tls_id;
    2251       37985 :         gid_t gid;
    2252             : 
    2253    16480066 :         UWRAP_LOCK(uwrap_id);
    2254    16480066 :         gid = id->egid;
    2255    16480066 :         UWRAP_UNLOCK(uwrap_id);
    2256             : 
    2257    16480066 :         return gid;
    2258             : }
    2259             : 
    2260             : uid_t getegid(void)
    2261             : {
    2262    16480066 :         if (!uid_wrapper_enabled()) {
    2263           0 :                 return libc_getegid();
    2264             :         }
    2265             : 
    2266    16480066 :         uwrap_init();
    2267    16480066 :         return uwrap_getegid();
    2268             : }
    2269             : 
    2270    12176828 : static int uwrap_setgroups_thread(size_t size, const gid_t *list)
    2271             : {
    2272    12176828 :         struct uwrap_thread *id = uwrap_tls_id;
    2273    12176828 :         int rc = -1;
    2274             : 
    2275    12176828 :         UWRAP_LOCK(uwrap_id);
    2276             : 
    2277    12176828 :         if (size == 0) {
    2278     6765653 :                 SAFE_FREE(id->groups);
    2279     6765653 :                 id->ngroups = 0;
    2280     5411175 :         } else if (size > 0) {
    2281        5911 :                 gid_t *tmp;
    2282             : 
    2283     5411175 :                 tmp = realloc(id->groups, sizeof(gid_t) * size);
    2284     5411175 :                 if (tmp == NULL) {
    2285           0 :                         errno = ENOMEM;
    2286           0 :                         goto out;
    2287             :                 }
    2288     5411175 :                 id->groups = tmp;
    2289     5411175 :                 id->ngroups = size;
    2290     5411175 :                 memcpy(id->groups, list, size * sizeof(gid_t));
    2291             :         }
    2292             : 
    2293    12150006 :         rc = 0;
    2294    12176828 : out:
    2295    12176828 :         UWRAP_UNLOCK(uwrap_id);
    2296             : 
    2297    12176828 :         return rc;
    2298             : }
    2299             : 
    2300           0 : static int uwrap_setgroups(size_t size, const gid_t *list)
    2301             : {
    2302           0 :         struct uwrap_thread *id;
    2303           0 :         int rc = -1;
    2304             : 
    2305           0 :         UWRAP_LOCK(uwrap_id);
    2306             : 
    2307           0 :         if (size == 0) {
    2308           0 :                 for (id = uwrap.ids; id; id = id->next) {
    2309           0 :                         SAFE_FREE(id->groups);
    2310           0 :                         id->ngroups = 0;
    2311             : 
    2312             :                 }
    2313           0 :         } else if (size > 0) {
    2314           0 :                 gid_t *tmp;
    2315             : 
    2316           0 :                 for (id = uwrap.ids; id; id = id->next) {
    2317           0 :                         tmp = realloc(id->groups, sizeof(gid_t) * size);
    2318           0 :                         if (tmp == NULL) {
    2319           0 :                                 errno = ENOMEM;
    2320           0 :                                 goto out;
    2321             :                         }
    2322           0 :                         id->groups = tmp;
    2323             : 
    2324           0 :                         id->ngroups = size;
    2325           0 :                         memcpy(id->groups, list, size * sizeof(gid_t));
    2326             :                 }
    2327             :         }
    2328             : 
    2329           0 :         rc = 0;
    2330           0 : out:
    2331           0 :         UWRAP_UNLOCK(uwrap_id);
    2332             : 
    2333           0 :         return rc;
    2334             : }
    2335             : 
    2336             : #ifdef HAVE_SETGROUPS_INT
    2337             : int setgroups(int size, const gid_t *list)
    2338             : #else
    2339             : int setgroups(size_t size, const gid_t *list)
    2340             : #endif
    2341             : {
    2342           0 :         if (!uid_wrapper_enabled()) {
    2343           0 :                 return libc_setgroups(size, list);
    2344             :         }
    2345             : 
    2346           0 :         uwrap_init();
    2347           0 :         return uwrap_setgroups(size, list);
    2348             : }
    2349             : 
    2350     9522684 : static int uwrap_getgroups(int size, gid_t *list)
    2351             : {
    2352     9522684 :         struct uwrap_thread *id = uwrap_tls_id;
    2353           0 :         int ngroups;
    2354             : 
    2355     9522684 :         UWRAP_LOCK(uwrap_id);
    2356     9522684 :         ngroups = id->ngroups;
    2357             : 
    2358     9522684 :         if (size > ngroups) {
    2359           0 :                 size = ngroups;
    2360             :         }
    2361     9522684 :         if (size == 0) {
    2362     5575641 :                 goto out;
    2363             :         }
    2364     3947043 :         if (size < ngroups) {
    2365           0 :                 errno = EINVAL;
    2366           0 :                 ngroups = -1;
    2367             :         }
    2368     3947043 :         memcpy(list, id->groups, size * sizeof(gid_t));
    2369             : 
    2370     9522684 : out:
    2371     9522684 :         UWRAP_UNLOCK(uwrap_id);
    2372             : 
    2373     9522684 :         return ngroups;
    2374             : }
    2375             : 
    2376             : int getgroups(int size, gid_t *list)
    2377             : {
    2378     9522684 :         if (!uid_wrapper_enabled()) {
    2379           0 :                 return libc_getgroups(size, list);
    2380             :         }
    2381             : 
    2382     9522684 :         uwrap_init();
    2383     9522684 :         return uwrap_getgroups(size, list);
    2384             : }
    2385             : 
    2386             : #ifdef HAVE___GETGROUPS_CHK
    2387             : static int uwrap___getgroups_chk(int size, gid_t *list, size_t listlen)
    2388             : {
    2389             :         if (size * sizeof(gid_t) > listlen) {
    2390             :                 UWRAP_LOG(UWRAP_LOG_DEBUG, "Buffer overflow detected");
    2391             :                 abort();
    2392             :         }
    2393             : 
    2394             :         return uwrap_getgroups(size, list);
    2395             : }
    2396             : 
    2397             : int __getgroups_chk(int size, gid_t *list, size_t listlen);
    2398             : 
    2399             : int __getgroups_chk(int size, gid_t *list, size_t listlen)
    2400             : {
    2401             :         if (!uid_wrapper_enabled()) {
    2402             :                 return libc___getgroups_chk(size, list, listlen);
    2403             :         }
    2404             : 
    2405             :         uwrap_init();
    2406             :         return uwrap___getgroups_chk(size, list, listlen);
    2407             : }
    2408             : #endif /* HAVE___GETGROUPS_CHK */
    2409             : 
    2410             : #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
    2411             :     && (defined(SYS_setreuid) || defined(SYS_setreuid32))
    2412    76725828 : static bool uwrap_is_uwrap_related_syscall(long int sysno)
    2413             : {
    2414    76725828 :         switch (sysno) {
    2415             :         /* gid */
    2416             : #ifdef __alpha__
    2417             :         case SYS_getxgid:
    2418             :                 return true;
    2419             : #else
    2420           0 :         case SYS_getgid:
    2421           0 :                 return true;
    2422             : #endif
    2423             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2424             :         case SYS_getgid32:
    2425             :                 return true;
    2426             : #endif
    2427             : #ifdef SYS_getegid
    2428           0 :         case SYS_getegid:
    2429           0 :                 return true;
    2430             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2431             :         case SYS_getegid32:
    2432             :                 return true;
    2433             : #endif
    2434             : #endif /* SYS_getegid */
    2435       16680 :         case SYS_setgid:
    2436       16680 :                 return true;
    2437             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2438             :         case SYS_setgid32:
    2439             :                 return true;
    2440             : #endif
    2441           0 :         case SYS_setregid:
    2442           0 :                 return true;
    2443             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2444             :         case SYS_setregid32:
    2445             :                 return true;
    2446             : #endif
    2447             : #ifdef SYS_setresgid
    2448    24316692 :         case SYS_setresgid:
    2449    24316692 :                 return true;
    2450             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2451             :         case SYS_setresgid32:
    2452             :                 return true;
    2453             : #endif
    2454             : #endif /* SYS_setresgid */
    2455             : #if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
    2456           0 :         case SYS_getresgid:
    2457           0 :                 return true;
    2458             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2459             :         case SYS_getresgid32:
    2460             :                 return true;
    2461             : #endif
    2462             : #endif /* SYS_getresgid && HAVE_GETRESGID */
    2463             : 
    2464             :         /* uid */
    2465             : #ifdef __alpha__
    2466             :         case SYS_getxuid:
    2467             :                 return true;
    2468             : #else
    2469           0 :         case SYS_getuid:
    2470           0 :                 return true;
    2471             : #endif
    2472             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2473             :         case SYS_getuid32:
    2474             :                 return true;
    2475             : #endif
    2476             : #ifdef SYS_geteuid
    2477           0 :         case SYS_geteuid:
    2478           0 :                 return true;
    2479             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2480             :         case SYS_geteuid32:
    2481             :                 return true;
    2482             : #endif
    2483             : #endif /* SYS_geteuid */
    2484       16680 :         case SYS_setuid:
    2485       16680 :                 return true;
    2486             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2487             :         case SYS_setuid32:
    2488             :                 return true;
    2489             : #endif
    2490           0 :         case SYS_setreuid:
    2491           0 :                 return true;
    2492             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2493             :         case SYS_setreuid32:
    2494             :                 return true;
    2495             : #endif
    2496             : #ifdef SYS_setresuid
    2497    27112830 :         case SYS_setresuid:
    2498    27112830 :                 return true;
    2499             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2500             :         case SYS_setresuid32:
    2501             :                 return true;
    2502             : #endif
    2503             : #endif /* SYS_setresuid */
    2504             : #if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
    2505           0 :         case SYS_getresuid:
    2506           0 :                 return true;
    2507             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2508             :         case SYS_getresuid32:
    2509             :                 return true;
    2510             : #endif
    2511             : #endif /* SYS_getresuid && HAVE_GETRESUID*/
    2512             :         /* groups */
    2513    24300012 :         case SYS_setgroups:
    2514    24300012 :                 return true;
    2515             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2516             :         case SYS_setgroups32:
    2517             :                 return true;
    2518             : #endif
    2519      800536 :         default:
    2520      800536 :                 return false;
    2521             :         }
    2522             : }
    2523             : 
    2524    37961913 : static long int uwrap_syscall (long int sysno, va_list vp)
    2525             : {
    2526       80466 :         long int rc;
    2527             : 
    2528    37961913 :         switch (sysno) {
    2529             :                 /* gid */
    2530             : #ifdef __alpha__
    2531             :                 case SYS_getxgid:
    2532             : #else
    2533           0 :                 case SYS_getgid:
    2534             : #endif
    2535             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2536             :                 case SYS_getgid32:
    2537             : #endif
    2538             :                         {
    2539           0 :                                 rc = uwrap_getgid();
    2540             :                         }
    2541           0 :                         break;
    2542             : #ifdef SYS_getegid
    2543           0 :                 case SYS_getegid:
    2544             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2545             :                 case SYS_getegid32:
    2546             : #endif
    2547             :                         {
    2548           0 :                                 rc = uwrap_getegid();
    2549             :                         }
    2550           0 :                         break;
    2551             : #endif /* SYS_getegid */
    2552        8340 :                 case SYS_setgid:
    2553             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2554             :                 case SYS_setgid32:
    2555             : #endif
    2556             :                         {
    2557        8340 :                                 gid_t gid = (gid_t) va_arg(vp, gid_t);
    2558             : 
    2559        8340 :                                 rc = uwrap_setgid_thread(gid);
    2560             :                         }
    2561        8340 :                         break;
    2562           0 :                 case SYS_setregid:
    2563             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2564             :                 case SYS_setregid32:
    2565             : #endif
    2566             :                         {
    2567           0 :                                 gid_t rgid = (gid_t) va_arg(vp, gid_t);
    2568           0 :                                 gid_t egid = (gid_t) va_arg(vp, gid_t);
    2569             : 
    2570           0 :                                 rc = uwrap_setregid_thread(rgid, egid);
    2571             :                         }
    2572           0 :                         break;
    2573             : #ifdef SYS_setresgid
    2574    12185168 :                 case SYS_setresgid:
    2575             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2576             :                 case SYS_setresgid32:
    2577             : #endif
    2578             :                         {
    2579    12185168 :                                 gid_t rgid = (gid_t) va_arg(vp, gid_t);
    2580    12185168 :                                 gid_t egid = (gid_t) va_arg(vp, gid_t);
    2581    12185168 :                                 gid_t sgid = (gid_t) va_arg(vp, gid_t);
    2582             : 
    2583    12185168 :                                 rc = uwrap_setresgid_thread(rgid, egid, sgid);
    2584             :                         }
    2585    12185168 :                         break;
    2586             : #endif /* SYS_setresgid */
    2587             : #if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
    2588           0 :                 case SYS_getresgid:
    2589             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2590             :                 case SYS_getresgid32:
    2591             : #endif
    2592             :                         {
    2593           0 :                                 gid_t *rgid = (gid_t *) va_arg(vp, gid_t *);
    2594           0 :                                 gid_t *egid = (gid_t *) va_arg(vp, gid_t *);
    2595           0 :                                 gid_t *sgid = (gid_t *) va_arg(vp, gid_t *);
    2596             : 
    2597           0 :                                 rc = uwrap_getresgid(rgid, egid, sgid);
    2598             :                         }
    2599           0 :                         break;
    2600             : #endif /* SYS_getresgid && HAVE_GETRESGID */
    2601             : 
    2602             :                 /* uid */
    2603             : #ifdef __alpha__
    2604             :                 case SYS_getxuid:
    2605             : #else
    2606           0 :                 case SYS_getuid:
    2607             : #endif
    2608             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2609             :                 case SYS_getuid32:
    2610             : #endif
    2611             :                         {
    2612           0 :                                 rc = uwrap_getuid();
    2613             :                         }
    2614           0 :                         break;
    2615             : #ifdef SYS_geteuid
    2616           0 :                 case SYS_geteuid:
    2617             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2618             :                 case SYS_geteuid32:
    2619             : #endif
    2620             :                         {
    2621           0 :                                 rc = uwrap_geteuid();
    2622             :                         }
    2623           0 :                         break;
    2624             : #endif /* SYS_geteuid */
    2625        8340 :                 case SYS_setuid:
    2626             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2627             :                 case SYS_setuid32:
    2628             : #endif
    2629             :                         {
    2630        8340 :                                 uid_t uid = (uid_t) va_arg(vp, uid_t);
    2631             : 
    2632        8340 :                                 rc = uwrap_setuid_thread(uid);
    2633             :                         }
    2634        8340 :                         break;
    2635           0 :                 case SYS_setreuid:
    2636             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2637             :                 case SYS_setreuid32:
    2638             : #endif
    2639             :                         {
    2640           0 :                                 uid_t ruid = (uid_t) va_arg(vp, uid_t);
    2641           0 :                                 uid_t euid = (uid_t) va_arg(vp, uid_t);
    2642             : 
    2643           0 :                                 rc = uwrap_setreuid_thread(ruid, euid);
    2644             :                         }
    2645           0 :                         break;
    2646             : #ifdef SYS_setresuid
    2647    13583237 :                 case SYS_setresuid:
    2648             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2649             :                 case SYS_setresuid32:
    2650             : #endif
    2651             :                         {
    2652    13583237 :                                 uid_t ruid = (uid_t) va_arg(vp, uid_t);
    2653    13583237 :                                 uid_t euid = (uid_t) va_arg(vp, uid_t);
    2654    13583237 :                                 uid_t suid = (uid_t) va_arg(vp, uid_t);
    2655             : 
    2656    13583237 :                                 rc = uwrap_setresuid_thread(ruid, euid, suid);
    2657             :                         }
    2658    13583237 :                         break;
    2659             : #endif /* SYS_setresuid */
    2660             : #if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
    2661           0 :                 case SYS_getresuid:
    2662             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2663             :                 case SYS_getresuid32:
    2664             : #endif
    2665             :                         {
    2666           0 :                                 uid_t *ruid = (uid_t *) va_arg(vp, uid_t *);
    2667           0 :                                 uid_t *euid = (uid_t *) va_arg(vp, uid_t *);
    2668           0 :                                 uid_t *suid = (uid_t *) va_arg(vp, uid_t *);
    2669             : 
    2670           0 :                                 rc = uwrap_getresuid(ruid, euid, suid);
    2671             :                         }
    2672           0 :                         break;
    2673             : #endif /* SYS_getresuid && HAVE_GETRESUID*/
    2674             :                 /* groups */
    2675    12176828 :                 case SYS_setgroups:
    2676             : #ifdef HAVE_LINUX_32BIT_SYSCALLS
    2677             :                 case SYS_setgroups32:
    2678             : #endif
    2679             :                         {
    2680    12176828 :                                 size_t size = (size_t) va_arg(vp, size_t);
    2681    12176828 :                                 gid_t *list = (gid_t *) va_arg(vp, int *);
    2682             : 
    2683    12176828 :                                 rc = uwrap_setgroups_thread(size, list);
    2684             :                         }
    2685    12176828 :                         break;
    2686           0 :                 default:
    2687           0 :                         rc = -1;
    2688           0 :                         errno = ENOSYS;
    2689           0 :                         break;
    2690             :         }
    2691             : 
    2692    37961913 :         return rc;
    2693             : }
    2694             : 
    2695             : #ifdef HAVE_SYSCALL
    2696             : #ifdef HAVE_SYSCALL_INT
    2697             : int syscall (int sysno, ...)
    2698             : #else
    2699             : long int syscall (long int sysno, ...)
    2700             : #endif
    2701             : {
    2702             : #ifdef HAVE_SYSCALL_INT
    2703             :         int rc;
    2704             : #else
    2705           0 :         long int rc;
    2706             : #endif
    2707           0 :         va_list va;
    2708             : 
    2709           0 :         va_start(va, sysno);
    2710             : 
    2711             :         /*
    2712             :          * We need to check for uwrap related syscall numbers before calling
    2713             :          * uid_wrapper_enabled() otherwise we'd deadlock during the freebsd libc
    2714             :          * fork() which calls syscall() after invoking uwrap_thread_prepare().
    2715             :          */
    2716           0 :         if (!uwrap_is_uwrap_related_syscall(sysno)) {
    2717             :                 /*
    2718             :                  * We need to give socket_wrapper a
    2719             :                  * chance to take over...
    2720             :                  */
    2721           0 :                 if (uwrap_swrap_syscall_valid(sysno)) {
    2722           0 :                         rc = uwrap_swrap_syscall_va(sysno, va);
    2723           0 :                         va_end(va);
    2724           0 :                         return rc;
    2725             :                 }
    2726             : 
    2727           0 :                 rc = libc_vsyscall(sysno, va);
    2728           0 :                 va_end(va);
    2729           0 :                 return rc;
    2730             :         }
    2731             : 
    2732           0 :         if (!uid_wrapper_enabled()) {
    2733           0 :                 rc = libc_vsyscall(sysno, va);
    2734           0 :                 va_end(va);
    2735           0 :                 return rc;
    2736             :         }
    2737             : 
    2738           0 :         uwrap_init();
    2739           0 :         rc = uwrap_syscall(sysno, va);
    2740           0 :         va_end(va);
    2741             : 
    2742           0 :         return rc;
    2743             : }
    2744             : 
    2745             : /* used by socket_wrapper */
    2746             : bool uid_wrapper_syscall_valid(long int sysno);
    2747    38763915 : bool uid_wrapper_syscall_valid(long int sysno)
    2748             : {
    2749    38763915 :         if (!uwrap_is_uwrap_related_syscall(sysno)) {
    2750      800536 :                 return false;
    2751             :         }
    2752             : 
    2753    37961913 :         if (!uid_wrapper_enabled()) {
    2754           0 :                 return false;
    2755             :         }
    2756             : 
    2757    37881447 :         return true;
    2758             : }
    2759             : 
    2760             : /* used by socket_wrapper */
    2761             : long int uid_wrapper_syscall_va(long int sysno, va_list va);
    2762    37961913 : long int uid_wrapper_syscall_va(long int sysno, va_list va)
    2763             : {
    2764    37961913 :         if (!uwrap_is_uwrap_related_syscall(sysno)) {
    2765           0 :                 errno = ENOSYS;
    2766           0 :                 return -1;
    2767             :         }
    2768             : 
    2769    37961913 :         if (!uid_wrapper_enabled()) {
    2770           0 :                 return libc_vsyscall(sysno, va);
    2771             :         }
    2772             : 
    2773    37961913 :         uwrap_init();
    2774             : 
    2775    37961913 :         return uwrap_syscall(sysno, va);
    2776             : }
    2777             : #endif /* HAVE_SYSCALL */
    2778             : #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
    2779             : 
    2780             : /****************************
    2781             :  * CONSTRUCTOR
    2782             :  ***************************/
    2783             : 
    2784      179839 : void uwrap_constructor(void)
    2785             : {
    2786        4842 :         char *glibc_malloc_lock_bug;
    2787             : 
    2788             :         /*
    2789             :          * This is a workaround for a bug in glibc < 2.24:
    2790             :          *
    2791             :          * The child handler for the malloc() function is called and locks the
    2792             :          * mutex. Then our child handler is called and we try to call setenv().
    2793             :          * setenv() wants to malloc and tries to aquire the lock for malloc and
    2794             :          * we end up in a deadlock.
    2795             :          *
    2796             :          * So as a workaround we need to call malloc once before we setup the
    2797             :          * handlers.
    2798             :          *
    2799             :          * See https://sourceware.org/bugzilla/show_bug.cgi?id=16742
    2800             :          */
    2801      179839 :         glibc_malloc_lock_bug = malloc(1);
    2802      179839 :         if (glibc_malloc_lock_bug == NULL) {
    2803           0 :                 exit(-1);
    2804             :         }
    2805      179839 :         glibc_malloc_lock_bug[0] = '\0';
    2806             : 
    2807      179839 :         UWRAP_REINIT_ALL;
    2808             : 
    2809             :         /*
    2810             :         * If we hold a lock and the application forks, then the child
    2811             :         * is not able to unlock the mutex and we are in a deadlock.
    2812             :         * This should prevent such deadlocks.
    2813             :         */
    2814      179839 :         pthread_atfork(&uwrap_thread_prepare,
    2815             :                        &uwrap_thread_parent,
    2816             :                        &uwrap_thread_child);
    2817             : 
    2818      179839 :         free(glibc_malloc_lock_bug);
    2819             : 
    2820             :         /* Here is safe place to call uwrap_init() and initialize data
    2821             :          * for main process.
    2822             :          */
    2823      179839 :         uwrap_init();
    2824      179839 : }
    2825             : 
    2826             : /****************************
    2827             :  * DESTRUCTOR
    2828             :  ***************************/
    2829             : 
    2830             : /*
    2831             :  * This function is called when the library is unloaded and makes sure that
    2832             :  * resources are freed.
    2833             :  */
    2834      232040 : void uwrap_destructor(void)
    2835             : {
    2836      232040 :         struct uwrap_thread *u = uwrap.ids;
    2837             : 
    2838      232040 :         UWRAP_LOCK_ALL;
    2839             : 
    2840      468875 :         while (u != NULL) {
    2841      236835 :                 UWRAP_DLIST_REMOVE(uwrap.ids, u);
    2842             : 
    2843      236835 :                 SAFE_FREE(u->groups);
    2844      236835 :                 SAFE_FREE(u);
    2845             : 
    2846      236835 :                 u = uwrap.ids;
    2847             :         }
    2848             : 
    2849             : 
    2850      232040 :         if (uwrap.libc.handle != NULL
    2851             : #ifdef RTLD_NEXT
    2852      232040 :             && uwrap.libc.handle != RTLD_NEXT
    2853             : #endif
    2854             :            ) {
    2855      232040 :                 dlclose(uwrap.libc.handle);
    2856             :         }
    2857             : 
    2858      232040 :         if (uwrap.libpthread.handle != NULL
    2859             : #ifdef RTLD_NEXT
    2860      232040 :             && uwrap.libpthread.handle != RTLD_NEXT
    2861             : #endif
    2862             :            ) {
    2863           0 :                 dlclose(uwrap.libpthread.handle);
    2864             :         }
    2865             : 
    2866      232040 :         UWRAP_UNLOCK_ALL;
    2867      232040 : }

Generated by: LCOV version 1.14