2009-08-05 10:50:03 +10:00
/*
2014-01-17 14:43:01 +01:00
* Copyright ( c ) 2009 Andrew Tridgell
* Copyright ( c ) 2011 - 2013 Andreas Schneider < asn @ samba . org >
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2009-08-05 10:50:03 +10:00
*/
2014-01-17 14:43:01 +01:00
# include "config.h"
2010-01-30 14:25:51 +01:00
2014-01-17 14:43:01 +01:00
# include <errno.h>
# include <stdarg.h>
# include <stdbool.h>
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <sys/types.h>
# include <unistd.h>
# include <grp.h>
# ifdef HAVE_SYS_SYSCALL_H
# include <sys/syscall.h>
# endif
# ifdef HAVE_SYSCALL_H
# include <syscall.h>
# endif
# include <dlfcn.h>
2019-07-15 10:32:49 +02:00
# include <limits.h>
2014-01-17 14:43:01 +01:00
# include <pthread.h>
2024-06-13 07:41:41 +02:00
# ifdef HAVE_GNU_LIB_NAMES_H
# include <gnu/lib-names.h>
# endif
2014-01-17 14:43:01 +01:00
# ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
# define UWRAP_THREAD __thread
# else
# define UWRAP_THREAD
# endif
2015-01-23 15:10:02 +01:00
# ifdef HAVE_CONSTRUCTOR_ATTRIBUTE
# define CONSTRUCTOR_ATTRIBUTE __attribute__ ((constructor))
# else
# define CONSTRUCTOR_ATTRIBUTE
# endif /* HAVE_CONSTRUCTOR_ATTRIBUTE */
2014-01-17 14:43:01 +01:00
# ifdef HAVE_DESTRUCTOR_ATTRIBUTE
# define DESTRUCTOR_ATTRIBUTE __attribute__ ((destructor))
# else
# define DESTRUCTOR_ATTRIBUTE
# endif /* HAVE_DESTRUCTOR_ATTRIBUTE */
2015-01-23 15:22:18 +01:00
# ifdef HAVE_ADDRESS_SANITIZER_ATTRIBUTE
# define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE __attribute__((no_sanitize_address))
# else /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
# define DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
# endif /* DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE */
2014-07-31 10:18:13 +02:00
/* GCC have printf type attribute check. */
# ifdef HAVE_FUNCTION_ATTRIBUTE_FORMAT
# define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
# else
# define PRINTF_ATTRIBUTE(a,b)
# endif /* HAVE_FUNCTION_ATTRIBUTE_FORMAT */
2019-07-15 10:32:49 +02:00
# ifndef FALL_THROUGH
# ifdef HAVE_FALLTHROUGH_ATTRIBUTE
# define FALL_THROUGH __attribute__ ((fallthrough))
# else /* HAVE_FALLTHROUGH_ATTRIBUTE */
# define FALL_THROUGH
# endif /* HAVE_FALLTHROUGH_ATTRIBUTE */
# endif /* FALL_THROUGH */
2014-01-17 14:43:01 +01:00
# define UWRAP_DLIST_ADD(list,item) do { \
if ( ! ( list ) ) { \
( item ) - > prev = NULL ; \
( item ) - > next = NULL ; \
( list ) = ( item ) ; \
} else { \
( item ) - > prev = NULL ; \
( item ) - > next = ( list ) ; \
( list ) - > prev = ( item ) ; \
( list ) = ( item ) ; \
} \
} while ( 0 )
2010-01-30 14:25:51 +01:00
2014-01-17 14:43:01 +01:00
# define UWRAP_DLIST_REMOVE(list,item) do { \
if ( ( list ) = = ( item ) ) { \
( list ) = ( item ) - > next ; \
if ( list ) { \
( list ) - > prev = NULL ; \
} \
} else { \
if ( ( item ) - > prev ) { \
( item ) - > prev - > next = ( item ) - > next ; \
} \
if ( ( item ) - > next ) { \
( item ) - > next - > prev = ( item ) - > prev ; \
} \
} \
( item ) - > prev = NULL ; \
( item ) - > next = NULL ; \
} while ( 0 )
# ifndef SAFE_FREE
# define SAFE_FREE(x) do { if ((x) != NULL) {free(x); (x)=NULL;} } while(0)
# endif
2010-01-30 14:25:51 +01:00
2014-07-31 10:18:59 +02:00
/*****************
* LOGGING
* * * * * * * * * * * * * * * * */
enum uwrap_dbglvl_e {
UWRAP_LOG_ERROR = 0 ,
UWRAP_LOG_WARN ,
UWRAP_LOG_DEBUG ,
UWRAP_LOG_TRACE
} ;
2023-01-16 22:14:03 +01:00
# ifndef HAVE_GETPROGNAME
static const char * getprogname ( void )
{
# if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
return program_invocation_short_name ;
# elif defined(HAVE_GETEXECNAME)
return getexecname ( ) ;
# else
return NULL ;
# endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */
}
# endif /* HAVE_GETPROGNAME */
2015-10-30 13:36:39 +01:00
static void uwrap_log ( enum uwrap_dbglvl_e dbglvl , const char * function , const char * format , . . . ) PRINTF_ATTRIBUTE ( 3 , 4 ) ;
# define UWRAP_LOG(dbglvl, ...) uwrap_log((dbglvl), __func__, __VA_ARGS__)
2014-07-31 10:18:59 +02:00
2015-10-30 13:36:39 +01:00
static void uwrap_log ( enum uwrap_dbglvl_e dbglvl , const char * function , const char * format , . . . )
2014-07-31 10:18:59 +02:00
{
char buffer [ 1024 ] ;
va_list va ;
const char * d ;
unsigned int lvl = 0 ;
2017-07-13 08:57:13 +02:00
const char * prefix = " UWRAP " ;
2023-01-16 22:14:03 +01:00
const char * progname = getprogname ( ) ;
2014-07-31 10:18:59 +02:00
d = getenv ( " UID_WRAPPER_DEBUGLEVEL " ) ;
if ( d ! = NULL ) {
lvl = atoi ( d ) ;
}
2017-07-13 08:57:13 +02:00
if ( lvl < dbglvl ) {
return ;
}
2014-07-31 10:18:59 +02:00
va_start ( va , format ) ;
vsnprintf ( buffer , sizeof ( buffer ) , format , va ) ;
va_end ( va ) ;
2017-07-13 08:57:13 +02:00
switch ( dbglvl ) {
case UWRAP_LOG_ERROR :
prefix = " UWRAP_ERROR " ;
break ;
case UWRAP_LOG_WARN :
prefix = " UWRAP_WARN " ;
break ;
case UWRAP_LOG_DEBUG :
prefix = " UWRAP_DEBUG " ;
break ;
case UWRAP_LOG_TRACE :
prefix = " UWRAP_TRACE " ;
break ;
2014-07-31 10:18:59 +02:00
}
2017-07-13 08:57:13 +02:00
2023-01-16 22:14:03 +01:00
if ( progname = = NULL ) {
progname = " <unknown> " ;
}
2017-07-13 08:57:13 +02:00
fprintf ( stderr ,
2023-01-16 22:14:03 +01:00
" %s[%s (%u)] - %s: %s \n " ,
2017-07-13 08:57:13 +02:00
prefix ,
2023-01-16 22:14:03 +01:00
progname ,
2017-07-13 08:57:13 +02:00
( int ) getpid ( ) ,
function ,
buffer ) ;
2014-07-31 10:18:59 +02:00
}
/*****************
* LIBC
* * * * * * * * * * * * * * * * */
2014-01-17 14:43:01 +01:00
# define LIBC_NAME "libc.so"
2010-01-30 14:25:51 +01:00
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_setuid ) ( uid_t uid ) ;
typedef uid_t ( * __libc_getuid ) ( void ) ;
2014-01-17 14:43:01 +01:00
# ifdef HAVE_SETEUID
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_seteuid ) ( uid_t euid ) ;
2014-01-17 14:43:01 +01:00
# endif
2015-01-23 15:28:37 +01:00
2014-01-17 14:43:01 +01:00
# ifdef HAVE_SETREUID
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_setreuid ) ( uid_t ruid , uid_t euid ) ;
2014-01-17 14:43:01 +01:00
# endif
2015-01-23 15:28:37 +01:00
2014-01-17 14:43:01 +01:00
# ifdef HAVE_SETRESUID
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_setresuid ) ( uid_t ruid , uid_t euid , uid_t suid ) ;
2015-01-23 15:27:25 +01:00
# endif
2015-01-23 15:28:37 +01:00
2015-01-23 15:27:25 +01:00
# ifdef HAVE_GETRESUID
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_getresuid ) ( uid_t * ruid , uid_t * euid , uid_t * suid ) ;
2010-01-30 14:25:51 +01:00
# endif
2009-08-05 10:50:03 +10:00
2015-01-23 15:28:37 +01:00
typedef uid_t ( * __libc_geteuid ) ( void ) ;
typedef int ( * __libc_setgid ) ( gid_t gid ) ;
typedef gid_t ( * __libc_getgid ) ( void ) ;
2014-01-17 14:43:01 +01:00
# ifdef HAVE_SETEGID
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_setegid ) ( uid_t egid ) ;
2014-01-17 14:43:01 +01:00
# endif
2015-01-23 15:28:37 +01:00
2014-01-17 14:43:01 +01:00
# ifdef HAVE_SETREGID
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_setregid ) ( uid_t rgid , uid_t egid ) ;
2014-01-17 14:43:01 +01:00
# endif
2015-01-23 15:28:37 +01:00
2014-01-17 14:43:01 +01:00
# ifdef HAVE_SETRESGID
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_setresgid ) ( uid_t rgid , uid_t egid , uid_t sgid ) ;
2015-01-23 15:27:25 +01:00
# endif
2015-01-23 15:28:37 +01:00
2015-01-23 15:27:25 +01:00
# ifdef HAVE_GETRESGID
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_getresgid ) ( gid_t * rgid , gid_t * egid , gid_t * sgid ) ;
2014-01-17 14:43:01 +01:00
# endif
2015-01-23 15:28:37 +01:00
typedef gid_t ( * __libc_getegid ) ( void ) ;
typedef int ( * __libc_getgroups ) ( int size , gid_t list [ ] ) ;
2023-01-16 22:14:03 +01:00
# ifdef HAVE___GETGROUPS_CHK
typedef int ( * __libc___getgroups_chk ) ( int size , gid_t list [ ] , size_t listlen ) ;
# endif
2015-01-23 15:28:37 +01:00
typedef int ( * __libc_setgroups ) ( size_t size , const gid_t * list ) ;
2014-01-17 14:43:01 +01:00
# ifdef HAVE_SYSCALL
2015-01-23 15:28:37 +01:00
typedef long int ( * __libc_syscall ) ( long int sysno , . . . ) ;
# endif
# define UWRAP_SYMBOL_ENTRY(i) \
union { \
__libc_ # # i f ; \
void * obj ; \
} _libc_ # # i
struct uwrap_libc_symbols {
UWRAP_SYMBOL_ENTRY ( setuid ) ;
UWRAP_SYMBOL_ENTRY ( getuid ) ;
# ifdef HAVE_SETEUID
UWRAP_SYMBOL_ENTRY ( seteuid ) ;
# endif
# ifdef HAVE_SETREUID
UWRAP_SYMBOL_ENTRY ( setreuid ) ;
# endif
# ifdef HAVE_SETRESUID
UWRAP_SYMBOL_ENTRY ( setresuid ) ;
# endif
# ifdef HAVE_GETRESUID
UWRAP_SYMBOL_ENTRY ( getresuid ) ;
# endif
UWRAP_SYMBOL_ENTRY ( geteuid ) ;
UWRAP_SYMBOL_ENTRY ( setgid ) ;
UWRAP_SYMBOL_ENTRY ( getgid ) ;
# ifdef HAVE_SETEGID
UWRAP_SYMBOL_ENTRY ( setegid ) ;
# endif
# ifdef HAVE_SETREGID
UWRAP_SYMBOL_ENTRY ( setregid ) ;
# endif
# ifdef HAVE_SETRESGID
UWRAP_SYMBOL_ENTRY ( setresgid ) ;
# endif
# ifdef HAVE_GETRESGID
UWRAP_SYMBOL_ENTRY ( getresgid ) ;
# endif
UWRAP_SYMBOL_ENTRY ( getegid ) ;
UWRAP_SYMBOL_ENTRY ( getgroups ) ;
2023-01-16 22:14:03 +01:00
# ifdef HAVE___GETGROUPS_CHK
UWRAP_SYMBOL_ENTRY ( __getgroups_chk ) ;
# endif
2015-01-23 15:28:37 +01:00
UWRAP_SYMBOL_ENTRY ( setgroups ) ;
# ifdef HAVE_SYSCALL
UWRAP_SYMBOL_ENTRY ( syscall ) ;
2009-08-05 10:50:03 +10:00
# endif
2014-01-17 14:43:01 +01:00
} ;
2015-01-23 15:30:03 +01:00
# undef UWRAP_SYMBOL_ENTRY
2023-01-16 22:14:03 +01:00
# define UWRAP_SYMBOL_ENTRY(i) \
union { \
__rtld_default_ # # i f ; \
void * obj ; \
} _rtld_default_ # # i
# ifdef HAVE_SYSCALL
typedef bool ( * __rtld_default_socket_wrapper_syscall_valid ) ( long int sysno ) ;
typedef long int ( * __rtld_default_socket_wrapper_syscall_va ) ( long int sysno ,
va_list va ) ;
# endif
struct uwrap_rtld_default_symbols {
# ifdef HAVE_SYSCALL
UWRAP_SYMBOL_ENTRY ( socket_wrapper_syscall_valid ) ;
UWRAP_SYMBOL_ENTRY ( socket_wrapper_syscall_va ) ;
# else
uint8_t dummy ;
# endif
} ;
# undef UWRAP_SYMBOL_ENTRY
2015-01-23 15:30:03 +01:00
/*****************
* LIBPTHREAD
* * * * * * * * * * * * * * * * */
/* Yeah... I'm pig. I overloading macro here... So what? */
# define UWRAP_SYMBOL_ENTRY(i) \
union { \
__libpthread_ # # i f ; \
void * obj ; \
} _libpthread_ # # i
typedef int ( * __libpthread_pthread_create ) ( pthread_t * thread ,
const pthread_attr_t * attr ,
void * ( * start_routine ) ( void * ) ,
void * arg ) ;
typedef void ( * __libpthread_pthread_exit ) ( void * retval ) ;
struct uwrap_libpthread_symbols {
UWRAP_SYMBOL_ENTRY ( pthread_create ) ;
UWRAP_SYMBOL_ENTRY ( pthread_exit ) ;
} ;
# undef UWRAP_SYMBOL_ENTRY
2009-08-05 10:50:03 +10:00
/*
2014-01-17 14:43:01 +01:00
* We keep the virtualised euid / egid / groups information here
2009-08-05 10:50:03 +10:00
*/
2014-01-17 14:43:01 +01:00
struct uwrap_thread {
2015-01-23 15:30:30 +01:00
bool enabled ;
2014-01-17 14:43:01 +01:00
uid_t ruid ;
uid_t euid ;
uid_t suid ;
gid_t rgid ;
gid_t egid ;
gid_t sgid ;
int ngroups ;
2015-01-23 15:25:16 +01:00
gid_t * groups ;
2014-01-17 14:43:01 +01:00
struct uwrap_thread * next ;
struct uwrap_thread * prev ;
} ;
struct uwrap {
struct {
void * handle ;
2015-01-23 15:28:37 +01:00
struct uwrap_libc_symbols symbols ;
2014-01-17 14:43:01 +01:00
} libc ;
2023-01-16 22:14:03 +01:00
struct {
struct uwrap_rtld_default_symbols symbols ;
} rtld_default ;
2015-01-23 15:30:03 +01:00
struct {
void * handle ;
struct uwrap_libpthread_symbols symbols ;
} libpthread ;
2009-08-05 10:50:03 +10:00
bool initialised ;
2015-01-23 15:25:16 +01:00
2015-01-23 15:16:34 +01:00
/* Real uid and gid of user who run uid wrapper */
2011-10-07 18:58:58 +02:00
uid_t myuid ;
2015-01-23 15:16:34 +01:00
gid_t mygid ;
2014-01-17 14:43:01 +01:00
struct uwrap_thread * ids ;
} ;
static struct uwrap uwrap ;
/* Shortcut to the list item */
static UWRAP_THREAD struct uwrap_thread * uwrap_tls_id ;
/* The mutex or accessing the id */
static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER ;
2023-01-16 22:14:03 +01:00
# define uwrap_init_mutex(m) _uwrap_init_mutex(m, #m)
static int _uwrap_init_mutex ( pthread_mutex_t * m , const char * name )
{
pthread_mutexattr_t ma ;
bool need_destroy = false ;
int ret = 0 ;
# define __CHECK(cmd) \
do { \
ret = cmd ; \
if ( ret ! = 0 ) { \
UWRAP_LOG ( UWRAP_LOG_ERROR , \
" %s: %s - failed %d " , \
name , \
# cmd, \
ret ) ; \
goto done ; \
} \
} while ( 0 )
* m = ( pthread_mutex_t ) PTHREAD_MUTEX_INITIALIZER ;
__CHECK ( pthread_mutexattr_init ( & ma ) ) ;
need_destroy = true ;
__CHECK ( pthread_mutexattr_settype ( & ma , PTHREAD_MUTEX_ERRORCHECK ) ) ;
__CHECK ( pthread_mutex_init ( m , & ma ) ) ;
done :
if ( need_destroy ) {
pthread_mutexattr_destroy ( & ma ) ;
}
return ret ;
}
# define uwrap_mutex_lock(m) _uwrap_mutex_lock(m, #m, __func__, __LINE__)
static void _uwrap_mutex_lock ( pthread_mutex_t * mutex ,
const char * name ,
const char * caller ,
unsigned line )
{
int ret ;
2015-01-23 15:12:02 +01:00
2023-01-16 22:14:03 +01:00
ret = pthread_mutex_lock ( mutex ) ;
if ( ret ! = 0 ) {
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" PID(%d):PPID(%d): %s(%u): Couldn't lock pthread "
" mutex(%s) - %s " ,
getpid ( ) ,
getppid ( ) ,
caller ,
line ,
name ,
strerror ( ret ) ) ;
abort ( ) ;
}
}
# define uwrap_mutex_unlock(m) _uwrap_mutex_unlock(m, #m, __func__, __LINE__)
static void _uwrap_mutex_unlock ( pthread_mutex_t * mutex ,
const char * name ,
const char * caller ,
unsigned line )
{
int ret ;
ret = pthread_mutex_unlock ( mutex ) ;
if ( ret ! = 0 ) {
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" PID(%d):PPID(%d): %s(%u): Couldn't unlock pthread "
" mutex(%s) - %s " ,
getpid ( ) ,
getppid ( ) ,
caller ,
line ,
name ,
strerror ( ret ) ) ;
abort ( ) ;
}
}
# define UWRAP_LOCK(m) \
do { \
uwrap_mutex_lock ( & ( m # # _mutex ) ) ; \
} while ( 0 )
# define UWRAP_UNLOCK(m) \
do { \
uwrap_mutex_unlock ( & ( m # # _mutex ) ) ; \
} while ( 0 )
/* Add new global locks here please */
# define UWRAP_REINIT_ALL \
do { \
int ret ; \
ret = uwrap_init_mutex ( & uwrap_id_mutex ) ; \
if ( ret ! = 0 ) \
exit ( - 1 ) ; \
} while ( 0 )
/* Add new global locks here please */
# define UWRAP_LOCK_ALL \
do { \
UWRAP_LOCK ( uwrap_id ) ; \
} while ( 0 )
# define UWRAP_UNLOCK_ALL \
do { \
UWRAP_UNLOCK ( uwrap_id ) ; \
} while ( 0 )
2015-01-23 15:30:03 +01:00
2014-01-17 14:43:01 +01:00
/*********************************************************
* UWRAP PROTOTYPES
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool uid_wrapper_enabled ( void ) ;
2023-01-16 22:14:03 +01:00
# if ! defined(HAVE_CONSTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_INIT)
/* xlC and other oldschool compilers support (only) this */
# pragma init (uwrap_constructor)
# endif
2015-01-23 15:10:02 +01:00
void uwrap_constructor ( void ) CONSTRUCTOR_ATTRIBUTE ;
2023-01-16 22:14:03 +01:00
# if ! defined(HAVE_DESTRUCTOR_ATTRIBUTE) && defined(HAVE_PRAGMA_FINI)
# pragma fini (uwrap_destructor)
# endif
2014-01-17 14:43:01 +01:00
void uwrap_destructor ( void ) DESTRUCTOR_ATTRIBUTE ;
/*********************************************************
* UWRAP LIBC LOADER FUNCTIONS
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
enum uwrap_lib {
UWRAP_LIBC ,
2015-01-23 15:30:03 +01:00
UWRAP_LIBPTHREAD ,
2014-01-17 14:43:01 +01:00
} ;
static void * uwrap_load_lib_handle ( enum uwrap_lib lib )
{
int flags = RTLD_LAZY ;
void * handle = NULL ;
int i ;
# ifdef RTLD_DEEPBIND
2019-07-15 10:32:49 +02:00
const char * env_preload = getenv ( " LD_PRELOAD " ) ;
const char * env_deepbind = getenv ( " UID_WRAPPER_DISABLE_DEEPBIND " ) ;
bool enable_deepbind = true ;
/* Don't do a deepbind if we run with libasan */
if ( env_preload ! = NULL & & strlen ( env_preload ) < 1024 ) {
const char * p = strstr ( env_preload , " libasan.so " ) ;
if ( p ! = NULL ) {
enable_deepbind = false ;
}
}
if ( env_deepbind ! = NULL & & strlen ( env_deepbind ) > = 1 ) {
enable_deepbind = false ;
}
if ( enable_deepbind ) {
flags | = RTLD_DEEPBIND ;
}
2014-01-17 14:43:01 +01:00
# endif
switch ( lib ) {
case UWRAP_LIBC :
handle = uwrap . libc . handle ;
2024-06-13 07:41:41 +02:00
# ifdef LIBC_SO
if ( handle = = NULL ) {
handle = dlopen ( LIBC_SO , flags ) ;
uwrap . libc . handle = handle ;
}
# endif
2014-01-17 14:43:01 +01:00
if ( handle = = NULL ) {
2015-01-23 13:59:14 +01:00
for ( i = 10 ; i > = 0 ; i - - ) {
2014-01-17 14:43:01 +01:00
char soname [ 256 ] = { 0 } ;
snprintf ( soname , sizeof ( soname ) , " libc.so.%d " , i ) ;
handle = dlopen ( soname , flags ) ;
2015-01-23 13:59:14 +01:00
if ( handle ! = NULL ) {
break ;
}
2017-07-13 08:57:13 +02:00
/* glibc on Alpha and IA64 is libc.so.6.1 */
snprintf ( soname , sizeof ( soname ) , " libc.so.%d.1 " , i ) ;
handle = dlopen ( soname , flags ) ;
if ( handle ! = NULL ) {
break ;
}
2014-01-17 14:43:01 +01:00
}
uwrap . libc . handle = handle ;
}
break ;
2015-01-23 15:30:03 +01:00
case UWRAP_LIBPTHREAD :
handle = uwrap . libpthread . handle ;
if ( handle = = NULL ) {
2023-01-16 22:14:03 +01:00
# ifdef RTLD_NEXT
/*
* Because thread sanatizer also overloads
* pthread_create ( ) and pthread_exit ( ) we need use
* RTLD_NEXT instead of libpthread . so .0
*/
handle = uwrap . libpthread . handle = RTLD_NEXT ;
# else
2015-01-23 15:30:03 +01:00
handle = dlopen ( " libpthread.so.0 " , flags ) ;
2023-01-16 22:14:03 +01:00
# endif
2015-01-23 15:30:03 +01:00
if ( handle ! = NULL ) {
break ;
}
}
break ;
2014-01-17 14:43:01 +01:00
}
if ( handle = = NULL ) {
2014-07-31 10:13:40 +02:00
# ifdef RTLD_NEXT
2023-01-16 22:14:03 +01:00
switch ( lib ) {
case UWRAP_LIBC :
handle = uwrap . libc . handle = RTLD_NEXT ;
break ;
case UWRAP_LIBPTHREAD :
handle = uwrap . libpthread . handle = RTLD_NEXT ;
break ;
}
2014-07-31 10:13:40 +02:00
# else
2014-01-17 14:43:01 +01:00
fprintf ( stderr ,
" Failed to dlopen library: %s \n " ,
dlerror ( ) ) ;
exit ( - 1 ) ;
2014-07-31 10:13:40 +02:00
# endif
2014-01-17 14:43:01 +01:00
}
return handle ;
}
2015-01-23 15:28:37 +01:00
static void * _uwrap_bind_symbol ( enum uwrap_lib lib , const char * fn_name )
2014-01-17 14:43:01 +01:00
{
void * handle ;
void * func ;
handle = uwrap_load_lib_handle ( lib ) ;
func = dlsym ( handle , fn_name ) ;
if ( func = = NULL ) {
fprintf ( stderr ,
" Failed to find %s: %s \n " ,
fn_name , dlerror ( ) ) ;
exit ( - 1 ) ;
}
return func ;
}
2015-01-23 15:30:03 +01:00
# define uwrap_bind_symbol_libc(sym_name) \
2015-01-23 15:28:37 +01:00
if ( uwrap . libc . symbols . _libc_ # # sym_name . obj = = NULL ) { \
uwrap . libc . symbols . _libc_ # # sym_name . obj = \
2015-01-23 15:30:03 +01:00
_uwrap_bind_symbol ( UWRAP_LIBC , # sym_name ) ; \
2023-01-16 22:14:03 +01:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:30:03 +01:00
# define uwrap_bind_symbol_libpthread(sym_name) \
if ( uwrap . libpthread . symbols . _libpthread_ # # sym_name . obj = = NULL ) { \
uwrap . libpthread . symbols . _libpthread_ # # sym_name . obj = \
_uwrap_bind_symbol ( UWRAP_LIBPTHREAD , # sym_name ) ; \
2023-01-16 22:14:03 +01:00
}
# define uwrap_bind_symbol_rtld_default_optional(sym_name) \
if ( uwrap . rtld_default . symbols . _rtld_default_ # # sym_name . obj = = NULL ) { \
uwrap . rtld_default . symbols . _rtld_default_ # # sym_name . obj = \
dlsym ( RTLD_DEFAULT , # sym_name ) ; \
}
2024-06-13 07:41:41 +02:00
/* JEMALLOC: This tells uid_wrapper if it should handle syscall() */
static bool uwrap_handle_syscall ;
2023-01-16 22:14:03 +01:00
/* DO NOT call this function during library initialization! */
static void __uwrap_bind_symbol_all_once ( void )
{
uwrap_bind_symbol_libc ( setuid ) ;
uwrap_bind_symbol_libc ( getuid ) ;
# ifdef HAVE_SETEUID
uwrap_bind_symbol_libc ( seteuid ) ;
# endif
# ifdef HAVE_SETREUID
uwrap_bind_symbol_libc ( setreuid ) ;
# endif
# ifdef HAVE_SETRESUID
uwrap_bind_symbol_libc ( setresuid ) ;
# endif
# ifdef HAVE_GETRESUID
uwrap_bind_symbol_libc ( getresuid ) ;
# endif
uwrap_bind_symbol_libc ( geteuid ) ;
uwrap_bind_symbol_libc ( setgid ) ;
uwrap_bind_symbol_libc ( getgid ) ;
# ifdef HAVE_SETEGID
uwrap_bind_symbol_libc ( setegid ) ;
# endif
# ifdef HAVE_SETREGID
uwrap_bind_symbol_libc ( setregid ) ;
# endif
# ifdef HAVE_SETRESGID
uwrap_bind_symbol_libc ( setresgid ) ;
# endif
# ifdef HAVE_GETRESGID
uwrap_bind_symbol_libc ( setresgid ) ;
# endif
uwrap_bind_symbol_libc ( getegid ) ;
uwrap_bind_symbol_libc ( getgroups ) ;
uwrap_bind_symbol_libc ( setgroups ) ;
# ifdef HAVE_SYSCALL
uwrap_bind_symbol_libc ( syscall ) ;
uwrap_bind_symbol_rtld_default_optional ( socket_wrapper_syscall_valid ) ;
uwrap_bind_symbol_rtld_default_optional ( socket_wrapper_syscall_va ) ;
# endif
uwrap_bind_symbol_libpthread ( pthread_create ) ;
uwrap_bind_symbol_libpthread ( pthread_exit ) ;
2024-06-13 07:41:41 +02:00
uwrap_handle_syscall = true ;
2023-01-16 22:14:03 +01:00
}
static void uwrap_bind_symbol_all ( void )
{
static pthread_once_t all_symbol_binding_once = PTHREAD_ONCE_INIT ;
pthread_once ( & all_symbol_binding_once , __uwrap_bind_symbol_all_once ) ;
}
2015-01-23 15:30:03 +01:00
2014-01-17 14:43:01 +01:00
/*
* IMPORTANT
*
* Functions expeciall from libc need to be loaded individually , you can ' t load
* all at once or gdb will segfault at startup . The same applies to valgrind and
* has probably something todo with with the linker .
* So we need load each function at the point it is called the first time .
*/
static int libc_setuid ( uid_t uid )
{
2023-01-16 22:14:03 +01:00
uwrap_bind_symbol_all ( ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_setuid . f ( uid ) ;
2014-01-17 14:43:01 +01:00
}
static uid_t libc_getuid ( void )
{
2023-01-16 22:14:03 +01:00
uwrap_bind_symbol_all ( ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_getuid . f ( ) ;
2014-01-17 14:43:01 +01:00
}
# ifdef HAVE_SETEUID
static int libc_seteuid ( uid_t euid )
{
2023-01-16 22:14:03 +01:00
uwrap_bind_symbol_all ( ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_seteuid . f ( euid ) ;
2014-01-17 14:43:01 +01:00
}
# endif
# ifdef HAVE_SETREUID
static int libc_setreuid ( uid_t ruid , uid_t euid )
{
2023-01-16 22:14:03 +01:00
uwrap_bind_symbol_all ( ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_setreuid . f ( ruid , euid ) ;
2014-01-17 14:43:01 +01:00
}
# endif
# ifdef HAVE_SETRESUID
static int libc_setresuid ( uid_t ruid , uid_t euid , uid_t suid )
{
2023-01-16 22:14:03 +01:00
uwrap_bind_symbol_all ( ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_setresuid . f ( ruid , euid , suid ) ;
2014-01-17 14:43:01 +01:00
}
# endif
2015-01-23 15:27:25 +01:00
# ifdef HAVE_GETRESUID
static int libc_getresuid ( uid_t * ruid , uid_t * euid , uid_t * suid )
{
2023-01-16 22:14:03 +01:00
uwrap_bind_symbol_all ( ) ;
2015-01-23 15:27:25 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_getresuid . f ( ruid , euid , suid ) ;
2015-01-23 15:27:25 +01:00
}
# endif
2014-01-17 14:43:01 +01:00
static uid_t libc_geteuid ( void )
{
2023-01-16 22:14:03 +01:00
uwrap_bind_symbol_all ( ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_geteuid . f ( ) ;
2014-01-17 14:43:01 +01:00
}
static int libc_setgid ( gid_t gid )
{
2023-01-16 22:14:03 +01:00
uwrap_bind_symbol_all ( ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_setgid . f ( gid ) ;
2014-01-17 14:43:01 +01:00
}
static gid_t libc_getgid ( void )
{
2023-01-16 22:14:03 +01:00
uwrap_bind_symbol_all ( ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_getgid . f ( ) ;
2014-01-17 14:43:01 +01:00
}
# ifdef HAVE_SETEGID
static int libc_setegid ( gid_t egid )
{
2023-01-16 22:14:03 +01:00
uwrap_bind_symbol_all ( ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_setegid . f ( egid ) ;
2014-01-17 14:43:01 +01:00
}
# endif
# ifdef HAVE_SETREGID
static int libc_setregid ( gid_t rgid , gid_t egid )
{
2023-01-16 22:14:03 +01:00
uwrap_bind_symbol_all ( ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_setregid . f ( rgid , egid ) ;
2014-01-17 14:43:01 +01:00
}
# endif
# ifdef HAVE_SETRESGID
static int libc_setresgid ( gid_t rgid , gid_t egid , gid_t sgid )
{
2023-01-16 22:14:03 +01:00
uwrap_bind_symbol_all ( ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_setresgid . f ( rgid , egid , sgid ) ;
2014-01-17 14:43:01 +01:00
}
# endif
2015-01-23 15:27:25 +01:00
# ifdef HAVE_GETRESGID
static int libc_getresgid ( gid_t * rgid , gid_t * egid , gid_t * sgid )
{
2023-01-16 22:14:03 +01:00
uwrap_bind_symbol_all ( ) ;
2015-01-23 15:27:25 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_getresgid . f ( rgid , egid , sgid ) ;
2015-01-23 15:27:25 +01:00
}
# endif
2014-01-17 14:43:01 +01:00
static gid_t libc_getegid ( void )
{
2023-01-16 22:14:03 +01:00
uwrap_bind_symbol_all ( ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_getegid . f ( ) ;
2014-01-17 14:43:01 +01:00
}
static int libc_getgroups ( int size , gid_t list [ ] )
{
2023-01-16 22:14:03 +01:00
uwrap_bind_symbol_all ( ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_getgroups . f ( size , list ) ;
2014-01-17 14:43:01 +01:00
}
2023-01-16 22:14:03 +01:00
# ifdef HAVE___GETGROUPS_CHK
static int libc___getgroups_chk ( int size , gid_t list [ ] , size_t listlen )
{
uwrap_bind_symbol_libc ( __getgroups_chk ) ;
return uwrap . libc . symbols . _libc___getgroups_chk . f ( size ,
list ,
listlen ) ;
}
# endif /* HAVE___GETGROUPS_CHK */
2014-01-17 14:43:01 +01:00
static int libc_setgroups ( size_t size , const gid_t * list )
{
2023-01-16 22:14:03 +01:00
uwrap_bind_symbol_all ( ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:28:37 +01:00
return uwrap . libc . symbols . _libc_setgroups . f ( size , list ) ;
2014-01-17 14:43:01 +01:00
}
# ifdef HAVE_SYSCALL
2015-01-23 15:22:18 +01:00
DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
2014-01-17 14:43:01 +01:00
static long int libc_vsyscall ( long int sysno , va_list va )
{
long int args [ 8 ] ;
long int rc ;
int i ;
2024-06-13 07:41:41 +02:00
/*
* JEMALLOC :
*
* This is a workaround to prevent a deadlock in jemalloc calling
* malloc_init ( ) twice . The first allocation call will trigger a
* malloc_init ( ) of jemalloc . The functions calls syscall ( SYS_open , . . . )
* so it goes to socket or uid wrapper . In this code path we need to
* avoid any allocation calls . This will prevent the deadlock .
*
* We also need to avoid dlopen ( ) as that would trigger the recursion
* into malloc_init ( ) , so we use dlsym ( RTLD_NEXT ) , until we reached
* swrap_constructor ( ) or any real socket call at that time
* swrap_bind_symbol_all ( ) will replace the function pointer again after
* dlopen of libc .
*/
if ( uwrap_handle_syscall ) {
uwrap_bind_symbol_all ( ) ;
} else if ( uwrap . libc . symbols . _libc_syscall . obj = = NULL ) {
uwrap . libc . symbols . _libc_syscall . obj = dlsym ( RTLD_NEXT ,
" syscall " ) ;
}
2014-01-17 14:43:01 +01:00
for ( i = 0 ; i < 8 ; i + + ) {
args [ i ] = va_arg ( va , long int ) ;
}
2015-01-23 15:28:37 +01:00
rc = uwrap . libc . symbols . _libc_syscall . f ( sysno ,
2014-01-17 14:43:01 +01:00
args [ 0 ] ,
args [ 1 ] ,
args [ 2 ] ,
args [ 3 ] ,
args [ 4 ] ,
args [ 5 ] ,
args [ 6 ] ,
args [ 7 ] ) ;
return rc ;
}
2023-01-16 22:14:03 +01:00
static bool uwrap_swrap_syscall_valid ( long int sysno )
{
uwrap_bind_symbol_all ( ) ;
if ( uwrap . rtld_default . symbols . _rtld_default_socket_wrapper_syscall_valid . f = = NULL ) {
return false ;
}
return uwrap . rtld_default . symbols . _rtld_default_socket_wrapper_syscall_valid . f (
sysno ) ;
}
DO_NOT_SANITIZE_ADDRESS_ATTRIBUTE
static long int uwrap_swrap_syscall_va ( long int sysno , va_list va )
{
uwrap_bind_symbol_all ( ) ;
if ( uwrap . rtld_default . symbols . _rtld_default_socket_wrapper_syscall_va . f = = NULL ) {
/*
* Fallback to libc , if socket_wrapper_vsyscall is not
* available .
*/
return libc_vsyscall ( sysno , va ) ;
}
return uwrap . rtld_default . symbols . _rtld_default_socket_wrapper_syscall_va . f (
sysno ,
va ) ;
}
2014-01-17 14:43:01 +01:00
# endif
2023-01-16 22:14:03 +01:00
static int libpthread_pthread_create ( pthread_t * thread ,
const pthread_attr_t * attr ,
void * ( * start_routine ) ( void * ) ,
void * arg )
{
uwrap_bind_symbol_all ( ) ;
return uwrap . libpthread . symbols . _libpthread_pthread_create . f ( thread ,
attr ,
start_routine ,
arg ) ;
}
2015-01-23 15:30:03 +01:00
/*
* This part is " optimistic " .
* Thread can ends without pthread_exit call .
*/
static void libpthread_pthread_exit ( void * retval )
{
2023-01-16 22:14:03 +01:00
uwrap_bind_symbol_all ( ) ;
2015-01-23 15:30:03 +01:00
uwrap . libpthread . symbols . _libpthread_pthread_exit . f ( retval ) ;
}
static void uwrap_pthread_exit ( void * retval )
{
2015-01-23 15:30:30 +01:00
struct uwrap_thread * id = uwrap_tls_id ;
UWRAP_LOG ( UWRAP_LOG_DEBUG , " Cleanup thread " ) ;
UWRAP_LOCK ( uwrap_id ) ;
if ( id = = NULL ) {
UWRAP_UNLOCK ( uwrap_id ) ;
libpthread_pthread_exit ( retval ) ;
2015-01-23 15:31:17 +01:00
return ;
2015-01-23 15:30:30 +01:00
}
UWRAP_DLIST_REMOVE ( uwrap . ids , id ) ;
SAFE_FREE ( id - > groups ) ;
SAFE_FREE ( id ) ;
uwrap_tls_id = NULL ;
UWRAP_UNLOCK ( uwrap_id ) ;
2015-01-23 15:30:03 +01:00
libpthread_pthread_exit ( retval ) ;
}
void pthread_exit ( void * retval )
{
if ( ! uid_wrapper_enabled ( ) ) {
libpthread_pthread_exit ( retval ) ;
} ;
uwrap_pthread_exit ( retval ) ;
/* Calm down gcc warning. */
exit ( 666 ) ;
}
2015-01-23 15:30:30 +01:00
struct uwrap_pthread_create_args {
struct uwrap_thread * id ;
void * ( * start_routine ) ( void * ) ;
void * arg ;
} ;
static void * uwrap_pthread_create_start ( void * _a )
{
struct uwrap_pthread_create_args * a =
( struct uwrap_pthread_create_args * ) _a ;
void * ( * start_routine ) ( void * ) = a - > start_routine ;
void * arg = a - > arg ;
struct uwrap_thread * id = a - > id ;
SAFE_FREE ( a ) ;
uwrap_tls_id = id ;
return start_routine ( arg ) ;
}
2015-01-23 15:30:03 +01:00
static int uwrap_pthread_create ( pthread_t * thread ,
const pthread_attr_t * attr ,
void * ( * start_routine ) ( void * ) ,
void * arg )
{
2015-01-23 15:30:30 +01:00
struct uwrap_pthread_create_args * args ;
struct uwrap_thread * src_id = uwrap_tls_id ;
int ret ;
args = malloc ( sizeof ( struct uwrap_pthread_create_args ) ) ;
if ( args = = NULL ) {
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" uwrap_pthread_create: Unable to allocate memory " ) ;
errno = ENOMEM ;
return - 1 ;
}
args - > start_routine = start_routine ;
args - > arg = arg ;
args - > id = calloc ( 1 , sizeof ( struct uwrap_thread ) ) ;
if ( args - > id = = NULL ) {
SAFE_FREE ( args ) ;
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" uwrap_pthread_create: Unable to allocate memory " ) ;
errno = ENOMEM ;
return - 1 ;
}
UWRAP_LOCK ( uwrap_id ) ;
2019-07-15 10:32:49 +02:00
args - > id - > groups = calloc ( src_id - > ngroups , sizeof ( gid_t ) ) ;
2015-01-23 15:30:30 +01:00
if ( args - > id - > groups = = NULL ) {
UWRAP_UNLOCK ( uwrap_id ) ;
SAFE_FREE ( args - > id ) ;
SAFE_FREE ( args ) ;
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" uwrap_pthread_create: Unable to allocate memory again " ) ;
errno = ENOMEM ;
return - 1 ;
}
args - > id - > ruid = src_id - > ruid ;
args - > id - > euid = src_id - > euid ;
args - > id - > suid = src_id - > suid ;
args - > id - > rgid = src_id - > rgid ;
args - > id - > egid = src_id - > egid ;
args - > id - > sgid = src_id - > sgid ;
args - > id - > enabled = src_id - > enabled ;
args - > id - > ngroups = src_id - > ngroups ;
if ( src_id - > groups ! = NULL ) {
memcpy ( args - > id - > groups , src_id - > groups ,
sizeof ( gid_t ) * src_id - > ngroups ) ;
} else {
SAFE_FREE ( args - > id - > groups ) ;
}
UWRAP_DLIST_ADD ( uwrap . ids , args - > id ) ;
UWRAP_UNLOCK ( uwrap_id ) ;
ret = libpthread_pthread_create ( thread , attr ,
uwrap_pthread_create_start ,
args ) ;
if ( ret ! = 0 ) {
return ret ;
}
return ret ;
2015-01-23 15:30:03 +01:00
}
int pthread_create ( pthread_t * thread ,
const pthread_attr_t * attr ,
void * ( * start_routine ) ( void * ) ,
void * arg )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libpthread_pthread_create ( thread ,
attr ,
start_routine ,
arg ) ;
} ;
return uwrap_pthread_create ( thread ,
attr ,
start_routine ,
arg ) ;
}
2014-01-17 14:43:01 +01:00
/*********************************************************
* UWRAP ID HANDLING
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-07-13 08:57:13 +02:00
# define GROUP_STRING_SIZE 16384
# define GROUP_MAX_COUNT (GROUP_STRING_SIZE / (10 + 1))
/**
* This function exports all the IDs of the current user so if
* we fork and then exec we can setup uid_wrapper in the new process
* with those IDs .
*/
static void uwrap_export_ids ( struct uwrap_thread * id )
{
char groups_str [ GROUP_STRING_SIZE ] = { 0 } ;
size_t groups_str_size = sizeof ( groups_str ) ;
char unsigned_str [ 16 ] = { 0 } ; /* We need 10 + 1 (+ 1) */
int i ;
/* UIDS */
snprintf ( unsigned_str , sizeof ( unsigned_str ) , " %u " , id - > ruid ) ;
setenv ( " UID_WRAPPER_INITIAL_RUID " , unsigned_str , 1 ) ;
snprintf ( unsigned_str , sizeof ( unsigned_str ) , " %u " , id - > euid ) ;
setenv ( " UID_WRAPPER_INITIAL_EUID " , unsigned_str , 1 ) ;
snprintf ( unsigned_str , sizeof ( unsigned_str ) , " %u " , id - > suid ) ;
setenv ( " UID_WRAPPER_INITIAL_SUID " , unsigned_str , 1 ) ;
/* GIDS */
snprintf ( unsigned_str , sizeof ( unsigned_str ) , " %u " , id - > rgid ) ;
setenv ( " UID_WRAPPER_INITIAL_RGID " , unsigned_str , 1 ) ;
snprintf ( unsigned_str , sizeof ( unsigned_str ) , " %u " , id - > egid ) ;
setenv ( " UID_WRAPPER_INITIAL_EGID " , unsigned_str , 1 ) ;
snprintf ( unsigned_str , sizeof ( unsigned_str ) , " %u " , id - > sgid ) ;
setenv ( " UID_WRAPPER_INITIAL_SGID " , unsigned_str , 1 ) ;
if ( id - > ngroups > GROUP_MAX_COUNT ) {
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" ERROR: Number of groups (%u) exceeds maximum value "
" uid_wrapper can handle (%u). " ,
id - > ngroups ,
GROUP_MAX_COUNT ) ;
exit ( - 1 ) ;
}
/* GROUPS */
for ( i = 0 ; i < id - > ngroups ; i + + ) {
size_t groups_str_len = strlen ( groups_str ) ;
size_t groups_str_avail = groups_str_size - groups_str_len - 1 ;
int len ;
len = snprintf ( unsigned_str , sizeof ( unsigned_str ) , " ,%u " , id - > groups [ i ] ) ;
if ( len < = 1 ) {
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" snprintf failed for groups[%d]=%u " ,
i ,
id - > groups [ i ] ) ;
break ;
}
if ( ( ( size_t ) len ) > = groups_str_avail ) {
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" groups env string is to small for %d groups " ,
i ) ;
break ;
}
len = snprintf ( groups_str + groups_str_len ,
groups_str_size - groups_str_len ,
" %s " ,
i = = 0 ? unsigned_str + 1 : unsigned_str ) ;
if ( len < 1 ) {
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" snprintf failed to create groups string at groups[%d]=%u " ,
i ,
id - > groups [ i ] ) ;
break ;
}
}
if ( id - > ngroups = = i ) {
setenv ( " UID_WRAPPER_INITIAL_GROUPS " , groups_str , 1 ) ;
snprintf ( unsigned_str , sizeof ( unsigned_str ) , " %u " , id - > ngroups ) ;
setenv ( " UID_WRAPPER_INITIAL_GROUPS_COUNT " , unsigned_str , 1 ) ;
}
}
2015-01-23 15:30:30 +01:00
static void uwrap_thread_prepare ( void )
2014-01-17 14:43:01 +01:00
{
struct uwrap_thread * id = uwrap_tls_id ;
2023-01-16 22:14:03 +01:00
/*
* We bind all symbols to avoid deadlocks of the fork is interrupted by
* a signal handler using a symbol of this library .
*/
uwrap_bind_symbol_all ( ) ;
2017-07-13 08:57:13 +02:00
UWRAP_LOCK_ALL ;
2015-10-30 13:37:11 +01:00
/* uid_wrapper is loaded but not enabled */
if ( id = = NULL ) {
return ;
}
2014-01-17 14:43:01 +01:00
/*
* What happens if another atfork prepare functions calls a uwrap
* function ? So disable it in case another atfork prepare function
2015-01-23 15:30:30 +01:00
* calls a ( s ) uid function . We disable uid_wrapper only for thread
* ( process ) which called fork .
2014-01-17 14:43:01 +01:00
*/
2015-01-23 15:30:30 +01:00
id - > enabled = false ;
2014-01-17 14:43:01 +01:00
}
static void uwrap_thread_parent ( void )
{
2015-01-23 15:30:30 +01:00
struct uwrap_thread * id = uwrap_tls_id ;
2015-10-30 13:37:11 +01:00
/* uid_wrapper is loaded but not enabled */
if ( id = = NULL ) {
2017-07-13 08:57:13 +02:00
UWRAP_UNLOCK_ALL ;
2015-10-30 13:37:11 +01:00
return ;
}
2015-01-23 15:30:30 +01:00
id - > enabled = true ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:29:35 +01:00
UWRAP_UNLOCK_ALL ;
2014-01-17 14:43:01 +01:00
}
static void uwrap_thread_child ( void )
{
2015-01-23 15:30:30 +01:00
struct uwrap_thread * id = uwrap_tls_id ;
struct uwrap_thread * u = uwrap . ids ;
2023-01-16 22:14:03 +01:00
UWRAP_REINIT_ALL ;
2015-10-30 13:37:11 +01:00
/* uid_wrapper is loaded but not enabled */
if ( id = = NULL ) {
return ;
}
2015-01-23 15:30:30 +01:00
/*
* " Garbage collector " - Inspired by DESTRUCTOR .
* All threads ( except one which called fork ( ) ) are dead now . . Dave
* That ' s what posix said . . .
*/
while ( u ! = NULL ) {
if ( u = = id ) {
/* Skip this item. */
u = uwrap . ids - > next ;
continue ;
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:30:30 +01:00
UWRAP_DLIST_REMOVE ( uwrap . ids , u ) ;
2015-01-23 15:24:39 +01:00
2015-01-23 15:30:30 +01:00
SAFE_FREE ( u - > groups ) ;
SAFE_FREE ( u ) ;
u = uwrap . ids ;
}
2017-07-13 08:57:13 +02:00
uwrap_export_ids ( id ) ;
2015-01-23 15:30:30 +01:00
id - > enabled = true ;
2014-01-17 14:43:01 +01:00
}
2009-08-05 10:50:03 +10:00
2019-07-15 10:32:49 +02:00
static unsigned long uwrap_get_xid_from_env ( const char * envname )
{
unsigned long xid ;
const char * env = NULL ;
char * endp = NULL ;
env = getenv ( envname ) ;
if ( env = = NULL ) {
return ULONG_MAX ;
}
if ( env [ 0 ] = = ' \0 ' ) {
unsetenv ( envname ) ;
return ULONG_MAX ;
}
xid = strtoul ( env , & endp , 10 ) ;
unsetenv ( envname ) ;
if ( env = = endp ) {
return ULONG_MAX ;
}
return xid ;
}
2017-07-13 08:57:13 +02:00
/*
* This initializes uid_wrapper with the IDs exported to the environment . Those
* are normally set after we forked and executed .
*/
static void uwrap_init_env ( struct uwrap_thread * id )
{
const char * env ;
int ngroups = 0 ;
2019-07-15 10:32:49 +02:00
unsigned long xid ;
2017-07-13 08:57:13 +02:00
2019-07-15 10:32:49 +02:00
/* UIDs */
xid = uwrap_get_xid_from_env ( " UID_WRAPPER_INITIAL_RUID " ) ;
if ( xid ! = ULONG_MAX ) {
id - > ruid = ( uid_t ) xid ;
2017-07-13 08:57:13 +02:00
}
2019-07-15 10:32:49 +02:00
xid = uwrap_get_xid_from_env ( " UID_WRAPPER_INITIAL_EUID " ) ;
if ( xid ! = ULONG_MAX ) {
id - > euid = ( uid_t ) xid ;
2017-07-13 08:57:13 +02:00
}
2019-07-15 10:32:49 +02:00
xid = uwrap_get_xid_from_env ( " UID_WRAPPER_INITIAL_SUID " ) ;
if ( xid ! = ULONG_MAX ) {
id - > suid = ( uid_t ) xid ;
2017-07-13 08:57:13 +02:00
}
2019-07-15 10:32:49 +02:00
/* GIDs */
xid = uwrap_get_xid_from_env ( " UID_WRAPPER_INITIAL_RGID " ) ;
if ( xid ! = ULONG_MAX ) {
id - > rgid = ( gid_t ) xid ;
2017-07-13 08:57:13 +02:00
}
2019-07-15 10:32:49 +02:00
xid = uwrap_get_xid_from_env ( " UID_WRAPPER_INITIAL_EGID " ) ;
if ( xid ! = ULONG_MAX ) {
id - > egid = ( gid_t ) xid ;
2017-07-13 08:57:13 +02:00
}
2019-07-15 10:32:49 +02:00
xid = uwrap_get_xid_from_env ( " UID_WRAPPER_INITIAL_SGID " ) ;
if ( xid ! = ULONG_MAX ) {
id - > sgid = ( gid_t ) xid ;
2017-07-13 08:57:13 +02:00
}
2017-08-03 10:52:59 +02:00
env = getenv ( " UID_WRAPPER_INITIAL_GROUPS_COUNT " ) ;
if ( env ! = NULL & & env [ 0 ] ! = ' \0 ' ) {
char * endp = NULL ;
long n ;
n = strtol ( env , & endp , 10 ) ;
if ( env = = endp ) {
ngroups = 0 ;
} else if ( n > 0 & & n < GROUP_MAX_COUNT ) {
ngroups = ( int ) n ;
}
unsetenv ( " UID_WRAPPER_INITIAL_GROUPS_COUNT " ) ;
}
if ( ngroups > 0 ) {
2017-07-13 08:57:13 +02:00
int i = 0 ;
id - > ngroups = 0 ;
free ( id - > groups ) ;
2017-07-27 14:09:20 +02:00
id - > groups = calloc ( ngroups , sizeof ( gid_t ) ) ;
2017-07-13 08:57:13 +02:00
if ( id - > groups = = NULL ) {
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" Unable to allocate memory " ) ;
exit ( - 1 ) ;
}
env = getenv ( " UID_WRAPPER_INITIAL_GROUPS " ) ;
if ( env ! = NULL & & env [ 0 ] ! = ' \0 ' ) {
char * groups_str = NULL ;
char * saveptr = NULL ;
const char * p = NULL ;
groups_str = strdup ( env ) ;
if ( groups_str = = NULL ) {
exit ( - 1 ) ;
}
p = strtok_r ( groups_str , " , " , & saveptr ) ;
while ( p ! = NULL ) {
id - > groups [ i ] = strtol ( p , ( char * * ) NULL , 10 ) ;
i + + ;
p = strtok_r ( NULL , " , " , & saveptr ) ;
}
SAFE_FREE ( groups_str ) ;
}
if ( i ! = ngroups ) {
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" ERROR: The number of groups (%u) passed, "
" does not match the number of groups (%u) "
" we parsed. " ,
ngroups ,
i ) ;
exit ( - 1 ) ;
}
2024-06-13 07:41:41 +02:00
UWRAP_LOG ( UWRAP_LOG_DEBUG , " Initialize groups with %s " , env ) ;
2017-07-13 08:57:13 +02:00
id - > ngroups = ngroups ;
}
}
2009-08-05 10:50:03 +10:00
static void uwrap_init ( void )
{
2015-01-23 15:15:42 +01:00
const char * env ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:12:43 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2015-01-23 15:28:37 +01:00
2014-01-17 14:43:01 +01:00
if ( uwrap . initialised ) {
struct uwrap_thread * id = uwrap_tls_id ;
2015-01-23 15:30:30 +01:00
if ( uwrap . ids = = NULL ) {
2015-01-23 15:12:43 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
return ;
}
if ( id = = NULL ) {
2015-01-23 15:30:30 +01:00
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" Invalid id for thread " ) ;
exit ( - 1 ) ;
2014-01-17 14:43:01 +01:00
}
2015-01-23 15:30:30 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
return ;
}
2014-07-31 10:19:58 +02:00
UWRAP_LOG ( UWRAP_LOG_DEBUG , " Initialize uid_wrapper " ) ;
2009-08-05 10:50:03 +10:00
uwrap . initialised = true ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:15:42 +01:00
env = getenv ( " UID_WRAPPER " ) ;
2014-01-17 14:43:01 +01:00
if ( env ! = NULL & & env [ 0 ] = = ' 1 ' ) {
const char * root = getenv ( " UID_WRAPPER_ROOT " ) ;
2015-01-23 15:30:30 +01:00
struct uwrap_thread * id ;
id = calloc ( 1 , sizeof ( struct uwrap_thread ) ) ;
if ( id = = NULL ) {
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" Unable to allocate memory for main id " ) ;
exit ( - 1 ) ;
}
UWRAP_DLIST_ADD ( uwrap . ids , id ) ;
uwrap_tls_id = id ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:16:34 +01:00
uwrap . myuid = libc_geteuid ( ) ;
uwrap . mygid = libc_getegid ( ) ;
2015-01-23 15:30:30 +01:00
2009-08-05 13:31:06 +10:00
/* put us in one group */
2014-01-17 14:43:01 +01:00
if ( root ! = NULL & & root [ 0 ] = = ' 1 ' ) {
2015-01-23 15:30:30 +01:00
id - > ruid = id - > euid = id - > suid = 0 ;
id - > rgid = id - > egid = id - > sgid = 0 ;
2015-01-23 15:25:16 +01:00
2015-01-23 15:30:30 +01:00
id - > groups = malloc ( sizeof ( gid_t ) * 1 ) ;
if ( id - > groups = = NULL ) {
2015-01-23 15:25:16 +01:00
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" Unable to allocate memory " ) ;
exit ( - 1 ) ;
}
2015-01-23 15:30:30 +01:00
id - > ngroups = 1 ;
id - > groups [ 0 ] = 0 ;
2015-01-23 15:25:16 +01:00
2014-01-17 14:43:01 +01:00
} else {
2015-01-23 15:30:30 +01:00
id - > ruid = id - > euid = id - > suid = uwrap . myuid ;
id - > rgid = id - > egid = id - > sgid = uwrap . mygid ;
2015-01-23 15:25:16 +01:00
2015-01-23 15:30:30 +01:00
id - > ngroups = libc_getgroups ( 0 , NULL ) ;
if ( id - > ngroups = = - 1 ) {
2015-01-23 15:25:16 +01:00
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" Unable to call libc_getgroups in uwrap_init. " ) ;
exit ( - 1 ) ;
}
2015-01-23 15:30:30 +01:00
id - > groups = malloc ( sizeof ( gid_t ) * id - > ngroups ) ;
if ( id - > groups = = NULL ) {
2015-01-23 15:25:16 +01:00
UWRAP_LOG ( UWRAP_LOG_ERROR , " Unable to allocate memory " ) ;
exit ( - 1 ) ;
}
2015-01-23 15:30:30 +01:00
if ( libc_getgroups ( id - > ngroups , id - > groups ) = = - 1 ) {
2015-01-23 15:25:16 +01:00
UWRAP_LOG ( UWRAP_LOG_ERROR ,
" Unable to call libc_getgroups again in uwrap_init. " ) ;
2015-01-23 15:30:30 +01:00
id - > groups = 0 ;
2015-01-23 15:25:16 +01:00
/*
* Deallocation of uwrap . groups is handled by
* library destructor .
*/
exit ( - 1 ) ;
}
2014-01-17 14:43:01 +01:00
}
2017-07-13 08:57:13 +02:00
uwrap_init_env ( id ) ;
2015-01-23 15:30:30 +01:00
id - > enabled = true ;
2014-07-31 10:19:58 +02:00
UWRAP_LOG ( UWRAP_LOG_DEBUG ,
2015-10-30 13:36:04 +01:00
" Enabled uid_wrapper as %s (real uid=%u) " ,
id - > ruid = = 0 ? " root " : " user " ,
( unsigned int ) uwrap . myuid ) ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-07-31 10:19:58 +02:00
2017-07-13 08:57:13 +02:00
UWRAP_LOG ( UWRAP_LOG_DEBUG , " Successfully initialized uid_wrapper " ) ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
bool uid_wrapper_enabled ( void )
2009-08-05 11:21:06 +10:00
{
2015-01-23 15:30:30 +01:00
struct uwrap_thread * id = uwrap_tls_id ;
bool enabled ;
if ( id = = NULL ) {
return false ;
}
UWRAP_LOCK ( uwrap_id ) ;
enabled = id - > enabled ;
UWRAP_UNLOCK ( uwrap_id ) ;
2015-01-23 15:15:04 +01:00
return enabled ;
2009-08-05 11:21:06 +10:00
}
2015-10-30 13:37:51 +01:00
/*
* UWRAP_SETxUID FUNCTIONS
*/
static int uwrap_setresuid_args ( uid_t ruid , uid_t euid , uid_t suid )
2015-01-23 15:27:25 +01:00
{
struct uwrap_thread * id = uwrap_tls_id ;
2015-10-30 13:37:51 +01:00
UWRAP_LOG ( UWRAP_LOG_TRACE ,
" ruid %d -> %d, euid %d -> %d, suid %d -> %d " ,
id - > ruid , ruid , id - > euid , euid , id - > suid , suid ) ;
if ( id - > euid ! = 0 ) {
if ( ruid ! = ( uid_t ) - 1 & &
ruid ! = id - > ruid & &
ruid ! = id - > euid & &
ruid ! = id - > suid ) {
errno = EPERM ;
return - 1 ;
}
if ( euid ! = ( uid_t ) - 1 & &
euid ! = id - > ruid & &
euid ! = id - > euid & &
euid ! = id - > suid ) {
errno = EPERM ;
return - 1 ;
}
if ( suid ! = ( uid_t ) - 1 & &
suid ! = id - > ruid & &
suid ! = id - > euid & &
suid ! = id - > suid ) {
errno = EPERM ;
return - 1 ;
}
}
2015-01-23 15:27:25 +01:00
return 0 ;
}
2014-01-17 14:43:01 +01:00
static int uwrap_setresuid_thread ( uid_t ruid , uid_t euid , uid_t suid )
2009-08-05 10:50:03 +10:00
{
2014-01-17 14:43:01 +01:00
struct uwrap_thread * id = uwrap_tls_id ;
2015-10-30 13:37:51 +01:00
int rc ;
2014-01-17 14:43:01 +01:00
2015-10-30 13:37:51 +01:00
UWRAP_LOG ( UWRAP_LOG_TRACE ,
" ruid %d -> %d, euid %d -> %d, suid %d -> %d " ,
id - > ruid , ruid , id - > euid , euid , id - > suid , suid ) ;
rc = uwrap_setresuid_args ( ruid , euid , suid ) ;
if ( rc ! = 0 ) {
return rc ;
2014-01-17 14:43:01 +01:00
}
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2015-10-30 13:37:51 +01:00
2014-01-17 14:43:01 +01:00
if ( ruid ! = ( uid_t ) - 1 ) {
id - > ruid = ruid ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
if ( euid ! = ( uid_t ) - 1 ) {
id - > euid = euid ;
2011-10-07 18:58:58 +02:00
}
2014-01-17 14:43:01 +01:00
if ( suid ! = ( uid_t ) - 1 ) {
id - > suid = suid ;
}
2015-01-23 15:24:39 +01:00
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
2009-08-05 10:50:03 +10:00
return 0 ;
}
2014-01-17 14:43:01 +01:00
2015-10-30 13:37:51 +01:00
static int uwrap_setresuid ( uid_t ruid , uid_t euid , uid_t suid )
2015-01-23 15:27:25 +01:00
{
struct uwrap_thread * id = uwrap_tls_id ;
2015-10-30 13:37:51 +01:00
int rc ;
2015-01-23 15:27:25 +01:00
2015-10-30 13:37:51 +01:00
UWRAP_LOG ( UWRAP_LOG_TRACE ,
" ruid %d -> %d, euid %d -> %d, suid %d -> %d " ,
id - > ruid , ruid , id - > euid , euid , id - > suid , suid ) ;
2015-01-23 15:27:25 +01:00
2015-10-30 13:37:51 +01:00
rc = uwrap_setresuid_args ( ruid , euid , suid ) ;
if ( rc ! = 0 ) {
return rc ;
2014-01-17 14:43:01 +01:00
}
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2015-10-30 13:37:51 +01:00
2014-01-17 14:43:01 +01:00
for ( id = uwrap . ids ; id ; id = id - > next ) {
if ( ruid ! = ( uid_t ) - 1 ) {
id - > ruid = ruid ;
}
if ( euid ! = ( uid_t ) - 1 ) {
id - > euid = euid ;
}
if ( suid ! = ( uid_t ) - 1 ) {
id - > suid = suid ;
}
}
2015-01-23 15:16:34 +01:00
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
return 0 ;
}
2015-10-30 13:38:32 +01:00
static int uwrap_setreuid_args ( uid_t ruid , uid_t euid ,
uid_t * _new_ruid ,
uid_t * _new_euid ,
uid_t * _new_suid )
{
struct uwrap_thread * id = uwrap_tls_id ;
uid_t new_ruid = - 1 , new_euid = - 1 , new_suid = - 1 ;
UWRAP_LOG ( UWRAP_LOG_TRACE ,
" ruid %d -> %d, euid %d -> %d " ,
id - > ruid , ruid , id - > euid , euid ) ;
if ( ruid ! = ( uid_t ) - 1 ) {
new_ruid = ruid ;
if ( ruid ! = id - > ruid & &
ruid ! = id - > euid & &
id - > euid ! = 0 ) {
errno = EPERM ;
return - 1 ;
}
}
if ( euid ! = ( uid_t ) - 1 ) {
new_euid = euid ;
if ( euid ! = id - > ruid & &
euid ! = id - > euid & &
euid ! = id - > suid & &
id - > euid ! = 0 ) {
errno = EPERM ;
return - 1 ;
}
}
if ( ruid ! = ( uid_t ) - 1 | |
( euid ! = ( uid_t ) - 1 & & id - > ruid ! = euid ) ) {
new_suid = new_euid ;
}
* _new_ruid = new_ruid ;
* _new_euid = new_euid ;
* _new_suid = new_suid ;
return 0 ;
}
static int uwrap_setreuid_thread ( uid_t ruid , uid_t euid )
{
struct uwrap_thread * id = uwrap_tls_id ;
uid_t new_ruid = - 1 , new_euid = - 1 , new_suid = - 1 ;
int rc ;
UWRAP_LOG ( UWRAP_LOG_TRACE ,
" ruid %d -> %d, euid %d -> %d " ,
id - > ruid , ruid , id - > euid , euid ) ;
rc = uwrap_setreuid_args ( ruid , euid , & new_ruid , & new_euid , & new_suid ) ;
if ( rc ! = 0 ) {
return rc ;
}
return uwrap_setresuid_thread ( new_ruid , new_euid , new_suid ) ;
}
# ifdef HAVE_SETREUID
static int uwrap_setreuid ( uid_t ruid , uid_t euid )
{
struct uwrap_thread * id = uwrap_tls_id ;
uid_t new_ruid = - 1 , new_euid = - 1 , new_suid = - 1 ;
int rc ;
UWRAP_LOG ( UWRAP_LOG_TRACE ,
" ruid %d -> %d, euid %d -> %d " ,
id - > ruid , ruid , id - > euid , euid ) ;
rc = uwrap_setreuid_args ( ruid , euid , & new_ruid , & new_euid , & new_suid ) ;
if ( rc ! = 0 ) {
return rc ;
}
return uwrap_setresuid ( new_ruid , new_euid , new_suid ) ;
}
# endif
2015-10-30 13:37:51 +01:00
2015-10-30 13:39:02 +01:00
static int uwrap_setuid_args ( uid_t uid ,
uid_t * new_ruid ,
uid_t * new_euid ,
uid_t * new_suid )
{
struct uwrap_thread * id = uwrap_tls_id ;
UWRAP_LOG ( UWRAP_LOG_TRACE ,
" uid %d -> %d " ,
id - > ruid , uid ) ;
if ( uid = = ( uid_t ) - 1 ) {
errno = EINVAL ;
return - 1 ;
}
if ( id - > euid = = 0 ) {
* new_suid = * new_ruid = uid ;
} else if ( uid ! = id - > ruid & &
uid ! = id - > suid ) {
errno = EPERM ;
return - 1 ;
}
* new_euid = uid ;
return 0 ;
}
static int uwrap_setuid_thread ( uid_t uid )
{
uid_t new_ruid = - 1 , new_euid = - 1 , new_suid = - 1 ;
int rc ;
rc = uwrap_setuid_args ( uid , & new_ruid , & new_euid , & new_suid ) ;
if ( rc ! = 0 ) {
return rc ;
}
return uwrap_setresuid_thread ( new_ruid , new_euid , new_suid ) ;
}
static int uwrap_setuid ( uid_t uid )
{
uid_t new_ruid = - 1 , new_euid = - 1 , new_suid = - 1 ;
int rc ;
rc = uwrap_setuid_args ( uid , & new_ruid , & new_euid , & new_suid ) ;
if ( rc ! = 0 ) {
return rc ;
}
return uwrap_setresuid ( new_ruid , new_euid , new_suid ) ;
}
2015-10-30 13:37:51 +01:00
/*
* UWRAP_GETxUID FUNCTIONS
*/
# ifdef HAVE_GETRESUID
static int uwrap_getresuid ( uid_t * ruid , uid_t * euid , uid_t * suid )
{
struct uwrap_thread * id = uwrap_tls_id ;
UWRAP_LOCK ( uwrap_id ) ;
* ruid = id - > ruid ;
* euid = id - > euid ;
* suid = id - > suid ;
UWRAP_UNLOCK ( uwrap_id ) ;
return 0 ;
}
# endif
# ifdef HAVE_GETRESGID
static int uwrap_getresgid ( gid_t * rgid , gid_t * egid , gid_t * sgid )
{
struct uwrap_thread * id = uwrap_tls_id ;
UWRAP_LOCK ( uwrap_id ) ;
* rgid = id - > rgid ;
* egid = id - > egid ;
* sgid = id - > sgid ;
UWRAP_UNLOCK ( uwrap_id ) ;
return 0 ;
}
# endif
2015-10-30 13:39:55 +01:00
/*
* UWRAP_SETxGID FUNCTIONS
*/
static int uwrap_setresgid_args ( gid_t rgid , gid_t egid , gid_t sgid )
{
struct uwrap_thread * id = uwrap_tls_id ;
UWRAP_LOG ( UWRAP_LOG_TRACE ,
" rgid %d -> %d, egid %d -> %d, sgid %d -> %d " ,
id - > rgid , rgid , id - > egid , egid , id - > sgid , sgid ) ;
if ( id - > euid ! = 0 ) {
if ( rgid ! = ( gid_t ) - 1 & &
rgid ! = id - > rgid & &
rgid ! = id - > egid & &
rgid ! = id - > sgid ) {
errno = EPERM ;
return - 1 ;
}
if ( egid ! = ( gid_t ) - 1 & &
egid ! = id - > rgid & &
egid ! = id - > egid & &
egid ! = id - > sgid ) {
errno = EPERM ;
return - 1 ;
}
if ( sgid ! = ( gid_t ) - 1 & &
sgid ! = id - > rgid & &
sgid ! = id - > egid & &
sgid ! = id - > sgid ) {
errno = EPERM ;
return - 1 ;
}
}
return 0 ;
}
static int uwrap_setresgid_thread ( gid_t rgid , gid_t egid , gid_t sgid )
{
struct uwrap_thread * id = uwrap_tls_id ;
int rc ;
UWRAP_LOG ( UWRAP_LOG_TRACE ,
" rgid %d -> %d, egid %d -> %d, sgid %d -> %d " ,
id - > rgid , rgid , id - > egid , egid , id - > sgid , sgid ) ;
rc = uwrap_setresgid_args ( rgid , egid , sgid ) ;
if ( rc ! = 0 ) {
return rc ;
}
UWRAP_LOCK ( uwrap_id ) ;
if ( rgid ! = ( gid_t ) - 1 ) {
id - > rgid = rgid ;
}
if ( egid ! = ( gid_t ) - 1 ) {
id - > egid = egid ;
}
if ( sgid ! = ( gid_t ) - 1 ) {
id - > sgid = sgid ;
}
UWRAP_UNLOCK ( uwrap_id ) ;
return 0 ;
}
static int uwrap_setresgid ( gid_t rgid , gid_t egid , gid_t sgid )
{
struct uwrap_thread * id = uwrap_tls_id ;
int rc ;
UWRAP_LOG ( UWRAP_LOG_TRACE ,
" rgid %d -> %d, egid %d -> %d, sgid %d -> %d " ,
id - > rgid , rgid , id - > egid , egid , id - > sgid , sgid ) ;
rc = uwrap_setresgid_args ( rgid , egid , sgid ) ;
if ( rc ! = 0 ) {
return rc ;
}
UWRAP_LOCK ( uwrap_id ) ;
for ( id = uwrap . ids ; id ; id = id - > next ) {
if ( rgid ! = ( gid_t ) - 1 ) {
id - > rgid = rgid ;
}
if ( egid ! = ( gid_t ) - 1 ) {
id - > egid = egid ;
}
if ( sgid ! = ( gid_t ) - 1 ) {
id - > sgid = sgid ;
}
}
UWRAP_UNLOCK ( uwrap_id ) ;
return 0 ;
}
2015-10-30 13:40:18 +01:00
static int uwrap_setregid_args ( gid_t rgid , gid_t egid ,
gid_t * _new_rgid ,
gid_t * _new_egid ,
gid_t * _new_sgid )
{
struct uwrap_thread * id = uwrap_tls_id ;
gid_t new_rgid = - 1 , new_egid = - 1 , new_sgid = - 1 ;
UWRAP_LOG ( UWRAP_LOG_TRACE ,
" rgid %d -> %d, egid %d -> %d " ,
id - > rgid , rgid , id - > egid , egid ) ;
if ( rgid ! = ( gid_t ) - 1 ) {
new_rgid = rgid ;
if ( rgid ! = id - > rgid & &
rgid ! = id - > egid & &
id - > euid ! = 0 ) {
errno = EPERM ;
return - 1 ;
}
}
if ( egid ! = ( gid_t ) - 1 ) {
new_egid = egid ;
if ( egid ! = id - > rgid & &
egid ! = id - > egid & &
egid ! = id - > sgid & &
id - > euid ! = 0 ) {
errno = EPERM ;
return - 1 ;
}
}
if ( rgid ! = ( gid_t ) - 1 | |
( egid ! = ( gid_t ) - 1 & & id - > rgid ! = egid ) ) {
new_sgid = new_egid ;
}
* _new_rgid = new_rgid ;
* _new_egid = new_egid ;
* _new_sgid = new_sgid ;
return 0 ;
}
static int uwrap_setregid_thread ( gid_t rgid , gid_t egid )
{
struct uwrap_thread * id = uwrap_tls_id ;
gid_t new_rgid = - 1 , new_egid = - 1 , new_sgid = - 1 ;
int rc ;
UWRAP_LOG ( UWRAP_LOG_TRACE ,
" rgid %d -> %d, egid %d -> %d " ,
id - > rgid , rgid , id - > egid , egid ) ;
rc = uwrap_setregid_args ( rgid , egid , & new_rgid , & new_egid , & new_sgid ) ;
if ( rc ! = 0 ) {
return rc ;
}
return uwrap_setresgid_thread ( new_rgid , new_egid , new_sgid ) ;
}
# ifdef HAVE_SETREGID
static int uwrap_setregid ( gid_t rgid , gid_t egid )
{
struct uwrap_thread * id = uwrap_tls_id ;
gid_t new_rgid = - 1 , new_egid = - 1 , new_sgid = - 1 ;
int rc ;
UWRAP_LOG ( UWRAP_LOG_TRACE ,
" rgid %d -> %d, egid %d -> %d " ,
id - > rgid , rgid , id - > egid , egid ) ;
rc = uwrap_setregid_args ( rgid , egid , & new_rgid , & new_egid , & new_sgid ) ;
if ( rc ! = 0 ) {
return rc ;
}
return uwrap_setresgid ( new_rgid , new_egid , new_sgid ) ;
}
# endif
2015-10-30 13:40:45 +01:00
static int uwrap_setgid_args ( gid_t gid ,
gid_t * new_rgid ,
gid_t * new_egid ,
gid_t * new_sgid )
{
struct uwrap_thread * id = uwrap_tls_id ;
UWRAP_LOG ( UWRAP_LOG_TRACE ,
" gid %d -> %d " ,
id - > rgid , gid ) ;
if ( gid = = ( gid_t ) - 1 ) {
errno = EINVAL ;
return - 1 ;
}
if ( id - > euid = = 0 ) {
* new_sgid = * new_rgid = gid ;
} else if ( gid ! = id - > rgid & &
gid ! = id - > sgid ) {
errno = EPERM ;
return - 1 ;
}
* new_egid = gid ;
return 0 ;
}
static int uwrap_setgid_thread ( gid_t gid )
{
gid_t new_rgid = - 1 , new_egid = - 1 , new_sgid = - 1 ;
int rc ;
rc = uwrap_setgid_args ( gid , & new_rgid , & new_egid , & new_sgid ) ;
if ( rc ! = 0 ) {
return rc ;
}
return uwrap_setresgid_thread ( new_rgid , new_egid , new_sgid ) ;
}
static int uwrap_setgid ( gid_t gid )
{
gid_t new_rgid = - 1 , new_egid = - 1 , new_sgid = - 1 ;
int rc ;
rc = uwrap_setgid_args ( gid , & new_rgid , & new_egid , & new_sgid ) ;
if ( rc ! = 0 ) {
return rc ;
}
return uwrap_setresgid ( new_rgid , new_egid , new_sgid ) ;
}
2014-01-17 14:43:01 +01:00
/*
* SETUID
*/
int setuid ( uid_t uid )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_setuid ( uid ) ;
}
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2015-10-30 13:39:02 +01:00
return uwrap_setuid ( uid ) ;
2014-01-17 14:43:01 +01:00
}
# ifdef HAVE_SETEUID
int seteuid ( uid_t euid )
{
2015-10-30 13:39:30 +01:00
if ( ! uid_wrapper_enabled ( ) ) {
return libc_seteuid ( euid ) ;
}
/* On FreeBSD the uid_t -1 is set and doesn't produce and error */
2014-01-17 14:43:01 +01:00
if ( euid = = ( uid_t ) - 1 ) {
errno = EINVAL ;
return - 1 ;
}
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_setresuid ( - 1 , euid , - 1 ) ;
}
2011-10-08 10:08:37 +02:00
# endif
2009-08-05 10:50:03 +10:00
2011-10-08 10:08:37 +02:00
# ifdef HAVE_SETREUID
2014-01-17 14:43:01 +01:00
int setreuid ( uid_t ruid , uid_t euid )
2011-10-06 16:25:32 +02:00
{
2014-01-17 14:43:01 +01:00
if ( ! uid_wrapper_enabled ( ) ) {
return libc_setreuid ( ruid , euid ) ;
2011-10-07 18:58:58 +02:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2015-10-30 13:38:32 +01:00
return uwrap_setreuid ( ruid , euid ) ;
2011-10-06 16:25:32 +02:00
}
2011-10-08 10:08:37 +02:00
# endif
2011-10-06 16:25:32 +02:00
2011-10-08 10:08:37 +02:00
# ifdef HAVE_SETRESUID
2014-01-17 14:43:01 +01:00
int setresuid ( uid_t ruid , uid_t euid , uid_t suid )
2011-10-07 10:30:23 +02:00
{
2014-01-17 14:43:01 +01:00
if ( ! uid_wrapper_enabled ( ) ) {
return libc_setresuid ( ruid , euid , suid ) ;
2011-10-07 18:58:58 +02:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_setresuid ( ruid , euid , suid ) ;
2011-10-07 10:30:23 +02:00
}
2011-10-08 10:08:37 +02:00
# endif
2011-10-07 10:30:23 +02:00
2015-01-23 15:27:25 +01:00
# ifdef HAVE_GETRESUID
int getresuid ( uid_t * ruid , uid_t * euid , uid_t * suid )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_getresuid ( ruid , euid , suid ) ;
}
uwrap_init ( ) ;
return uwrap_getresuid ( ruid , euid , suid ) ;
}
# endif
2014-01-17 14:43:01 +01:00
/*
* GETUID
*/
static uid_t uwrap_getuid ( void )
2009-08-05 10:50:03 +10:00
{
2014-01-17 14:43:01 +01:00
struct uwrap_thread * id = uwrap_tls_id ;
uid_t uid ;
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
uid = id - > ruid ;
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
return uid ;
}
uid_t getuid ( void )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_getuid ( ) ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_getuid ( ) ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
/*
* GETEUID
*/
static uid_t uwrap_geteuid ( void )
2009-08-05 10:50:03 +10:00
{
2014-01-17 14:43:01 +01:00
const char * env = getenv ( " UID_WRAPPER_MYUID " ) ;
struct uwrap_thread * id = uwrap_tls_id ;
uid_t uid ;
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
uid = id - > euid ;
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
/* Disable root and return myuid */
if ( env ! = NULL & & env [ 0 ] = = ' 1 ' ) {
uid = uwrap . myuid ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
return uid ;
}
uid_t geteuid ( void )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_geteuid ( ) ;
2011-10-07 18:58:58 +02:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_geteuid ( ) ;
}
/*
* SETGID
*/
int setgid ( gid_t gid )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_setgid ( gid ) ;
}
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2015-10-30 13:40:45 +01:00
return uwrap_setgid ( gid ) ;
2014-01-17 14:43:01 +01:00
}
# ifdef HAVE_SETEGID
int setegid ( gid_t egid )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_setegid ( egid ) ;
}
2015-10-30 13:41:18 +01:00
/* On FreeBSD the uid_t -1 is set and doesn't produce and error */
if ( egid = = ( gid_t ) - 1 ) {
errno = EINVAL ;
return - 1 ;
}
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_setresgid ( - 1 , egid , - 1 ) ;
}
2011-10-08 10:08:37 +02:00
# endif
2011-10-06 16:52:03 +02:00
2014-01-17 14:43:01 +01:00
# ifdef HAVE_SETREGID
int setregid ( gid_t rgid , gid_t egid )
2011-10-08 10:52:02 +02:00
{
2014-01-17 14:43:01 +01:00
if ( ! uid_wrapper_enabled ( ) ) {
return libc_setregid ( rgid , egid ) ;
2011-10-08 10:52:02 +02:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2015-10-30 13:40:18 +01:00
return uwrap_setregid ( rgid , egid ) ;
2014-01-17 14:43:01 +01:00
}
# endif
# ifdef HAVE_SETRESGID
int setresgid ( gid_t rgid , gid_t egid , gid_t sgid )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_setresgid ( rgid , egid , sgid ) ;
2011-10-08 10:52:02 +02:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_setresgid ( rgid , egid , sgid ) ;
2011-10-08 10:52:02 +02:00
}
# endif
2015-01-23 15:27:25 +01:00
# ifdef HAVE_GETRESGID
int getresgid ( gid_t * rgid , gid_t * egid , gid_t * sgid )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_getresgid ( rgid , egid , sgid ) ;
}
uwrap_init ( ) ;
return uwrap_getresgid ( rgid , egid , sgid ) ;
}
# endif
2014-01-17 14:43:01 +01:00
/*
* GETGID
*/
static gid_t uwrap_getgid ( void )
2009-08-05 10:50:03 +10:00
{
2014-01-17 14:43:01 +01:00
struct uwrap_thread * id = uwrap_tls_id ;
gid_t gid ;
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
gid = id - > rgid ;
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
return gid ;
}
gid_t getgid ( void )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_getgid ( ) ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_getgid ( ) ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
/*
* GETEGID
*/
static uid_t uwrap_getegid ( void )
2009-08-05 10:50:03 +10:00
{
2014-01-17 14:43:01 +01:00
struct uwrap_thread * id = uwrap_tls_id ;
gid_t gid ;
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
gid = id - > egid ;
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
return gid ;
}
uid_t getegid ( void )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_getegid ( ) ;
2009-08-05 10:50:03 +10:00
}
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_getegid ( ) ;
}
static int uwrap_setgroups_thread ( size_t size , const gid_t * list )
{
struct uwrap_thread * id = uwrap_tls_id ;
int rc = - 1 ;
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
2014-07-31 10:20:40 +02:00
if ( size = = 0 ) {
2015-01-23 15:25:16 +01:00
SAFE_FREE ( id - > groups ) ;
2014-07-31 10:20:40 +02:00
id - > ngroups = 0 ;
} else if ( size > 0 ) {
2014-01-17 14:43:01 +01:00
gid_t * tmp ;
2009-08-05 13:31:06 +10:00
2014-01-17 14:43:01 +01:00
tmp = realloc ( id - > groups , sizeof ( gid_t ) * size ) ;
if ( tmp = = NULL ) {
2009-08-05 13:31:06 +10:00
errno = ENOMEM ;
2014-01-17 14:43:01 +01:00
goto out ;
2009-08-05 13:31:06 +10:00
}
2014-01-17 14:43:01 +01:00
id - > groups = tmp ;
id - > ngroups = size ;
memcpy ( id - > groups , list , size * sizeof ( gid_t ) ) ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
rc = 0 ;
out :
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
return rc ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
static int uwrap_setgroups ( size_t size , const gid_t * list )
2009-08-05 10:50:03 +10:00
{
2014-01-17 14:43:01 +01:00
struct uwrap_thread * id ;
int rc = - 1 ;
2011-02-19 23:21:07 +01:00
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
2014-07-31 10:20:40 +02:00
if ( size = = 0 ) {
for ( id = uwrap . ids ; id ; id = id - > next ) {
2015-01-23 15:25:16 +01:00
SAFE_FREE ( id - > groups ) ;
2014-07-31 10:20:40 +02:00
id - > ngroups = 0 ;
2015-01-23 15:25:16 +01:00
2014-07-31 10:20:40 +02:00
}
} else if ( size > 0 ) {
2015-01-23 15:25:16 +01:00
gid_t * tmp ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:25:16 +01:00
for ( id = uwrap . ids ; id ; id = id - > next ) {
2014-01-17 14:43:01 +01:00
tmp = realloc ( id - > groups , sizeof ( gid_t ) * size ) ;
if ( tmp = = NULL ) {
errno = ENOMEM ;
goto out ;
}
id - > groups = tmp ;
id - > ngroups = size ;
memcpy ( id - > groups , list , size * sizeof ( gid_t ) ) ;
}
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
rc = 0 ;
out :
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
return rc ;
}
# ifdef HAVE_SETGROUPS_INT
int setgroups ( int size , const gid_t * list )
# else
int setgroups ( size_t size , const gid_t * list )
# endif
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc_setgroups ( size , list ) ;
}
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_setgroups ( size , list ) ;
}
static int uwrap_getgroups ( int size , gid_t * list )
{
struct uwrap_thread * id = uwrap_tls_id ;
int ngroups ;
2015-01-23 14:00:49 +01:00
UWRAP_LOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
ngroups = id - > ngroups ;
2011-02-19 23:21:07 +01:00
if ( size > ngroups ) {
size = ngroups ;
2009-08-05 10:50:03 +10:00
}
if ( size = = 0 ) {
2014-01-17 14:43:01 +01:00
goto out ;
2009-08-05 10:50:03 +10:00
}
2011-02-19 23:21:07 +01:00
if ( size < ngroups ) {
2009-08-05 10:50:03 +10:00
errno = EINVAL ;
2014-01-17 14:43:01 +01:00
ngroups = - 1 ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
memcpy ( list , id - > groups , size * sizeof ( gid_t ) ) ;
out :
2015-01-23 14:00:49 +01:00
UWRAP_UNLOCK ( uwrap_id ) ;
2014-01-17 14:43:01 +01:00
2011-02-19 23:21:07 +01:00
return ngroups ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
int getgroups ( int size , gid_t * list )
2009-08-05 10:50:03 +10:00
{
2014-01-17 14:43:01 +01:00
if ( ! uid_wrapper_enabled ( ) ) {
return libc_getgroups ( size , list ) ;
2009-08-05 10:50:03 +10:00
}
2014-01-17 14:43:01 +01:00
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
return uwrap_getgroups ( size , list ) ;
2009-08-05 10:50:03 +10:00
}
2023-01-16 22:14:03 +01:00
# ifdef HAVE___GETGROUPS_CHK
static int uwrap___getgroups_chk ( int size , gid_t * list , size_t listlen )
{
if ( size * sizeof ( gid_t ) > listlen ) {
UWRAP_LOG ( UWRAP_LOG_DEBUG , " Buffer overflow detected " ) ;
abort ( ) ;
}
return uwrap_getgroups ( size , list ) ;
}
int __getgroups_chk ( int size , gid_t * list , size_t listlen ) ;
int __getgroups_chk ( int size , gid_t * list , size_t listlen )
{
if ( ! uid_wrapper_enabled ( ) ) {
return libc___getgroups_chk ( size , list , listlen ) ;
}
uwrap_init ( ) ;
return uwrap___getgroups_chk ( size , list , listlen ) ;
}
# endif /* HAVE___GETGROUPS_CHK */
2014-01-17 14:43:01 +01:00
# if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
& & ( defined ( SYS_setreuid ) | | defined ( SYS_setreuid32 ) )
2023-01-16 22:14:03 +01:00
static bool uwrap_is_uwrap_related_syscall ( long int sysno )
{
switch ( sysno ) {
/* gid */
# ifdef __alpha__
case SYS_getxgid :
return true ;
# else
case SYS_getgid :
return true ;
# endif
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getgid32 :
return true ;
# endif
# ifdef SYS_getegid
case SYS_getegid :
return true ;
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getegid32 :
return true ;
# endif
# endif /* SYS_getegid */
case SYS_setgid :
return true ;
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setgid32 :
return true ;
# endif
case SYS_setregid :
return true ;
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setregid32 :
return true ;
# endif
# ifdef SYS_setresgid
case SYS_setresgid :
return true ;
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setresgid32 :
return true ;
# endif
# endif /* SYS_setresgid */
# if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
case SYS_getresgid :
return true ;
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getresgid32 :
return true ;
# endif
# endif /* SYS_getresgid && HAVE_GETRESGID */
/* uid */
# ifdef __alpha__
case SYS_getxuid :
return true ;
# else
case SYS_getuid :
return true ;
# endif
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getuid32 :
return true ;
# endif
# ifdef SYS_geteuid
case SYS_geteuid :
return true ;
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_geteuid32 :
return true ;
# endif
# endif /* SYS_geteuid */
case SYS_setuid :
return true ;
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setuid32 :
return true ;
# endif
case SYS_setreuid :
return true ;
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setreuid32 :
return true ;
# endif
# ifdef SYS_setresuid
case SYS_setresuid :
return true ;
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setresuid32 :
return true ;
# endif
# endif /* SYS_setresuid */
# if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
case SYS_getresuid :
return true ;
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getresuid32 :
return true ;
# endif
# endif /* SYS_getresuid && HAVE_GETRESUID*/
/* groups */
case SYS_setgroups :
return true ;
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setgroups32 :
return true ;
# endif
default :
return false ;
}
}
2014-01-17 14:43:01 +01:00
static long int uwrap_syscall ( long int sysno , va_list vp )
2009-08-05 10:50:03 +10:00
{
2014-01-17 14:43:01 +01:00
long int rc ;
switch ( sysno ) {
/* gid */
2017-07-13 08:57:13 +02:00
# ifdef __alpha__
case SYS_getxgid :
# else
2014-01-17 14:43:01 +01:00
case SYS_getgid :
2017-07-13 08:57:13 +02:00
# endif
2014-01-17 14:43:01 +01:00
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getgid32 :
# endif
{
rc = uwrap_getgid ( ) ;
}
break ;
# ifdef SYS_getegid
case SYS_getegid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getegid32 :
# endif
{
rc = uwrap_getegid ( ) ;
}
break ;
# endif /* SYS_getegid */
case SYS_setgid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setgid32 :
# endif
{
2015-01-23 15:28:00 +01:00
gid_t gid = ( gid_t ) va_arg ( vp , gid_t ) ;
2014-01-17 14:43:01 +01:00
2015-10-30 13:40:45 +01:00
rc = uwrap_setgid_thread ( gid ) ;
2014-01-17 14:43:01 +01:00
}
break ;
case SYS_setregid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setregid32 :
# endif
{
2015-01-23 15:28:00 +01:00
gid_t rgid = ( gid_t ) va_arg ( vp , gid_t ) ;
gid_t egid = ( gid_t ) va_arg ( vp , gid_t ) ;
2014-01-17 14:43:01 +01:00
2015-10-30 13:40:18 +01:00
rc = uwrap_setregid_thread ( rgid , egid ) ;
2014-01-17 14:43:01 +01:00
}
break ;
# ifdef SYS_setresgid
case SYS_setresgid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setresgid32 :
# endif
{
2015-01-23 15:28:00 +01:00
gid_t rgid = ( gid_t ) va_arg ( vp , gid_t ) ;
gid_t egid = ( gid_t ) va_arg ( vp , gid_t ) ;
gid_t sgid = ( gid_t ) va_arg ( vp , gid_t ) ;
2014-01-17 14:43:01 +01:00
rc = uwrap_setresgid_thread ( rgid , egid , sgid ) ;
}
break ;
# endif /* SYS_setresgid */
2015-08-21 11:04:49 +02:00
# if defined(SYS_getresgid) && defined(HAVE_GETRESGID)
2015-01-23 15:27:25 +01:00
case SYS_getresgid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getresgid32 :
# endif
{
gid_t * rgid = ( gid_t * ) va_arg ( vp , gid_t * ) ;
gid_t * egid = ( gid_t * ) va_arg ( vp , gid_t * ) ;
gid_t * sgid = ( gid_t * ) va_arg ( vp , gid_t * ) ;
rc = uwrap_getresgid ( rgid , egid , sgid ) ;
}
break ;
2015-08-21 11:04:49 +02:00
# endif /* SYS_getresgid && HAVE_GETRESGID */
2014-01-17 14:43:01 +01:00
/* uid */
2017-07-13 08:57:13 +02:00
# ifdef __alpha__
case SYS_getxuid :
# else
2014-01-17 14:43:01 +01:00
case SYS_getuid :
2017-07-13 08:57:13 +02:00
# endif
2014-01-17 14:43:01 +01:00
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getuid32 :
# endif
{
rc = uwrap_getuid ( ) ;
}
break ;
# ifdef SYS_geteuid
case SYS_geteuid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_geteuid32 :
# endif
{
rc = uwrap_geteuid ( ) ;
}
break ;
# endif /* SYS_geteuid */
case SYS_setuid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setuid32 :
# endif
{
2015-01-23 15:28:00 +01:00
uid_t uid = ( uid_t ) va_arg ( vp , uid_t ) ;
2014-01-17 14:43:01 +01:00
2015-10-30 13:39:02 +01:00
rc = uwrap_setuid_thread ( uid ) ;
2014-01-17 14:43:01 +01:00
}
break ;
case SYS_setreuid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setreuid32 :
# endif
{
2015-01-23 15:28:00 +01:00
uid_t ruid = ( uid_t ) va_arg ( vp , uid_t ) ;
uid_t euid = ( uid_t ) va_arg ( vp , uid_t ) ;
2014-01-17 14:43:01 +01:00
2015-10-30 13:38:32 +01:00
rc = uwrap_setreuid_thread ( ruid , euid ) ;
2014-01-17 14:43:01 +01:00
}
break ;
# ifdef SYS_setresuid
case SYS_setresuid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setresuid32 :
# endif
{
2015-01-23 15:28:00 +01:00
uid_t ruid = ( uid_t ) va_arg ( vp , uid_t ) ;
uid_t euid = ( uid_t ) va_arg ( vp , uid_t ) ;
uid_t suid = ( uid_t ) va_arg ( vp , uid_t ) ;
2014-01-17 14:43:01 +01:00
rc = uwrap_setresuid_thread ( ruid , euid , suid ) ;
}
break ;
# endif /* SYS_setresuid */
2015-08-21 11:04:49 +02:00
# if defined(SYS_getresuid) && defined(HAVE_GETRESUID)
2015-01-23 15:27:25 +01:00
case SYS_getresuid :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_getresuid32 :
# endif
{
uid_t * ruid = ( uid_t * ) va_arg ( vp , uid_t * ) ;
uid_t * euid = ( uid_t * ) va_arg ( vp , uid_t * ) ;
uid_t * suid = ( uid_t * ) va_arg ( vp , uid_t * ) ;
2014-01-17 14:43:01 +01:00
2015-01-23 15:27:25 +01:00
rc = uwrap_getresuid ( ruid , euid , suid ) ;
}
break ;
2015-08-21 11:04:49 +02:00
# endif /* SYS_getresuid && HAVE_GETRESUID*/
2014-01-17 14:43:01 +01:00
/* groups */
case SYS_setgroups :
# ifdef HAVE_LINUX_32BIT_SYSCALLS
case SYS_setgroups32 :
# endif
{
size_t size = ( size_t ) va_arg ( vp , size_t ) ;
gid_t * list = ( gid_t * ) va_arg ( vp , int * ) ;
rc = uwrap_setgroups_thread ( size , list ) ;
}
break ;
default :
2023-01-16 22:14:03 +01:00
rc = - 1 ;
errno = ENOSYS ;
2014-01-17 14:43:01 +01:00
break ;
}
return rc ;
}
# ifdef HAVE_SYSCALL
# ifdef HAVE_SYSCALL_INT
int syscall ( int sysno , . . . )
# else
long int syscall ( long int sysno , . . . )
# endif
{
# ifdef HAVE_SYSCALL_INT
int rc ;
# else
long int rc ;
# endif
va_list va ;
va_start ( va , sysno ) ;
2024-06-13 07:41:41 +02:00
/*
* JEMALLOC :
*
* This is a workaround to prevent a deadlock in jemalloc calling
* malloc_init ( ) twice . The first allocation call will trigger a
* malloc_init ( ) of jemalloc . The functions calls syscall ( SYS_open , . . . )
* so it goes to socket or uid wrapper . In this code path we need to
* avoid any allocation calls . This will prevent the deadlock .
*/
if ( ! uwrap_handle_syscall ) {
rc = libc_vsyscall ( sysno , va ) ;
va_end ( va ) ;
return rc ;
}
2023-01-16 22:14:03 +01:00
/*
* We need to check for uwrap related syscall numbers before calling
* uid_wrapper_enabled ( ) otherwise we ' d deadlock during the freebsd libc
* fork ( ) which calls syscall ( ) after invoking uwrap_thread_prepare ( ) .
*/
if ( ! uwrap_is_uwrap_related_syscall ( sysno ) ) {
/*
* We need to give socket_wrapper a
* chance to take over . . .
*/
if ( uwrap_swrap_syscall_valid ( sysno ) ) {
rc = uwrap_swrap_syscall_va ( sysno , va ) ;
va_end ( va ) ;
return rc ;
}
rc = libc_vsyscall ( sysno , va ) ;
va_end ( va ) ;
return rc ;
}
2014-01-17 14:43:01 +01:00
if ( ! uid_wrapper_enabled ( ) ) {
rc = libc_vsyscall ( sysno , va ) ;
va_end ( va ) ;
return rc ;
}
2015-01-23 15:15:04 +01:00
uwrap_init ( ) ;
2014-01-17 14:43:01 +01:00
rc = uwrap_syscall ( sysno , va ) ;
va_end ( va ) ;
return rc ;
}
2023-01-16 22:14:03 +01:00
/* used by socket_wrapper */
bool uid_wrapper_syscall_valid ( long int sysno ) ;
bool uid_wrapper_syscall_valid ( long int sysno )
{
if ( ! uwrap_is_uwrap_related_syscall ( sysno ) ) {
return false ;
}
if ( ! uid_wrapper_enabled ( ) ) {
return false ;
}
return true ;
}
/* used by socket_wrapper */
long int uid_wrapper_syscall_va ( long int sysno , va_list va ) ;
long int uid_wrapper_syscall_va ( long int sysno , va_list va )
{
if ( ! uwrap_is_uwrap_related_syscall ( sysno ) ) {
errno = ENOSYS ;
return - 1 ;
}
if ( ! uid_wrapper_enabled ( ) ) {
return libc_vsyscall ( sysno , va ) ;
}
uwrap_init ( ) ;
return uwrap_syscall ( sysno , va ) ;
}
2014-01-17 14:43:01 +01:00
# endif /* HAVE_SYSCALL */
# endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */
2015-01-23 15:10:02 +01:00
/****************************
* CONSTRUCTOR
* * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-07-13 08:57:13 +02:00
2015-01-23 15:10:02 +01:00
void uwrap_constructor ( void )
{
2017-07-13 08:57:13 +02:00
char * glibc_malloc_lock_bug ;
/*
* This is a workaround for a bug in glibc < 2.24 :
*
* The child handler for the malloc ( ) function is called and locks the
* mutex . Then our child handler is called and we try to call setenv ( ) .
* setenv ( ) wants to malloc and tries to aquire the lock for malloc and
* we end up in a deadlock .
*
* So as a workaround we need to call malloc once before we setup the
* handlers .
*
* See https : //sourceware.org/bugzilla/show_bug.cgi?id=16742
*/
glibc_malloc_lock_bug = malloc ( 1 ) ;
if ( glibc_malloc_lock_bug = = NULL ) {
exit ( - 1 ) ;
}
glibc_malloc_lock_bug [ 0 ] = ' \0 ' ;
2023-01-16 22:14:03 +01:00
UWRAP_REINIT_ALL ;
2015-01-23 15:10:02 +01:00
/*
* If we hold a lock and the application forks , then the child
* is not able to unlock the mutex and we are in a deadlock .
* This should prevent such deadlocks .
*/
pthread_atfork ( & uwrap_thread_prepare ,
& uwrap_thread_parent ,
& uwrap_thread_child ) ;
2015-01-23 15:15:04 +01:00
2017-07-13 08:57:13 +02:00
free ( glibc_malloc_lock_bug ) ;
2015-01-23 15:15:04 +01:00
/* Here is safe place to call uwrap_init() and initialize data
* for main process .
*/
uwrap_init ( ) ;
2024-06-13 07:41:41 +02:00
/* Let socket_wrapper handle syscall() */
uwrap_handle_syscall = true ;
2015-01-23 15:10:02 +01:00
}
2014-01-17 14:43:01 +01:00
/****************************
* DESTRUCTOR
* * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* This function is called when the library is unloaded and makes sure that
* resources are freed .
*/
void uwrap_destructor ( void )
{
struct uwrap_thread * u = uwrap . ids ;
2015-01-23 15:29:35 +01:00
UWRAP_LOCK_ALL ;
2015-01-23 15:12:02 +01:00
2014-01-17 14:43:01 +01:00
while ( u ! = NULL ) {
UWRAP_DLIST_REMOVE ( uwrap . ids , u ) ;
SAFE_FREE ( u - > groups ) ;
SAFE_FREE ( u ) ;
u = uwrap . ids ;
}
2015-01-23 15:25:16 +01:00
2023-01-16 22:14:03 +01:00
if ( uwrap . libc . handle ! = NULL
# ifdef RTLD_NEXT
& & uwrap . libc . handle ! = RTLD_NEXT
# endif
) {
2014-01-17 14:43:01 +01:00
dlclose ( uwrap . libc . handle ) ;
2009-08-05 10:50:03 +10:00
}
2015-01-23 15:12:02 +01:00
2023-01-16 22:14:03 +01:00
if ( uwrap . libpthread . handle ! = NULL
# ifdef RTLD_NEXT
& & uwrap . libpthread . handle ! = RTLD_NEXT
# endif
) {
2015-01-23 15:30:03 +01:00
dlclose ( uwrap . libpthread . handle ) ;
}
2015-01-23 15:29:35 +01:00
UWRAP_UNLOCK_ALL ;
2009-08-05 10:50:03 +10:00
}