summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJed Davis <jld@mozilla.com>2016-01-29 11:46:27 +0100
committerJed Davis <jld@mozilla.com>2016-01-29 11:46:27 +0100
commit55e985c0e84a0e066f1fbaca67ba9c11cee022dd (patch)
tree269cd692cd49511b29d97d92d230a77921bb0119
parent114ef8ab0c411f0d742ec275e10c0c0d724e9ff3 (diff)
downloadnspr-hg-55e985c0e84a0e066f1fbaca67ba9c11cee022dd.tar.gz
Bug 1194678 - Add PR_GetEnvSecure. r=tedNSPR_4_12_BETA1
-rwxr-xr-xconfigure2
-rw-r--r--configure.in3
-rw-r--r--pr/include/prenv.h14
-rw-r--r--pr/src/io/prlog.c8
-rw-r--r--pr/src/misc/prenv.c35
-rw-r--r--pr/src/misc/prtrace.c8
-rw-r--r--pr/src/nspr.def1
-rw-r--r--pr/tests/env.c38
8 files changed, 92 insertions, 17 deletions
diff --git a/configure b/configure
index ba821b8d..0ff06ecf 100755
--- a/configure
+++ b/configure
@@ -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() */
{