/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include "base/globals.h" #include "base/mem_map.h" #include "fault_handler.h" namespace art { class TestFaultHandler final : public FaultHandler { public: explicit TestFaultHandler(FaultManager* manager) : FaultHandler(manager), map_error_(), target_map_(MemMap::MapAnonymous("test-305-mmap", /* addr */ nullptr, /* byte_count */ kPageSize, /* prot */ PROT_NONE, /* low_4gb */ false, /* reuse */ false, /* reservation */ nullptr, /* error_msg */ &map_error_, /* use_ashmem */ false)), was_hit_(false) { CHECK(target_map_.IsValid()) << "Unable to create segfault target address " << map_error_; manager_->AddHandler(this, /*in_generated_code*/false); } virtual ~TestFaultHandler() { manager_->RemoveHandler(this); } bool Action(int sig, siginfo_t* siginfo, void* context ATTRIBUTE_UNUSED) override { CHECK_EQ(sig, SIGSEGV); CHECK_EQ(reinterpret_cast(siginfo->si_addr), GetTargetPointer()) << "Segfault on unexpected address!"; CHECK(!was_hit_) << "Recursive signal!"; was_hit_ = true; LOG(INFO) << "SEGV Caught. mprotecting map."; CHECK(target_map_.Protect(PROT_READ | PROT_WRITE)) << "Failed to mprotect R/W"; LOG(INFO) << "Setting value to be read."; *GetTargetPointer() = kDataValue; LOG(INFO) << "Changing prot to be read-only."; CHECK(target_map_.Protect(PROT_READ)) << "Failed to mprotect R-only"; return true; } void CauseSegfault() { CHECK_EQ(target_map_.GetProtect(), PROT_NONE); // This will segfault. The handler should deal with it though and we will get a value out of it. uint32_t data = *GetTargetPointer(); // Prevent re-ordering around the *GetTargetPointer by the compiler std::atomic_signal_fence(std::memory_order_seq_cst); CHECK(was_hit_); CHECK_EQ(data, kDataValue) << "Unexpected read value from mmap"; CHECK_EQ(target_map_.GetProtect(), PROT_READ); LOG(INFO) << "Success!"; } private: uint32_t* GetTargetPointer() { return reinterpret_cast(target_map_.Begin() + 8); } static constexpr uint32_t kDataValue = 0xDEADBEEF; std::string map_error_; MemMap target_map_; bool was_hit_; }; extern "C" JNIEXPORT void JNICALL Java_Main_runFaultHandlerTest(JNIEnv*, jclass) { std::unique_ptr handler(new TestFaultHandler(&fault_manager)); handler->CauseSegfault(); } } // namespace art