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: 30160149
TEST: make test-art-{host,target}

Change-Id: I887b78bdb21ab20855636a96da14a74c767bbfef
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index ddcfb6d..f3fcd34 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -26,6 +26,9 @@
 #include <signal.h>
 #include <sys/syscall.h>
 #include "base/memory_tool.h"
+#if defined(__APPLE__)
+#include <crt_externs.h>  // for _NSGetEnviron
+#endif
 
 #include <cstdio>
 #include <cstdlib>
@@ -156,6 +159,22 @@
   size_t trace_file_size;
 };
 
+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
+
 Runtime::Runtime()
     : resolution_method_(nullptr),
       imt_conflict_method_(nullptr),
@@ -904,6 +923,10 @@
 }
 
 bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
+  // (b/30160149): protect subprocesses from modifications to LD_LIBRARY_PATH, etc.
+  // Take a snapshot of the environment at the time the runtime was created, for use by Exec, etc.
+  env_snapshot_.TakeSnapshot();
+
   RuntimeArgumentMap runtime_options(std::move(runtime_options_in));
   ScopedTrace trace(__FUNCTION__);
   CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize);
@@ -2021,4 +2044,22 @@
   return (jit_ != nullptr) && jit_->UseJitCompilation();
 }
 
+void Runtime::EnvSnapshot::TakeSnapshot() {
+  char** env = GetEnviron();
+  for (size_t i = 0; env[i] != nullptr; ++i) {
+    name_value_pairs_.emplace_back(new std::string(env[i]));
+  }
+  // The strings in name_value_pairs_ retain ownership of the c_str, but we assign pointers
+  // for quick use by GetSnapshot.  This avoids allocation and copying cost at Exec.
+  c_env_vector_.reset(new char*[name_value_pairs_.size() + 1]);
+  for (size_t i = 0; env[i] != nullptr; ++i) {
+    c_env_vector_[i] = const_cast<char*>(name_value_pairs_[i]->c_str());
+  }
+  c_env_vector_[name_value_pairs_.size()] = nullptr;
+}
+
+char** Runtime::EnvSnapshot::GetSnapshot() const {
+  return c_env_vector_.get();
+}
+
 }  // namespace art