From: Greg Hudson Date: Wed, 24 Apr 2019 19:56:43 +0000 (-0400) Subject: Add secure_getenv() support X-Git-Tag: krb5-1.18-beta1~150 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ff71934f40afd4ae536638fa626fcd9ab36daf75;p=thirdparty%2Fkrb5.git Add secure_getenv() support On systems with secure_getenv() (glibc 2.17+) use it directly. For the fallback implementation, check the current process uids and gids in a library initializer, looking at the saved uid and gid where possible. Include a comment about more aggressive approaches to detecting elevated privilege. ticket: 8800 (new) --- diff --git a/src/configure.ac b/src/configure.ac index 87d21350d9..9bafee73e6 100644 --- a/src/configure.ac +++ b/src/configure.ac @@ -148,7 +148,7 @@ AC_SUBST(po) # for kdc AC_CHECK_HEADERS(sys/sockio.h ifaddrs.h unistd.h fnmatch.h) -AC_CHECK_FUNCS(vsprintf vasprintf vsnprintf strlcpy fnmatch) +AC_CHECK_FUNCS(vsprintf vasprintf vsnprintf strlcpy fnmatch secure_getenv) EXTRA_SUPPORT_SYMS= AC_CHECK_FUNC(strlcpy, @@ -208,6 +208,18 @@ KRB5_NEED_PROTO([#include #include ],swab,1) +AC_CHECK_FUNC(secure_getenv, +[SECURE_GETENV_ST_OBJ= +SECURE_GETENV_OBJ= +SECURE_GETENV_INIT=], +[SECURE_GETENV_ST_OBJ=secure_getenv.o +SECURE_GETENV_OBJ='$(OUTPRE)secure_getenv.$(OBJEXT)' +SECURE_GETENV_INIT=k5_secure_getenv_init +EXTRA_SUPPORT_SYMS="$EXTRA_SUPPORT_SYMS k5_secure_getenv"]) +AC_SUBST(SECURE_GETENV_OBJ) +AC_SUBST(SECURE_GETENV_ST_OBJ) +AC_SUBST(SECURE_GETENV_INIT) + AC_PROG_AWK KRB5_AC_INET6 KRB5_SOCKADDR_SA_LEN @@ -442,7 +454,7 @@ AC_PROG_LEX AC_C_CONST AC_HEADER_DIRENT AC_FUNC_STRERROR_R -AC_CHECK_FUNCS(strdup setvbuf seteuid setresuid setreuid setegid setresgid setregid setsid flock fchmod chmod strptime geteuid setenv unsetenv getenv gmtime_r localtime_r bswap16 bswap64 mkstemp getusershell access getcwd srand48 srand srandom stat strchr strerror timegm explicit_bzero explicit_memset) +AC_CHECK_FUNCS(strdup setvbuf seteuid setresuid setreuid setegid setresgid setregid setsid flock fchmod chmod strptime geteuid setenv unsetenv getenv gmtime_r localtime_r bswap16 bswap64 mkstemp getusershell access getcwd srand48 srand srandom stat strchr strerror timegm explicit_bzero explicit_memset getresuid getresgid) AC_CHECK_FUNC(mkstemp, [MKSTEMP_ST_OBJ= diff --git a/src/include/k5-platform.h b/src/include/k5-platform.h index 1fcd68e8c0..11249317f9 100644 --- a/src/include/k5-platform.h +++ b/src/include/k5-platform.h @@ -45,6 +45,7 @@ * + path manipulation * + _, N_, dgettext, bindtextdomain (for localization) * + getopt_long + * + secure_getenv * + fetching filenames from a directory */ @@ -1134,6 +1135,14 @@ extern int k5_getopt_long(int nargc, char **nargv, char *options, #define getopt_long k5_getopt_long #endif /* HAVE_GETOPT_LONG */ +#if defined(_WIN32) +/* On Windows there is never a need to ignore the process environment. */ +#define secure_getenv getenv +#elif !defined(HAVE_SECURE_GETENV) +#define secure_getenv k5_secure_getenv +extern char *k5_secure_getenv(const char *name); +#endif + /* Set *fnames_out to a null-terminated list of filenames within dirname, * sorted according to strcmp(). Return 0 on success, or ENOENT/ENOMEM. */ int k5_dir_filenames(const char *dirname, char ***fnames_out); diff --git a/src/util/support/Makefile.in b/src/util/support/Makefile.in index db7b030b86..86d5a950a6 100644 --- a/src/util/support/Makefile.in +++ b/src/util/support/Makefile.in @@ -15,7 +15,7 @@ LIBBASE=krb5support LIBMAJOR=@SUPPORTLIB_MAJOR@ LIBMINOR=1 -LIBINITFUNC=krb5int_thread_support_init +LIBINITFUNC=krb5int_thread_support_init @SECURE_GETENV_INIT@ LIBFINIFUNC=krb5int_thread_support_fini GETTIMEOFDAY_ST_OBJ= @GETTIMEOFDAY_ST_OBJ@ @@ -53,6 +53,11 @@ GETOPT_LONG_OBJ= @GETOPT_LONG_OBJ@ ##DOS##GETOPT_LONG_ST_OBJ= getopt_long.o ##DOS##GETOPT_LONG_OBJ= $(OUTPRE)getopt_long.$(OBJEXT) +SECURE_GETENV_ST_OBJ= @SECURE_GETENV_ST_OBJ@ +SECURE_GETENV_OBJ= @SECURE_GETENV_OBJ@ +##DOS##SECURE_GETENV_ST_OBJ= +##DOS##SECURE_GETENV_OBJ= + IPC_ST_OBJ= IPC_OBJ= ##DOS##IPC_ST_OBJ= ipc_stream.o @@ -93,7 +98,8 @@ STLIBOBJS= \ $(PRINTF_ST_OBJ) \ $(MKSTEMP_ST_OBJ) \ $(GETOPT_ST_OBJ) \ - $(GETOPT_LONG_ST_OBJ) + $(GETOPT_LONG_ST_OBJ) \ + $(SECURE_GETENV_OBJ) LIBOBJS= \ $(OUTPRE)threads.$(OBJEXT) \ @@ -121,7 +127,8 @@ LIBOBJS= \ $(PRINTF_OBJ) \ $(MKSTEMP_OBJ) \ $(GETOPT_OBJ) \ - $(GETOPT_LONG_OBJ) + $(GETOPT_LONG_OBJ) \ + $(SECURE_GETENV_OBJ) SRCS=\ $(srcdir)/threads.c \ @@ -156,7 +163,8 @@ SRCS=\ $(srcdir)/t_utf8.c \ $(srcdir)/t_utf16.c \ $(srcdir)/getopt.c \ - $(srcdir)/getopt_long.c + $(srcdir)/getopt_long.c \ + $(srcdir)/secure_getenv.c SHLIB_EXPDEPS = # Add -lm if dumping thread stats, for sqrt. diff --git a/src/util/support/secure_getenv.c b/src/util/support/secure_getenv.c new file mode 100644 index 0000000000..6df05917cb --- /dev/null +++ b/src/util/support/secure_getenv.c @@ -0,0 +1,111 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* util/support/secure_getenv.c - secure_getenv() portability support */ +/* + * Copyright (C) 2019 by the Massachusetts Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This file contains the fallback implementation for secure_getenv(), which is + * currently only provided by glibc 2.17 and later. The goal is to ignore the + * environment if this process is (or previously was) running at elevated + * privilege compared to the calling process. + * + * In this fallback version we compare the real and effective uid/gid, and also + * compare the saved uid/gid if possible. These comparisons detect a setuid or + * setgid process which is still running with elevated privilege; if we can + * fetch the saved uid/gid, we also detect a process which has temporarily + * dropped privilege with seteuid() or setegid(). These comparisons do not + * detect the case where a setuid or setgid process has permanently dropped + * privilege before the library initializer ran; this is not ideal because such + * a process may possess a privileged resource or have privileged information + * in its address space. + * + * Heimdal also looks at the ELF aux vector in /proc/self/auxv to determine the + * starting uid/euid/gid/euid on Solaris/Illumos and NetBSD. On FreeBSD this + * approach can determine the executable path to do a stat() check. We do not + * go to this length due to the amount of code required. + * + * The BSDs and Solaris provide issetugid(), but the FreeBSD and NetBSD + * versions are not useful; they return true if a non-setuid/setgid executable + * is run by root and drops privilege, such as Apache httpd. We do not want to + * ignore the process environment in this case. + * + * On some platforms a process may have elevated privilege via mechanisms other + * than setuid/setgid. glibc's secure_getenv() should detect these cases on + * Linux; we do not detect them in this fallback version. + */ + +#include "k5-platform.h" + +static int elevated_privilege = 0; + +MAKE_INIT_FUNCTION(k5_secure_getenv_init); + +int +k5_secure_getenv_init() +{ + int saved_errno = errno; + +#ifdef HAVE_GETRESUID + { + uid_t r, e, s; + if (getresuid(&r, &e, &s) == 0) { + if (r != e || r != s) + elevated_privilege = 1; + } + } +#else + if (getuid() != geteuid()) + elevated_privilege = 1; +#endif + +#ifdef HAVE_GETRESGID + { + gid_t r, e, s; + if (!elevated_privilege && getresgid(&r, &e, &s) == 0) { + if (r != e || r != s) + elevated_privilege = 1; + } + } +#else + if (!elevated_privilege && getgid() != getegid()) + elevated_privilege = 1; +#endif + + errno = saved_errno; + return 0; +} + +char * +k5_secure_getenv(const char *name) +{ + if (CALL_INIT_FUNCTION(k5_secure_getenv_init) != 0) + return NULL; + return elevated_privilege ? NULL : getenv(name); +}