summaryrefslogtreecommitdiff
path: root/runtime/fault_handler.cc
diff options
context:
space:
mode:
author Josh Gao <jmgao@google.com> 2017-04-17 20:10:29 -0700
committer Josh Gao <jmgao@google.com> 2017-04-19 10:48:47 -0700
commit143f61c29e77328e19bcdba3cc94df7334c40358 (patch)
treee1116ca3ad55f10bef00e07730c9326308f1bd08 /runtime/fault_handler.cc
parent91119d69f0736f6dbd350c433632af2618c7575a (diff)
fault_handler: use SafeCopy to verify the validity of ArtMethod.
Reimplement ArtMethod::GetDeclaringClassUnchecked and VerifyClassClass in terms of SafeCopy, to be able to safely verify the validity of putative ArtMethods in FaultManager::IsInGeneratedCode. Bug: http://b/30836730 Test: m test-art-host Change-Id: Ie3d5e176ea569cedcefd320e2480a1e1e496a53a
Diffstat (limited to 'runtime/fault_handler.cc')
-rw-r--r--runtime/fault_handler.cc83
1 files changed, 79 insertions, 4 deletions
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index 4220250c38..4ef3a67b96 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -21,8 +21,10 @@
#include <sys/ucontext.h>
#include "art_method-inl.h"
+#include "base/safe_copy.h"
#include "base/stl_util.h"
#include "mirror/class.h"
+#include "mirror/object_reference.h"
#include "oat_quick_method_header.h"
#include "sigchain.h"
#include "thread-inl.h"
@@ -42,6 +44,80 @@ static bool art_fault_handler(int sig, siginfo_t* info, void* context) {
return fault_manager.HandleFault(sig, info, context);
}
+#if defined(__linux__)
+
+// Change to verify the safe implementations against the original ones.
+constexpr bool kVerifySafeImpls = false;
+
+// Provide implementations of ArtMethod::GetDeclaringClass and VerifyClassClass that use SafeCopy
+// to safely dereference pointers which are potentially garbage.
+// Only available on Linux due to availability of SafeCopy.
+
+static mirror::Class* SafeGetDeclaringClass(ArtMethod* method)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ char* method_declaring_class =
+ reinterpret_cast<char*>(method) + ArtMethod::DeclaringClassOffset().SizeValue();
+
+ // ArtMethod::declaring_class_ is a GcRoot<mirror::Class>.
+ // Read it out into as a CompressedReference directly for simplicity's sake.
+ mirror::CompressedReference<mirror::Class> cls;
+ ssize_t rc = SafeCopy(&cls, method_declaring_class, sizeof(cls));
+ CHECK_NE(-1, rc);
+
+ if (kVerifySafeImpls) {
+ mirror::Class* actual_class = method->GetDeclaringClassUnchecked<kWithoutReadBarrier>();
+ CHECK_EQ(actual_class, cls.AsMirrorPtr());
+ }
+
+ if (rc != sizeof(cls)) {
+ return nullptr;
+ }
+
+ return cls.AsMirrorPtr();
+}
+
+static mirror::Class* SafeGetClass(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
+ char* obj_cls = reinterpret_cast<char*>(obj) + mirror::Object::ClassOffset().SizeValue();
+
+ mirror::CompressedReference<mirror::Class> cls;
+ ssize_t rc = SafeCopy(&cls, obj_cls, sizeof(cls));
+ CHECK_NE(-1, rc);
+
+ if (kVerifySafeImpls) {
+ mirror::Class* actual_class = obj->GetClass<kVerifyNone>();
+ CHECK_EQ(actual_class, cls.AsMirrorPtr());
+ }
+
+ if (rc != sizeof(cls)) {
+ return nullptr;
+ }
+
+ return cls.AsMirrorPtr();
+}
+
+static bool SafeVerifyClassClass(mirror::Class* cls) REQUIRES_SHARED(Locks::mutator_lock_) {
+ mirror::Class* c_c = SafeGetClass(cls);
+ bool result = c_c != nullptr && c_c == SafeGetClass(c_c);
+
+ if (kVerifySafeImpls) {
+ CHECK_EQ(VerifyClassClass(cls), result);
+ }
+
+ return result;
+}
+
+#else
+
+static mirror::Class* SafeGetDeclaringClass(ArtMethod* method_obj) {
+ return method_obj->GetDeclaringClassUnchecked<kWithoutReadBarrier>();
+}
+
+static bool SafeVerifyClassClass(ArtClass* cls) {
+ return VerifyClassClass(cls);
+}
+#endif
+
+
FaultManager::FaultManager() : initialized_(false) {
sigaction(SIGSEGV, nullptr, &oldaction_);
}
@@ -191,20 +267,19 @@ bool FaultManager::IsInGeneratedCode(siginfo_t* siginfo, void* context, bool che
// Verify that the potential method is indeed a method.
// TODO: check the GC maps to make sure it's an object.
// Check that the class pointer inside the object is not null and is aligned.
- // TODO: Method might be not a heap address, and GetClass could fault.
// No read barrier because method_obj may not be a real object.
- mirror::Class* cls = method_obj->GetDeclaringClassUnchecked<kWithoutReadBarrier>();
+ mirror::Class* cls = SafeGetDeclaringClass(method_obj);
if (cls == nullptr) {
VLOG(signals) << "not a class";
return false;
}
+
if (!IsAligned<kObjectAlignment>(cls)) {
VLOG(signals) << "not aligned";
return false;
}
-
- if (!VerifyClassClass(cls)) {
+ if (!SafeVerifyClassClass(cls)) {
VLOG(signals) << "not a class class";
return false;
}