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