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