1/* 2 * Copyright (C) 2016 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#include <errno.h> 18#include <signal.h> 19#include <stdint.h> 20#include <stdlib.h> 21#include <string.h> 22#include <sys/mman.h> 23#include <sys/ptrace.h> 24#include <sys/types.h> 25#include <time.h> 26#include <unistd.h> 27 28#include <vector> 29 30#include <android-base/test_utils.h> 31#include <android-base/file.h> 32#include <gtest/gtest.h> 33 34#include "Memory.h" 35 36class MemoryRemoteTest : public ::testing::Test { 37 protected: 38 static uint64_t NanoTime() { 39 struct timespec t = { 0, 0 }; 40 clock_gettime(CLOCK_MONOTONIC, &t); 41 return static_cast<uint64_t>(t.tv_sec * NS_PER_SEC + t.tv_nsec); 42 } 43 44 static bool Attach(pid_t pid) { 45 if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) { 46 return false; 47 } 48 49 uint64_t start = NanoTime(); 50 siginfo_t si; 51 while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)) < 0 && errno == ESRCH) { 52 if ((NanoTime() - start) > 10 * NS_PER_SEC) { 53 printf("%d: Failed to stop after 10 seconds.\n", pid); 54 return false; 55 } 56 usleep(30); 57 } 58 return true; 59 } 60 61 static bool Detach(pid_t pid) { 62 return ptrace(PTRACE_DETACH, pid, 0, 0) == 0; 63 } 64 65 static constexpr size_t NS_PER_SEC = 1000000000ULL; 66}; 67 68TEST_F(MemoryRemoteTest, read) { 69 std::vector<uint8_t> src(1024); 70 memset(src.data(), 0x4c, 1024); 71 72 pid_t pid; 73 if ((pid = fork()) == 0) { 74 while (true); 75 exit(1); 76 } 77 ASSERT_LT(0, pid); 78 79 ASSERT_TRUE(Attach(pid)); 80 81 MemoryRemote remote(pid); 82 83 std::vector<uint8_t> dst(1024); 84 ASSERT_TRUE(remote.Read(reinterpret_cast<uint64_t>(src.data()), dst.data(), 1024)); 85 for (size_t i = 0; i < 1024; i++) { 86 ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i; 87 } 88 89 ASSERT_TRUE(Detach(pid)); 90 91 kill(pid, SIGKILL); 92} 93 94TEST_F(MemoryRemoteTest, read_fail) { 95 int pagesize = getpagesize(); 96 void* src = mmap(nullptr, pagesize * 2, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,-1, 0); 97 memset(src, 0x4c, pagesize * 2); 98 ASSERT_NE(MAP_FAILED, src); 99 // Put a hole right after the first page. 100 ASSERT_EQ(0, munmap(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(src) + pagesize), 101 pagesize)); 102 103 pid_t pid; 104 if ((pid = fork()) == 0) { 105 while (true); 106 exit(1); 107 } 108 ASSERT_LT(0, pid); 109 110 ASSERT_TRUE(Attach(pid)); 111 112 MemoryRemote remote(pid); 113 114 std::vector<uint8_t> dst(pagesize); 115 ASSERT_TRUE(remote.Read(reinterpret_cast<uint64_t>(src), dst.data(), pagesize)); 116 for (size_t i = 0; i < 1024; i++) { 117 ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i; 118 } 119 120 ASSERT_FALSE(remote.Read(reinterpret_cast<uint64_t>(src) + pagesize, dst.data(), 1)); 121 ASSERT_TRUE(remote.Read(reinterpret_cast<uint64_t>(src) + pagesize - 1, dst.data(), 1)); 122 ASSERT_FALSE(remote.Read(reinterpret_cast<uint64_t>(src) + pagesize - 4, dst.data(), 8)); 123 124 ASSERT_EQ(0, munmap(src, pagesize)); 125 126 ASSERT_TRUE(Detach(pid)); 127 128 kill(pid, SIGKILL); 129} 130 131TEST_F(MemoryRemoteTest, read_illegal) { 132 pid_t pid; 133 if ((pid = fork()) == 0) { 134 while (true); 135 exit(1); 136 } 137 ASSERT_LT(0, pid); 138 139 ASSERT_TRUE(Attach(pid)); 140 141 MemoryRemote remote(pid); 142 143 std::vector<uint8_t> dst(100); 144 ASSERT_FALSE(remote.Read(0, dst.data(), 1)); 145 ASSERT_FALSE(remote.Read(0, dst.data(), 100)); 146 147 ASSERT_TRUE(Detach(pid)); 148 149 kill(pid, SIGKILL); 150} 151