1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 18 #include <atomic> 19 #include <memory> 20 21 #include <jni.h> 22 #include <signal.h> 23 #include <stdint.h> 24 #include <sys/mman.h> 25 26 #include "fault_handler.h" 27 #include "globals.h" 28 #include "mem_map.h" 29 30 namespace art { 31 32 class TestFaultHandler FINAL : public FaultHandler { 33 public: 34 explicit TestFaultHandler(FaultManager* manager) 35 : FaultHandler(manager), 36 map_error_(""), 37 target_map_(MemMap::MapAnonymous("test-305-mmap", 38 /* addr */ nullptr, 39 /* byte_count */ kPageSize, 40 /* prot */ PROT_NONE, 41 /* low_4gb */ false, 42 /* reuse */ false, 43 /* error_msg */ &map_error_, 44 /* use_ashmem */ false)), 45 was_hit_(false) { 46 CHECK(target_map_ != nullptr) << "Unable to create segfault target address " << map_error_; 47 manager_->AddHandler(this, /*in_generated_code*/false); 48 } 49 50 virtual ~TestFaultHandler() { 51 manager_->RemoveHandler(this); 52 } 53 54 bool Action(int sig, siginfo_t* siginfo, void* context ATTRIBUTE_UNUSED) OVERRIDE { 55 CHECK_EQ(sig, SIGSEGV); 56 CHECK_EQ(reinterpret_cast<uint32_t*>(siginfo->si_addr), 57 GetTargetPointer()) << "Segfault on unexpected address!"; 58 CHECK(!was_hit_) << "Recursive signal!"; 59 was_hit_ = true; 60 61 LOG(INFO) << "SEGV Caught. mprotecting map."; 62 CHECK(target_map_->Protect(PROT_READ | PROT_WRITE)) << "Failed to mprotect R/W"; 63 LOG(INFO) << "Setting value to be read."; 64 *GetTargetPointer() = kDataValue; 65 LOG(INFO) << "Changing prot to be read-only."; 66 CHECK(target_map_->Protect(PROT_READ)) << "Failed to mprotect R-only"; 67 return true; 68 } 69 70 void CauseSegfault() { 71 CHECK_EQ(target_map_->GetProtect(), PROT_NONE); 72 73 // This will segfault. The handler should deal with it though and we will get a value out of it. 74 uint32_t data = *GetTargetPointer(); 75 76 // Prevent re-ordering around the *GetTargetPointer by the compiler 77 std::atomic_signal_fence(std::memory_order_seq_cst); 78 79 CHECK(was_hit_); 80 CHECK_EQ(data, kDataValue) << "Unexpected read value from mmap"; 81 CHECK_EQ(target_map_->GetProtect(), PROT_READ); 82 LOG(INFO) << "Success!"; 83 } 84 85 private: 86 uint32_t* GetTargetPointer() { 87 return reinterpret_cast<uint32_t*>(target_map_->Begin() + 8); 88 } 89 90 static constexpr uint32_t kDataValue = 0xDEADBEEF; 91 92 std::string map_error_; 93 std::unique_ptr<MemMap> target_map_; 94 bool was_hit_; 95 }; 96 97 extern "C" JNIEXPORT void JNICALL Java_Main_runFaultHandlerTest(JNIEnv*, jclass) { 98 std::unique_ptr<TestFaultHandler> handler(new TestFaultHandler(&fault_manager)); 99 handler->CauseSegfault(); 100 } 101 102 } // namespace art 103