Save environment snapshot and use at fork/exec

Some applications may inadvertently or maliciously set of environment
variables such as LD_LIBRARY_PATH before spawning subprocesses.
To make this more difficult, save the environment at the time the
runtime starts and use the saved copy anytime Exec is called.

BUG=b/30160149
TEST=make test-art-{host,target}-gtest-utils_test

Change-Id: Ice0097bf0de30db3d4ead124caf93316f39e3df3
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 6a50b8e..fb6c1b3 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -56,6 +56,22 @@
 
 namespace art {
 
+namespace {
+#ifdef __APPLE__
+inline char** GetEnviron() {
+  // When Google Test is built as a framework on MacOS X, the environ variable
+  // is unavailable. Apple's documentation (man environ) recommends using
+  // _NSGetEnviron() instead.
+  return *_NSGetEnviron();
+}
+#else
+// Some POSIX platforms expect you to declare environ. extern "C" makes
+// it reside in the global namespace.
+extern "C" char** environ;
+inline char** GetEnviron() { return environ; }
+#endif
+}  // namespace
+
 #if defined(__linux__)
 static constexpr bool kUseAddr2line = !kIsTargetBuild;
 #endif
@@ -1393,6 +1409,15 @@
   return filename;
 }
 
+const EnvSnapshot* TakeEnvSnapshot() {
+  EnvSnapshot* snapshot = new EnvSnapshot();
+  char** env = GetEnviron();
+  for (size_t i = 0; env[i] != nullptr; ++i) {
+    snapshot->name_value_pairs_.emplace_back(new std::string(env[i]));
+  }
+  return snapshot;
+}
+
 int ExecAndReturnCode(std::vector<std::string>& arg_vector, std::string* error_msg) {
   const std::string command_line(Join(arg_vector, ' '));
   CHECK_GE(arg_vector.size(), 1U) << command_line;
@@ -1416,8 +1441,20 @@
     // change process groups, so we don't get reaped by ProcessManager
     setpgid(0, 0);
 
-    execv(program, &args[0]);
-    PLOG(ERROR) << "Failed to execv(" << command_line << ")";
+    // The child inherits the environment unless the caller overrides it.
+    if (Runtime::Current() == nullptr || Runtime::Current()->GetEnvSnapshot() == nullptr) {
+      execv(program, &args[0]);
+    } else {
+      const EnvSnapshot* saved_snapshot = Runtime::Current()->GetEnvSnapshot();
+      // Allocation between fork and exec is not well-behaved.  Use a variable-length array instead.
+      char* envp[saved_snapshot->name_value_pairs_.size() + 1];
+      for (size_t i = 0; i < saved_snapshot->name_value_pairs_.size(); ++i) {
+        envp[i] = const_cast<char*>(saved_snapshot->name_value_pairs_[i]->c_str());
+      }
+      envp[saved_snapshot->name_value_pairs_.size()] = nullptr;
+      execve(program, &args[0], envp);
+    }
+    PLOG(ERROR) << "Failed to execve(" << command_line << ")";
     // _exit to avoid atexit handlers in child.
     _exit(1);
   } else {