diff options
author | Jed Davis <jld@mozilla.com> | 2016-01-29 11:46:27 +0100 |
---|---|---|
committer | Jed Davis <jld@mozilla.com> | 2016-01-29 11:46:27 +0100 |
commit | 55e985c0e84a0e066f1fbaca67ba9c11cee022dd (patch) | |
tree | 269cd692cd49511b29d97d92d230a77921bb0119 | |
parent | 114ef8ab0c411f0d742ec275e10c0c0d724e9ff3 (diff) | |
download | nspr-hg-55e985c0e84a0e066f1fbaca67ba9c11cee022dd.tar.gz |
Bug 1194678 - Add PR_GetEnvSecure. r=tedNSPR_4_12_BETA1
-rwxr-xr-x | configure | 2 | ||||
-rw-r--r-- | configure.in | 3 | ||||
-rw-r--r-- | pr/include/prenv.h | 14 | ||||
-rw-r--r-- | pr/src/io/prlog.c | 8 | ||||
-rw-r--r-- | pr/src/misc/prenv.c | 35 | ||||
-rw-r--r-- | pr/src/misc/prtrace.c | 8 | ||||
-rw-r--r-- | pr/src/nspr.def | 1 | ||||
-rw-r--r-- | pr/tests/env.c | 38 |
8 files changed, 92 insertions, 17 deletions
@@ -7890,7 +7890,7 @@ fi _SAVE_LIBS="$LIBS" LIBS="$LIBS $OS_LIBS" -for ac_func in dladdr gettid lchown setpriority strerror syscall +for ac_func in dladdr gettid lchown setpriority strerror syscall secure_getenv __secure_getenv do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/configure.in b/configure.in index c408d3e9..2ab23833 100644 --- a/configure.in +++ b/configure.in @@ -2539,7 +2539,8 @@ dnl ======================================================== AC_PROG_GCC_TRADITIONAL _SAVE_LIBS="$LIBS" LIBS="$LIBS $OS_LIBS" -AC_CHECK_FUNCS(dladdr gettid lchown setpriority strerror syscall) +AC_CHECK_FUNCS(dladdr gettid lchown setpriority strerror syscall dnl + secure_getenv __secure_getenv) LIBS="$_SAVE_LIBS" dnl ======================================================== diff --git a/pr/include/prenv.h b/pr/include/prenv.h index 2a477167..468c7d59 100644 --- a/pr/include/prenv.h +++ b/pr/include/prenv.h @@ -91,6 +91,20 @@ PR_BEGIN_EXTERN_C NSPR_API(char*) PR_GetEnv(const char *var); /* +** PR_GetEnvSecure() -- get a security-sensitive environment variable +** +** Description: +** +** PR_GetEnvSecure() is similar to PR_GetEnv(), but it returns NULL if +** the program was run with elevated privilege (e.g., setuid or setgid +** on Unix). This can be used for cases like log file paths which +** could otherwise be used for privilege escalation. Note that some +** platforms may have platform-specific privilege elevation mechanisms +** not recognized by this function; see the implementation for details. +*/ +NSPR_API(char*) PR_GetEnvSecure(const char *var); + +/* ** PR_SetEnv() -- set, unset or change an environment variable ** ** Description: diff --git a/pr/src/io/prlog.c b/pr/src/io/prlog.c index dae80282..6098460e 100644 --- a/pr/src/io/prlog.c +++ b/pr/src/io/prlog.c @@ -238,13 +238,7 @@ void _PR_InitLog(void) } PR_SetLogBuffering(isSync ? 0 : bufSize); -#ifdef XP_UNIX - if ((getuid() != geteuid()) || (getgid() != getegid())) { - return; - } -#endif /* XP_UNIX */ - - ev = PR_GetEnv("NSPR_LOG_FILE"); + ev = PR_GetEnvSecure("NSPR_LOG_FILE"); if (ev && ev[0]) { if (!PR_SetLogFile(ev)) { #ifdef XP_PC diff --git a/pr/src/misc/prenv.c b/pr/src/misc/prenv.c index 4935f9dc..cc2e198b 100644 --- a/pr/src/misc/prenv.c +++ b/pr/src/misc/prenv.c @@ -4,10 +4,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include <string.h> +#include <stdlib.h> #include "primpl.h" #include "prmem.h" #if defined(XP_UNIX) +#include <unistd.h> #if defined(DARWIN) #if defined(HAVE_CRT_EXTERNS_H) #include <crt_externs.h> @@ -17,6 +19,11 @@ PR_IMPORT_DATA(char **) environ; #endif /* DARWIN */ #endif /* XP_UNIX */ +#if !defined(HAVE_SECURE_GETENV) && defined(HAVE___SECURE_GETENV) +#define secure_getenv __secure_getenv +#define HAVE_SECURE_GETENV 1 +#endif + /* Lock used to lock the environment */ #if defined(_PR_NO_PREEMPT) #define _PR_NEW_LOCK_ENV() @@ -63,6 +70,34 @@ PR_IMPLEMENT(char*) PR_GetEnv(const char *var) return ev; } +PR_IMPLEMENT(char*) PR_GetEnvSecure(const char *var) +{ +#ifdef HAVE_SECURE_GETENV + char *ev; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + _PR_LOCK_ENV(); + ev = secure_getenv(var); + _PR_UNLOCK_ENV(); + + return ev; +#else +#ifdef XP_UNIX + /* + ** Fall back to checking uids and gids. This won't detect any other + ** privilege-granting mechanisms the platform may have. This also + ** can't detect the case where the process already called + ** setuid(geteuid()) and/or setgid(getegid()). + */ + if (getuid() != geteuid() || getgid() != getegid()) { + return NULL; + } +#endif /* XP_UNIX */ + return PR_GetEnv(var); +#endif /* HAVE_SECURE_GETENV */ +} + PR_IMPLEMENT(PRStatus) PR_SetEnv(const char *string) { PRIntn result; diff --git a/pr/src/misc/prtrace.c b/pr/src/misc/prtrace.c index e1b456c7..058f700b 100644 --- a/pr/src/misc/prtrace.c +++ b/pr/src/misc/prtrace.c @@ -657,14 +657,8 @@ static PRFileDesc * InitializeRecording( void ) logLostData = 0; /* reset at entry */ logState = LogReset; -#ifdef XP_UNIX - if ((getuid() != geteuid()) || (getgid() != getegid())) { - return NULL; - } -#endif /* XP_UNIX */ - /* Get the filename for the logfile from the environment */ - logFileName = PR_GetEnv( "NSPR_TRACE_LOG" ); + logFileName = PR_GetEnvSecure( "NSPR_TRACE_LOG" ); if ( logFileName == NULL ) { PR_LOG( lm, PR_LOG_ERROR, diff --git a/pr/src/nspr.def b/pr/src/nspr.def index edd6b322..726979ba 100644 --- a/pr/src/nspr.def +++ b/pr/src/nspr.def @@ -460,4 +460,5 @@ EXPORTS ;- ;+NSPR_4.12 { ;+ global: PR_DuplicateEnvironment; + PR_GetEnvSecure; ;+} NSPR_4.10.3; diff --git a/pr/tests/env.c b/pr/tests/env.c index 720c0c40..c11588d6 100644 --- a/pr/tests/env.c +++ b/pr/tests/env.c @@ -18,6 +18,7 @@ PRIntn debug = 0; PRIntn verbose = 0; +PRIntn secure = 0; PRBool failedAlready = PR_FALSE; #define ENVNAME "NSPR_ENVIRONMENT_TEST_VARIABLE" @@ -43,7 +44,7 @@ int main(int argc, char **argv) { /* Get command line options */ PLOptStatus os; - PLOptState *opt = PL_CreateOptState(argc, argv, "vd"); + PLOptState *opt = PL_CreateOptState(argc, argv, "vds"); while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { @@ -56,6 +57,15 @@ int main(int argc, char **argv) case 'v': /* verbose */ verbose = 1; break; + case 's': /* secure / set[ug]id */ + /* + ** To test PR_GetEnvSecure, make this executable (or a + ** copy of it) setuid / setgid / otherwise inherently + ** privileged (e.g., file capabilities) and run it + ** with this flag. + */ + secure = 1; + break; default: break; } @@ -113,6 +123,32 @@ int main(int argc, char **argv) if (verbose) printf("env: PR_GetEnv() worked after setting it. Found: %s\n", value ); } + if ( secure ) { + /* + ** In this case we've been run with elevated privileges, so + ** test that PR_GetEnvSecure *doesn't* find that env var. + */ + value = PR_GetEnvSecure( ENVNAME ); + if ( NULL != value ) { + if (debug) printf( "env: PR_GetEnvSecure() failed; expected NULL, found \"%s\"\n", value ); + failedAlready = PR_TRUE; + } else { + if (verbose) printf("env: PR_GetEnvSecure() worked\n" ); + } + } else { + /* + ** In this case the program is being run normally, so do the + ** same check for PR_GetEnvSecure as for PR_GetEnv. + */ + value = PR_GetEnvSecure( ENVNAME ); + if ( (NULL == value ) || (strcmp( value, ENVVALUE))) { + if (debug) printf( "env: PR_GetEnvSecure() Failed after setting\n" ); + failedAlready = PR_TRUE; + } else { + if (verbose) printf("env: PR_GetEnvSecure() worked after setting it. Found: %s\n", value ); + } + } + /* ---------------------------------------------------------------------- */ /* check that PR_DuplicateEnvironment() agrees with PR_GetEnv() */ { |