From f778eb275986811a3e1aba82d364b7e6a94678f3 Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Mon, 13 Apr 2015 14:17:09 -0700 Subject: [PATCH] ART: Add Security cutout to unstarted runtime This allows limited I/O in the compiler to read security.properties, which in turn allows to compile-time initialize Security, and thus Services and most of the providers. Bug: 19498458 Bug: 19542228 Change-Id: I853952b83ca99006907c070734f767259c975517 --- runtime/interpreter/unstarted_runtime.cc | 97 ++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc index 4fb634b66..9039e3c66 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -39,6 +39,7 @@ #include "thread.h" #include "transaction.h" #include "well_known_classes.h" +#include "zip_archive.h" namespace art { namespace interpreter { @@ -636,6 +637,100 @@ static void UnstartedMemoryPeekArrayEntry( } } +// This allows reading security.properties in an unstarted runtime and initialize Security. +static void UnstartedSecurityGetSecurityPropertiesReader( + Thread* self, + ShadowFrame* shadow_frame ATTRIBUTE_UNUSED, + JValue* result, + size_t arg_offset ATTRIBUTE_UNUSED) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + Runtime* runtime = Runtime::Current(); + const std::vector& path = runtime->GetClassLinker()->GetBootClassPath(); + std::string canonical(DexFile::GetDexCanonicalLocation(path[0]->GetLocation().c_str())); + mirror::String* string_data; + + // Use a block to enclose the I/O and MemMap code so buffers are released early. + { + std::string error_msg; + std::unique_ptr zip_archive(ZipArchive::Open(canonical.c_str(), &error_msg)); + if (zip_archive.get() == nullptr) { + AbortTransactionOrFail(self, "Could not open zip file %s: %s", canonical.c_str(), + error_msg.c_str()); + return; + } + std::unique_ptr zip_entry(zip_archive->Find("java/security/security.properties", + &error_msg)); + if (zip_entry.get() == nullptr) { + AbortTransactionOrFail(self, "Could not find security.properties file in %s: %s", + canonical.c_str(), error_msg.c_str()); + return; + } + std::unique_ptr map(zip_entry->ExtractToMemMap(canonical.c_str(), + "java/security/security.properties", + &error_msg)); + if (map.get() == nullptr) { + AbortTransactionOrFail(self, "Could not unzip security.properties file in %s: %s", + canonical.c_str(), error_msg.c_str()); + return; + } + + uint32_t length = zip_entry->GetUncompressedLength(); + std::unique_ptr tmp(new char[length + 1]); + memcpy(tmp.get(), map->Begin(), length); + tmp.get()[length] = 0; // null terminator + + string_data = mirror::String::AllocFromModifiedUtf8(self, tmp.get()); + } + + if (string_data == nullptr) { + AbortTransactionOrFail(self, "Could not create string from file content of %s", + canonical.c_str()); + return; + } + + // Create a StringReader. + StackHandleScope<3> hs(self); + Handle h_string(hs.NewHandle(string_data)); + + Handle h_class(hs.NewHandle( + runtime->GetClassLinker()->FindClass(self, + "Ljava/io/StringReader;", + NullHandle()))); + if (h_class.Get() == nullptr) { + AbortTransactionOrFail(self, "Could not find StringReader class"); + return; + } + + if (!runtime->GetClassLinker()->EnsureInitialized(self, h_class, true, true)) { + AbortTransactionOrFail(self, "Could not initialize StringReader class"); + return; + } + + Handle h_obj(hs.NewHandle(h_class->AllocObject(self))); + if (h_obj.Get() == nullptr) { + AbortTransactionOrFail(self, "Could not allocate StringReader object"); + return; + } + + mirror::ArtMethod* constructor = h_class->FindDeclaredDirectMethod("", + "(Ljava/lang/String;)V"); + if (constructor == nullptr) { + AbortTransactionOrFail(self, "Could not find StringReader constructor"); + return; + } + + uint32_t args[1]; + args[0] = static_cast(reinterpret_cast(h_string.Get())); + EnterInterpreterFromInvoke(self, constructor, h_obj.Get(), args, nullptr); + + if (self->IsExceptionPending()) { + AbortTransactionOrFail(self, "Could not run StringReader constructor"); + return; + } + + result->SetL(h_obj.Get()); +} + static void UnstartedJNIVMRuntimeNewUnpaddedArray(Thread* self, mirror::ArtMethod* method ATTRIBUTE_UNUSED, mirror::Object* receiver ATTRIBUTE_UNUSED, @@ -958,6 +1053,8 @@ static void UnstartedRuntimeInitializeInvokeHandlers() { &UnstartedMemoryPeekEntry }, { "void libcore.io.Memory.peekByteArray(long, byte[], int, int)", &UnstartedMemoryPeekArrayEntry }, + { "java.io.Reader java.security.Security.getSecurityPropertiesReader()", + &UnstartedSecurityGetSecurityPropertiesReader }, }; for (auto& def : defs) { -- 2.11.0