>From 662ed6ab1ad262a6713cb678cdb65d84bb846284 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 25 Jun 2012 18:08:36 -0700 Subject: [PATCH 1/4] Add missing setresgid() wrapper. --- lib/uid_wrapper/uid_wrapper.h | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/lib/uid_wrapper/uid_wrapper.h b/lib/uid_wrapper/uid_wrapper.h index 680e544..c597493 100644 --- a/lib/uid_wrapper/uid_wrapper.h +++ b/lib/uid_wrapper/uid_wrapper.h @@ -27,6 +27,7 @@ int uwrap_setresuid(uid_t reuid, uid_t euid, uid_t suid); uid_t uwrap_geteuid(void); int uwrap_setegid(gid_t egid); int uwrap_setregid(gid_t rgid, gid_t egid); +int uwrap_setresgid(gid_t regid, gid_t egid, gid_t sgid); uid_t uwrap_getegid(void); int uwrap_setgroups(size_t size, const gid_t *list); int uwrap_getgroups(int size, gid_t *list); -- 1.7.7.3 >From cfae4dbc57bab5a25f76ab164fa35bb874e19d9a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 26 Jun 2012 09:47:14 -0700 Subject: [PATCH 2/4] Ensure replace.h includes syscall headers if we have them. --- lib/replace/replace.h | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/lib/replace/replace.h b/lib/replace/replace.h index bb271d4..d77b8da 100644 --- a/lib/replace/replace.h +++ b/lib/replace/replace.h @@ -140,6 +140,14 @@ #include #endif +#ifdef HAVE_SYSCALL_H +#include +#endif + +#ifdef HAVE_SYS_SYSCALL_H +#include +#endif + #ifndef HAVE_STRERROR extern char *sys_errlist[]; #define strerror(i) sys_errlist[i] -- 1.7.7.3 >From e6dc17b06c9c5f12fc52ab5d4489ad0fe7ea39db Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 26 Jun 2012 10:49:58 -0700 Subject: [PATCH 3/4] Add in the ability to replace all the set[res][ug]id functions with thread-specific functions inside libreplace. --- lib/replace/libreplace.m4 | 4 +- lib/replace/replace.c | 24 --------- lib/replace/replace.h | 30 ++++++++++++ lib/replace/setids.c | 115 +++++++++++++++++++++++++++++++++++++++++++++ lib/replace/wscript | 4 +- 5 files changed, 151 insertions(+), 26 deletions(-) create mode 100644 lib/replace/setids.c diff --git a/lib/replace/libreplace.m4 b/lib/replace/libreplace.m4 index ad0f904..d298b92 100644 --- a/lib/replace/libreplace.m4 +++ b/lib/replace/libreplace.m4 @@ -124,8 +124,10 @@ AC_CHECK_HEADERS(sys/mount.h mntent.h) AC_CHECK_HEADERS(stropts.h) AC_CHECK_HEADERS(unix.h) AC_CHECK_HEADERS(malloc.h) +AC_CHECK_HEADERS(syscall.h) +AC_CHECK_HEADERS(sys/syscall.h) -AC_CHECK_FUNCS(seteuid setreuid setresuid setegid setregid setresgid) +AC_CHECK_FUNCS(syscall setuid seteuid setreuid setresuid setgid setegid setregid setresgid setgroups) AC_CHECK_FUNCS(chroot bzero strerror strerror_r memalign posix_memalign getpagesize) AC_CHECK_FUNCS(vsyslog setlinebuf mktime ftruncate chsize rename) AC_CHECK_FUNCS(waitpid wait4 strlcpy strlcat initgroups memmove strdup) diff --git a/lib/replace/replace.c b/lib/replace/replace.c index 322bf49..b9a0356 100644 --- a/lib/replace/replace.c +++ b/lib/replace/replace.c @@ -368,30 +368,6 @@ int rep_waitpid(pid_t pid,int *status,int options) } #endif -#ifndef HAVE_SETEUID -int rep_seteuid(uid_t euid) -{ -#ifdef HAVE_SETRESUID - return setresuid(-1, euid, -1); -#else - errno = ENOSYS; - return -1; -#endif -} -#endif - -#ifndef HAVE_SETEGID -int rep_setegid(gid_t egid) -{ -#ifdef HAVE_SETRESGID - return setresgid(-1, egid, -1); -#else - errno = ENOSYS; - return -1; -#endif -} -#endif - /******************************************************************* os/2 also doesn't have chroot ********************************************************************/ diff --git a/lib/replace/replace.h b/lib/replace/replace.h index d77b8da..c967b62f 100644 --- a/lib/replace/replace.h +++ b/lib/replace/replace.h @@ -243,6 +243,35 @@ int setenv(const char *name, const char *value, int overwrite); int rep_unsetenv(const char *name); #endif +#if defined(USE_LINUX_THREAD_UID_CALLS) +#define setresuid rep_setresuid +int rep_setresuid(uid_t ruid, uid_t euid, uid_t suid); + +#define setresgid rep_setresgid +int rep_setresgid(gid_t rgid, gid_t egid, gid_t sgid); + +#define setreuid rep_setreuid +int rep_setreuid(uid_t ruid, uid_t euid); + +#define setregid rep_setregid +int rep_setregid(gid_t rgid, gid_t egid); + +#define setegid rep_setegid +int rep_setegid(gid_t egid); + +#define seteuid rep_seteuid +int rep_seteuid(uid_t euid); + +#define setuid rep_setuid +int rep_setuid(uid_t uid); + +#define setgid rep_setgid +int rep_setgid(gid_t gid); + +#define setgroups rep_setgroups +int rep_setgroups(size_t setlen, const gid_t *gidset); + +#else #ifndef HAVE_SETEUID #define seteuid rep_seteuid int rep_seteuid(uid_t); @@ -260,6 +289,7 @@ int setresuid(uid_t ruid, uid_t euid, uid_t suid); #if (defined(USE_SETRESUID) && !defined(HAVE_SETRESGID_DECL)) int setresgid(gid_t rgid, gid_t egid, gid_t sgid); #endif +#endif #ifndef HAVE_CHOWN #define chown rep_chown diff --git a/lib/replace/setids.c b/lib/replace/setids.c new file mode 100644 index 0000000..20ea4b9 --- /dev/null +++ b/lib/replace/setids.c @@ -0,0 +1,115 @@ +/* + Unix SMB/CIFS implementation. + replacement routines for broken systems + Copyright (C) Jeremy Allison 2012 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see . +*/ + +#include "replace.h" +#include "system/passwd.h" + +#if defined(USE_LINUX_THREAD_UID_CALLS) + +/************************************************************************** + Linux-specific versions of setXX functions that only change the per-thread + credentials. +****************************************************************************/ + +int rep_setresuid(uid_t ruid, uid_t euid, uid_t suid) +{ + return syscall(SYS_setresuid, ruid, euid, suid); +} + +int rep_setresgid(gid_t rgid, gid_t egid, gid_t sgid) +{ + return syscall(SYS_setresgid, rgid, egid, sgid); +} + +int rep_setreuid(uid_t ruid, uid_t euid) +{ + return syscall(SYS_setreuid, ruid, euid); +} + +int rep_setregid(gid_t rgid, gid_t egid) +{ + return syscall(SYS_setregid, rgid, egid); +} + +/* setegid is not a separate system call. */ +int rep_setegid(gid_t egid) +{ + return syscall(SYS_setresgid, -1, egid, -1); +} + +/* seteuid is not a separate system call. */ +int rep_seteuid(uid_t euid) +{ + return syscall(SYS_setresuid, -1, euid, -1); +} + +int rep_setuid(uid_t uid) +{ + return syscall(SYS_setuid, uid); +} + +int rep_setgid(gid_t gid) +{ + return syscall(SYS_setgid, gid); +} + +int rep_setgroups(size_t setlen, const gid_t *gidset) +{ + return syscall(SYS_setgroups, setlen, gidset); +} + +#else + +/******************************************************* + Give the system something to link if none of + the below get replaced. +********************************************************/ + +void replace_setid_dummy(void); +void replace_setid_dummy(void) {} + +#ifndef HAVE_SETEUID +int rep_seteuid(uid_t euid) +{ +#ifdef HAVE_SETRESUID + return setresuid(-1, euid, -1); +#else + errno = ENOSYS; + return -1; +#endif +} +#endif + +#ifndef HAVE_SETEGID +int rep_setegid(gid_t egid) +{ +#ifdef HAVE_SETRESGID + return setresgid(-1, egid, -1); +#else + errno = ENOSYS; + return -1; +#endif +} +#endif + +#endif diff --git a/lib/replace/wscript b/lib/replace/wscript index 68138cf..efa334c 100644 --- a/lib/replace/wscript +++ b/lib/replace/wscript @@ -207,7 +207,7 @@ def configure(conf): conf.CHECK_FUNCS('if_nametoindex strerror_r') conf.CHECK_FUNCS('getdirentries getdents syslog') conf.CHECK_FUNCS('gai_strerror get_current_dir_name') - conf.CHECK_FUNCS('timegm getifaddrs freeifaddrs mmap setgroups setsid') + conf.CHECK_FUNCS('timegm getifaddrs freeifaddrs mmap setgroups syscall setsid') conf.CHECK_FUNCS('getgrent_r getgrgid_r getgrnam_r getgrouplist getpagesize') conf.CHECK_FUNCS('getpwent_r getpwnam_r getpwuid_r epoll_create') @@ -464,6 +464,8 @@ REPLACEMENT_FUNCTIONS = { # Note: WORKING_STRPTIME is not a function, but a special condition # for replacement 'strptime.c': ['WORKING_STRPTIME', 'strptime'], + 'setids.c' : [ 'setresuid', 'setresgid', 'setreuid' 'setregid', + 'setegid', 'seteuid', 'setuid', 'setgid', 'setgroups'], } -- 1.7.7.3 >From 719992b8e7effb6e61acf7b63a08ccff53f31a44 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 26 Jun 2012 16:04:48 -0700 Subject: [PATCH 4/4] Add waf and autoconf checks in libreplace for USE_LINUX_THREAD_UID_CALLS. Add comprehensive test code in setids.c to ensure system call wrappers work correctly. --- lib/replace/libreplace.m4 | 11 ++++ lib/replace/test/setids.c | 147 +++++++++++++++++++++++++++++++++++++++++++++ lib/replace/wscript | 10 +++ 3 files changed, 168 insertions(+), 0 deletions(-) create mode 100644 lib/replace/test/setids.c diff --git a/lib/replace/libreplace.m4 b/lib/replace/libreplace.m4 index d298b92..4045cc4 100644 --- a/lib/replace/libreplace.m4 +++ b/lib/replace/libreplace.m4 @@ -404,6 +404,17 @@ fi AC_CHECK_FUNCS([printf memset memcpy],,[AC_MSG_ERROR([Required function not found])]) +case "$host_os" in +*linux*) +AC_CACHE_CHECK([for Linux thread-specific credentials in libreplace],libreplace_cv_USE_LINUX_THREAD_UID_CALLS,[ +AC_TRY_RUN([#define NO_CONFIG_H 1 + #define AUTOCONF_TEST 1 + #include "$libreplacedir/test/setids.c"], + libreplace_cv_USE_LINUX_THREAD_UID_CALLS=yes,libreplace_cv_USE_LINUX_THREAD_UID_CALLS=no,libreplace_cv_USE_LINUX_THREAD_UID_CALLS=cross)]) +if test x"$libreplace_cv_USE_LINUX_THREAD_UID_CALLS" = x"yes"; then + AC_DEFINE(USE_LINUX_THREAD_UID_CALLS,1,[Whether we can use Linux thread-specific credentials in libreplace]) +fi + echo "LIBREPLACE_BROKEN_CHECKS: END" ]) dnl end AC_LIBREPLACE_BROKEN_CHECKS diff --git a/lib/replace/test/setids.c b/lib/replace/test/setids.c new file mode 100644 index 0000000..7cc6766 --- /dev/null +++ b/lib/replace/test/setids.c @@ -0,0 +1,147 @@ +/* + * Unix SMB/CIFS implementation. + * + * libreplace setids test for Linux thread-specific credentials. + * + * Copyright (C) Jeremy Allison 2012 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * All this code is testing is if we can + * safely use thread specific credentials (currently + * only on Linux). If not, then we're not actually + * going to replace anything so we can bail out. + */ + +#include "replace.h" +#include "system/passwd.h" + +static int have_syscall(void) +{ + errno = 0; + + syscall(SYS_setresuid, -1, -1, -1); + if (errno == ENOSYS) { + return -1; + } + + return 0; +} + +static int assert_uid(uid_t ruid, uid_t euid) +{ + if ((euid != (uid_t)-1 && geteuid() != euid) || + (ruid != (uid_t)-1 && getuid() != ruid)) { + fprintf(stderr, "failed to set uid\n"); + exit(1); + } + return 0; +} + +static int assert_gid(gid_t rgid, gid_t egid) +{ + if ((egid != (gid_t)-1 && getegid() != egid) || + (rgid != (gid_t)-1 && getgid() != rgid)) { + fprintf(stderr, "failed to set gid\n"); + exit(1); + } + return 0; +} + +static void gain_root_privilege(void) +{ + syscall(SYS_setresuid, 0, 0, 0); + syscall(SYS_setuid, 0); + assert_uid(0, 0); +} + +void gain_root_group_privilege(void) +{ + syscall(SYS_setresgid, 0, 0, 0); + syscall(SYS_setgid, 0); + assert_gid(0, 0); +} + +void set_effective_uid(uid_t uid) +{ + syscall(SYS_setresuid, uid, uid, -1); + assert_uid(-1, uid); +} + +static void set_effective_gid(gid_t gid) +{ + syscall(SYS_setresgid, -1, gid, -1); + assert_gid(-1, gid); +} + +static uid_t saved_euid, saved_ruid; +static gid_t saved_egid, saved_rgid; + +static void save_re_uid(void) +{ + saved_ruid = getuid(); + saved_euid = geteuid(); +} + +static void restore_re_uid_fromroot(void) +{ + syscall(SYS_setresuid, saved_ruid, saved_euid, -1); + assert_uid(saved_ruid, saved_euid); +} + +static void restore_re_uid(void) +{ + set_effective_uid(0); + restore_re_uid_fromroot(); +} + +static void become_user_permanently(uid_t uid, gid_t gid) +{ + gain_root_privilege(); + gain_root_group_privilege(); + + syscall(SYS_setresgid, gid, gid, gid); + syscall(SYS_setgid, gid); + syscall(SYS_setresuid, uid, uid, uid); + syscall(SYS_setuid, uid); + + assert_uid(uid, uid); + assert_gid(gid, gid); +} + +int main(void) +{ + if (getuid() != 0) { + return have_syscall(); + } + + gain_root_privilege(); + gain_root_group_privilege(); + set_effective_gid(1); + set_effective_uid(1); + save_re_uid(); + restore_re_uid(); + gain_root_privilege(); + gain_root_group_privilege(); + become_user_permanently(1, 1); + syscall(SYS_setuid, 0); + if (getuid() == 0) { + fprintf(stderr,"uid not set permanently\n"); + return 1; + } + printf("SUCCESS !\n"); + return 0; +} diff --git a/lib/replace/wscript b/lib/replace/wscript index efa334c..ab097a7 100644 --- a/lib/replace/wscript +++ b/lib/replace/wscript @@ -345,6 +345,16 @@ removeea setea define='HAVE_INCOHERENT_MMAP', msg="Checking for HAVE_INCOHERENT_MMAP") + # + # Test if we can use Linux thread-specific credentials. + if sys.platform.rfind('linux') > -1: + conf.CHECK_CODE('''#define NO_CONFIG_H 1 + #define AUTOCONF_TEST 1 + #include "test/setids.c"''', + addmain=False, add_headers=False, execute=True, + define='USE_LINUX_THREAD_UID_CALLS', + msg="Checking for Linux thread-specific credentials") + conf.SAMBA_BUILD_ENV() conf.CHECK_CODE(''' -- 1.7.7.3