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