2 * Copyright (c) 2009 Andrew Tridgell
3 * Copyright (c) 2011-2013 Andreas Schneider <asn@samba.org>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <sys/types.h>
30 #ifdef HAVE_SYS_SYSCALL_H
31 #include <sys/syscall.h>
40 #ifdef HAVE_GCC_THREAD_LOCAL_STORAGE
41 # define UWRAP_THREAD __thread
47 #define UWRAP_DEBUG(...)
49 #define UWRAP_DEBUG(...) fprintf(stderr, __VA_ARGS__)
52 #define UWRAP_DLIST_ADD(list,item) do { \
54 (item)->prev = NULL; \
55 (item)->next = NULL; \
58 (item)->prev = NULL; \
59 (item)->next = (list); \
60 (list)->prev = (item); \
65 #define UWRAP_DLIST_REMOVE(list,item) do { \
66 if ((list) == (item)) { \
67 (list) = (item)->next; \
69 (list)->prev = NULL; \
73 (item)->prev->next = (item)->next; \
76 (item)->next->prev = (item)->prev; \
79 (item)->prev = NULL; \
80 (item)->next = NULL; \
83 #define LIBC_NAME "libc.so"
85 struct uwrap_libc_fns {
86 int (*_libc_setuid)(uid_t uid);
87 uid_t (*_libc_getuid)(void);
90 int (*_libc_seteuid)(uid_t euid);
93 int (*_libc_setreuid)(uid_t ruid, uid_t euid);
96 int (*_libc_setresuid)(uid_t ruid, uid_t euid, uid_t suid);
98 uid_t (*_libc_geteuid)(void);
100 int (*_libc_setgid)(gid_t gid);
101 gid_t (*_libc_getgid)(void);
103 int (*_libc_setegid)(uid_t egid);
106 int (*_libc_setregid)(uid_t rgid, uid_t egid);
108 #ifdef HAVE_SETRESGID
109 int (*_libc_setresgid)(uid_t rgid, uid_t egid, uid_t sgid);
111 gid_t (*_libc_getegid)(void);
112 int (*_libc_getgroups)(int size, gid_t list[]);
113 int (*_libc_setgroups)(size_t size, const gid_t *list);
115 long int (*_libc_syscall)(long int sysno, ...);
120 * We keep the virtualised euid/egid/groups information here
122 struct uwrap_thread {
137 struct uwrap_thread *next;
138 struct uwrap_thread *prev;
144 struct uwrap_libc_fns fns;
153 struct uwrap_thread *ids;
156 static struct uwrap uwrap;
158 /* Shortcut to the list item */
159 static UWRAP_THREAD struct uwrap_thread *uwrap_tls_id;
161 /* The mutex or accessing the id */
162 static pthread_mutex_t uwrap_id_mutex = PTHREAD_MUTEX_INITIALIZER;
164 /*********************************************************
165 * UWRAP LIBC LOADER FUNCTIONS
166 *********************************************************/
174 static void *uwrap_load_lib_handle(enum uwrap_lib lib)
176 int flags = RTLD_LAZY;
185 flags |= RTLD_DEEPBIND;
191 case UWRAP_LIBSOCKET:
194 if (handle == NULL) {
195 for (handle = NULL, i = 10; handle == NULL && i >= 0; i--) {
196 char soname[256] = {0};
198 snprintf(soname, sizeof(soname), "libc.so.%d", i);
199 handle = dlopen(soname, flags);
202 uwrap.libc.handle = handle;
204 handle = uwrap.libc.handle;
209 if (handle == NULL) {
211 "Failed to dlopen library: %s\n",
219 static void *_uwrap_load_lib_function(enum uwrap_lib lib, const char *fn_name)
224 handle = uwrap_load_lib_handle(lib);
226 func = dlsym(handle, fn_name);
229 "Failed to find %s: %s\n",
237 #define uwrap_load_lib_function(lib, fn_name) \
238 if (uwrap.libc.fns._libc_##fn_name == NULL) { \
239 *(void **) (&uwrap.libc.fns._libc_##fn_name) = \
240 _uwrap_load_lib_function(lib, #fn_name); \
246 * Functions expeciall from libc need to be loaded individually, you can't load
247 * all at once or gdb will segfault at startup. The same applies to valgrind and
248 * has probably something todo with with the linker.
249 * So we need load each function at the point it is called the first time.
251 static int libc_setuid(uid_t uid)
253 uwrap_load_lib_function(UWRAP_LIBC, setuid);
255 return uwrap.libc.fns._libc_setuid(uid);
258 static uid_t libc_getuid(void)
260 uwrap_load_lib_function(UWRAP_LIBC, getuid);
262 return uwrap.libc.fns._libc_getuid();
266 static int libc_seteuid(uid_t euid)
268 uwrap_load_lib_function(UWRAP_LIBC, seteuid);
270 return uwrap.libc.fns._libc_seteuid(euid);
275 static int libc_setreuid(uid_t ruid, uid_t euid)
277 uwrap_load_lib_function(UWRAP_LIBC, setreuid);
279 return uwrap.libc.fns._libc_setreuid(ruid, euid);
283 #ifdef HAVE_SETRESUID
284 int libc_setresuid(uid_t ruid, uid_t euid, uid_t suid);
286 uwrap_load_lib_function(UWRAP_LIBC, setresuid);
288 return uwrap.libc.fns._libc_setresuid(ruid, euid, suid);
292 static uid_t libc_geteuid(void)
294 uwrap_load_lib_function(UWRAP_LIBC, geteuid);
296 return uwrap.libc.fns._libc_geteuid();
299 static int libc_setgid(gid_t gid)
301 uwrap_load_lib_function(UWRAP_LIBC, setgid);
303 return uwrap.libc.fns._libc_setgid(gid);
306 static gid_t libc_getgid(void)
308 uwrap_load_lib_function(UWRAP_LIBC, getgid);
310 return uwrap.libc.fns._libc_getgid();
314 static int libc_setegid(gid_t egid)
316 uwrap_load_lib_function(UWRAP_LIBC, setegid);
318 return uwrap.libc.fns._libc_setegid(egid);
323 static int libc_setregid(gid_t rgid, gid_t egid)
325 uwrap_load_lib_function(UWRAP_LIBC, setregid);
327 return uwrap.libc.fns._libc_setregid(rgid, egid);
331 #ifdef HAVE_SETRESGID
332 static int libc_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
334 uwrap_load_lib_function(UWRAP_LIBC, setresgid);
336 return uwrap.libc.fns._libc_setresgid(rgid, egid, sgid);
340 static gid_t libc_getegid(void)
342 uwrap_load_lib_function(UWRAP_LIBC, getegid);
344 return uwrap.libc.fns._libc_getegid();
347 static int libc_getgroups(int size, gid_t list[])
349 uwrap_load_lib_function(UWRAP_LIBC, getgroups);
351 return uwrap.libc.fns._libc_getgroups(size, list);
354 static int libc_setgroups(size_t size, const gid_t *list)
356 uwrap_load_lib_function(UWRAP_LIBC, setgroups);
358 return uwrap.libc.fns._libc_setgroups(size, list);
361 static void *uwrap_libc_fn(struct uwrap *u, const char *fn_name)
366 func = dlsym(RTLD_NEXT, fn_name);
368 if (u->libc.handle == NULL) {
372 func = dlsym(u->libc.handle, fn_name);
375 printf("Failed to find %s in %s: %s\n",
376 fn_name, LIBC_NAME, dlerror());
383 static void uwrap_libc_init(struct uwrap *u)
387 int flags = RTLD_LAZY;
390 flags |= RTLD_DEEPBIND;
393 for (u->libc.handle = NULL, i = 10; u->libc.handle == NULL; i--) {
394 char soname[256] = {0};
396 snprintf(soname, sizeof(soname), "%s.%u", LIBC_NAME, i);
397 u->libc.handle = dlopen(soname, flags);
400 if (u->libc.handle == NULL) {
401 printf("Failed to dlopen %s.%u: %s\n", LIBC_NAME, i, dlerror());
407 *(void **) (&u->libc.fns._libc_syscall) = uwrap_libc_fn(u, "syscall");
411 static struct uwrap_thread *find_uwrap_id(pthread_t tid)
413 struct uwrap_thread *id;
415 for (id = uwrap.ids; id; id = id->next) {
416 if (pthread_equal(id->tid, tid)) {
424 static int uwrap_new_id(pthread_t tid, bool do_alloc)
426 struct uwrap_thread *id = uwrap_tls_id;
429 id = malloc(sizeof(struct uwrap_thread));
439 id->ruid = id->euid = id->suid = uwrap.myuid;
440 id->rgid = id->egid = id->sgid = uwrap.mygid;
443 id->groups = malloc(sizeof(gid_t) * id->ngroups);
444 id->groups[0] = uwrap.mygid;
447 UWRAP_DLIST_ADD(uwrap.ids, id);
454 static void uwrap_thread_prepare(void)
456 pthread_mutex_lock(&uwrap_id_mutex);
459 * What happens if another atfork prepare functions calls a uwrap
460 * function? So disable it in case another atfork prepare function
461 * calls a (s)uid function.
463 uwrap.enabled = false;
466 static void uwrap_thread_parent(void)
468 uwrap.enabled = true;
470 pthread_mutex_unlock(&uwrap_id_mutex);
473 static void uwrap_thread_child(void)
475 uwrap.enabled = true;
477 pthread_mutex_unlock(&uwrap_id_mutex);
480 static void uwrap_init(void)
482 const char *env = getenv("UID_WRAPPER");
483 pthread_t tid = pthread_self();
487 if (uwrap.initialised) {
488 struct uwrap_thread *id = uwrap_tls_id;
495 pthread_mutex_lock(&uwrap_id_mutex);
496 id = find_uwrap_id(tid);
498 rc = uwrap_new_id(tid, 1);
503 /* We reuse an old thread id */
506 uwrap_new_id(tid, 0);
508 pthread_mutex_unlock(&uwrap_id_mutex);
514 * If we hold a lock and the application forks, then the child
515 * is not able to unlock the mutex and we are in a deadlock.
516 * This should prevent such deadlocks.
518 pthread_atfork(&uwrap_thread_prepare,
519 &uwrap_thread_parent,
520 &uwrap_thread_child);
522 pthread_mutex_lock(&uwrap_id_mutex);
524 uwrap_libc_init(&uwrap);
526 uwrap.initialised = true;
527 uwrap.enabled = false;
529 if (env != NULL && env[0] == '1') {
530 const char *root = getenv("UID_WRAPPER_ROOT");
533 /* put us in one group */
534 if (root != NULL && root[0] == '1') {
538 uwrap.myuid = libc_geteuid();
539 uwrap.mygid = libc_getegid();
542 rc = uwrap_new_id(tid, 1);
547 uwrap.enabled = true;
550 pthread_mutex_unlock(&uwrap_id_mutex);
553 static int uwrap_enabled(void)
557 return uwrap.enabled ? 1 : 0;
560 static int uwrap_setresuid_thread(uid_t ruid, uid_t euid, uid_t suid)
562 struct uwrap_thread *id = uwrap_tls_id;
564 if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
569 pthread_mutex_lock(&uwrap_id_mutex);
570 if (ruid != (uid_t)-1) {
574 if (euid != (uid_t)-1) {
578 if (suid != (uid_t)-1) {
581 pthread_mutex_unlock(&uwrap_id_mutex);
586 static int uwrap_setresuid(uid_t ruid, uid_t euid, uid_t suid)
588 struct uwrap_thread *id;
590 if (ruid == (uid_t)-1 && euid == (uid_t)-1 && suid == (uid_t)-1) {
595 pthread_mutex_lock(&uwrap_id_mutex);
596 for (id = uwrap.ids; id; id = id->next) {
601 if (ruid != (uid_t)-1) {
605 if (euid != (uid_t)-1) {
609 if (suid != (uid_t)-1) {
613 pthread_mutex_unlock(&uwrap_id_mutex);
621 int setuid(uid_t uid)
623 if (!uwrap_enabled()) {
624 return libc_setuid(uid);
627 return uwrap_setresuid(uid, -1, -1);
631 int seteuid(uid_t euid)
633 if (euid == (uid_t)-1) {
638 if (!uwrap_enabled()) {
639 return libc_seteuid(euid);
642 return uwrap_setresuid(-1, euid, -1);
647 int setreuid(uid_t ruid, uid_t euid)
649 if (ruid == (uid_t)-1 && euid == (uid_t)-1) {
654 if (!uwrap_enabled()) {
655 return libc_setreuid(ruid, euid);
658 return uwrap_setresuid(ruid, euid, -1);
662 #ifdef HAVE_SETRESUID
663 int setresuid(uid_t ruid, uid_t euid, uid_t suid)
665 if (!uwrap_enabled()) {
666 return libc_setresuid(ruid, euid, suid);
669 return uwrap_setresuid(ruid, euid, suid);
676 static uid_t uwrap_getuid(void)
678 struct uwrap_thread *id = uwrap_tls_id;
681 pthread_mutex_lock(&uwrap_id_mutex);
683 pthread_mutex_unlock(&uwrap_id_mutex);
690 if (!uwrap_enabled()) {
691 return libc_getuid();
694 return uwrap_getuid();
700 static uid_t uwrap_geteuid(void)
702 const char *env = getenv("UID_WRAPPER_ROOT");
703 struct uwrap_thread *id = uwrap_tls_id;
706 pthread_mutex_lock(&uwrap_id_mutex);
708 pthread_mutex_unlock(&uwrap_id_mutex);
710 /* Disable root and return myuid */
711 if (env != NULL && env[0] == '2') {
720 if (!uwrap_enabled()) {
721 return libc_geteuid();
724 return uwrap_geteuid();
727 static int uwrap_setresgid_thread(gid_t rgid, gid_t egid, gid_t sgid)
729 struct uwrap_thread *id = uwrap_tls_id;
731 if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
736 pthread_mutex_lock(&uwrap_id_mutex);
737 if (rgid != (gid_t)-1) {
741 if (egid != (gid_t)-1) {
745 if (sgid != (gid_t)-1) {
748 pthread_mutex_unlock(&uwrap_id_mutex);
753 static int uwrap_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
755 struct uwrap_thread *id;
757 if (rgid == (gid_t)-1 && egid == (gid_t)-1 && sgid == (gid_t)-1) {
762 pthread_mutex_lock(&uwrap_id_mutex);
763 for (id = uwrap.ids; id; id = id->next) {
768 if (rgid != (gid_t)-1) {
772 if (egid != (gid_t)-1) {
776 if (sgid != (gid_t)-1) {
780 pthread_mutex_unlock(&uwrap_id_mutex);
788 int setgid(gid_t gid)
790 if (!uwrap_enabled()) {
791 return libc_setgid(gid);
794 return uwrap_setresgid(gid, -1, -1);
798 int setegid(gid_t egid)
800 if (!uwrap_enabled()) {
801 return libc_setegid(egid);
804 return uwrap_setresgid(-1, egid, -1);
809 int setregid(gid_t rgid, gid_t egid)
811 if (!uwrap_enabled()) {
812 return libc_setregid(rgid, egid);
815 return uwrap_setresgid(rgid, egid, -1);
819 #ifdef HAVE_SETRESGID
820 int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
822 if (!uwrap_enabled()) {
823 return libc_setresgid(rgid, egid, sgid);
826 return uwrap_setresgid(rgid, egid, sgid);
833 static gid_t uwrap_getgid(void)
835 struct uwrap_thread *id = uwrap_tls_id;
838 pthread_mutex_lock(&uwrap_id_mutex);
840 pthread_mutex_unlock(&uwrap_id_mutex);
847 if (!uwrap_enabled()) {
848 return libc_getgid();
851 return uwrap_getgid();
857 static uid_t uwrap_getegid(void)
859 struct uwrap_thread *id = uwrap_tls_id;
862 pthread_mutex_lock(&uwrap_id_mutex);
864 pthread_mutex_unlock(&uwrap_id_mutex);
871 if (!uwrap_enabled()) {
872 return libc_getegid();
875 return uwrap_getegid();
878 static int uwrap_setgroups_thread(size_t size, const gid_t *list)
880 struct uwrap_thread *id = uwrap_tls_id;
883 pthread_mutex_lock(&uwrap_id_mutex);
889 id->groups = malloc(sizeof(gid_t) * size);
890 if (id->groups == NULL) {
895 memcpy(id->groups, list, size * sizeof(gid_t));
900 pthread_mutex_unlock(&uwrap_id_mutex);
905 static int uwrap_setgroups(size_t size, const gid_t *list)
907 struct uwrap_thread *id;
910 pthread_mutex_lock(&uwrap_id_mutex);
911 for (id = uwrap.ids; id; id = id->next) {
917 id->groups = malloc(sizeof(gid_t) * size);
918 if (id->groups == NULL) {
923 memcpy(id->groups, list, size * sizeof(gid_t));
929 pthread_mutex_unlock(&uwrap_id_mutex);
934 #ifdef HAVE_SETGROUPS_INT
935 int setgroups(int size, const gid_t *list)
937 int setgroups(size_t size, const gid_t *list)
940 if (!uwrap_enabled()) {
941 return libc_setgroups(size, list);
944 return uwrap_setgroups(size, list);
947 static int uwrap_getgroups(int size, gid_t *list)
949 struct uwrap_thread *id = uwrap_tls_id;
952 pthread_mutex_lock(&uwrap_id_mutex);
953 ngroups = id->ngroups;
955 if (size > ngroups) {
961 if (size < ngroups) {
965 memcpy(list, id->groups, size * sizeof(gid_t));
968 pthread_mutex_unlock(&uwrap_id_mutex);
973 int getgroups(int size, gid_t *list)
975 if (!uwrap_enabled()) {
976 return libc_getgroups(size, list);
979 return uwrap_getgroups(size, list);
982 static long int libc_vsyscall(long int sysno, va_list va)
988 for (i = 0; i < 8; i++) {
989 args[i] = va_arg(va, long int);
992 rc = uwrap.libc.fns._libc_syscall(sysno,
1005 #if (defined(HAVE_SYS_SYSCALL_H) || defined(HAVE_SYSCALL_H)) \
1006 && (defined(SYS_setreuid) || defined(SYS_setreuid32))
1007 static long int uwrap_syscall (long int sysno, va_list vp)
1014 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1018 rc = uwrap_getgid();
1023 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1027 rc = uwrap_getegid();
1030 #endif /* SYS_getegid */
1032 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1036 gid_t gid = (gid_t) va_arg(vp, int);
1038 rc = uwrap_setresgid_thread(gid, -1, -1);
1042 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1043 case SYS_setregid32:
1046 uid_t rgid = (uid_t) va_arg(vp, int);
1047 uid_t egid = (uid_t) va_arg(vp, int);
1049 rc = uwrap_setresgid_thread(rgid, egid, -1);
1052 #ifdef SYS_setresgid
1054 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1055 case SYS_setresgid32:
1058 uid_t rgid = (uid_t) va_arg(vp, int);
1059 uid_t egid = (uid_t) va_arg(vp, int);
1060 uid_t sgid = (uid_t) va_arg(vp, int);
1062 rc = uwrap_setresgid_thread(rgid, egid, sgid);
1065 #endif /* SYS_setresgid */
1069 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1073 rc = uwrap_getuid();
1078 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1082 rc = uwrap_geteuid();
1085 #endif /* SYS_geteuid */
1087 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1091 uid_t uid = (uid_t) va_arg(vp, int);
1093 rc = uwrap_setresuid_thread(uid, -1, -1);
1097 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1098 case SYS_setreuid32:
1101 uid_t ruid = (uid_t) va_arg(vp, int);
1102 uid_t euid = (uid_t) va_arg(vp, int);
1104 rc = uwrap_setresuid_thread(ruid, euid, -1);
1107 #ifdef SYS_setresuid
1109 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1110 case SYS_setresuid32:
1113 uid_t ruid = (uid_t) va_arg(vp, int);
1114 uid_t euid = (uid_t) va_arg(vp, int);
1115 uid_t suid = (uid_t) va_arg(vp, int);
1117 rc = uwrap_setresuid_thread(ruid, euid, suid);
1120 #endif /* SYS_setresuid */
1124 #ifdef HAVE_LINUX_32BIT_SYSCALLS
1125 case SYS_setgroups32:
1128 size_t size = (size_t) va_arg(vp, size_t);
1129 gid_t *list = (gid_t *) va_arg(vp, int *);
1131 rc = uwrap_setgroups_thread(size, list);
1135 UWRAP_DEBUG("UID_WRAPPER calling non-wrapped syscall "
1138 rc = libc_vsyscall(sysno, vp);
1146 #ifdef HAVE_SYSCALL_INT
1147 int syscall (int sysno, ...)
1149 long int syscall (long int sysno, ...)
1152 #ifdef HAVE_SYSCALL_INT
1159 va_start(va, sysno);
1161 if (!uwrap_enabled()) {
1162 rc = libc_vsyscall(sysno, va);
1167 rc = uwrap_syscall(sysno, va);
1172 #endif /* HAVE_SYSCALL */
1173 #endif /* HAVE_SYS_SYSCALL_H || HAVE_SYSCALL_H */