1 /*
2 * Copyright (C) 2020 The Android Open Sourete 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 #define LOG_TAG "coverage"
18
19 #include <BufferAllocator/BufferAllocator.h>
20 #include <android-base/file.h>
21 #include <android-base/logging.h>
22 #include <android-base/unique_fd.h>
23 #include <assert.h>
24 #include <log/log.h>
25 #include <stdio.h>
26 #include <sys/mman.h>
27 #include <sys/uio.h>
28 #include <trusty/coverage/coverage.h>
29 #include <trusty/coverage/record.h>
30 #include <trusty/coverage/tipc.h>
31 #include <trusty/tipc.h>
32 #include <iostream>
33
34 #define COVERAGE_CLIENT_PORT "com.android.trusty.coverage.client"
35
36 namespace android {
37 namespace trusty {
38 namespace coverage {
39
40 using android::base::ErrnoError;
41 using android::base::Error;
42 using std::string;
43 using std::to_string;
44 using std::unique_ptr;
45
CoverageRecord(string tipc_dev,struct uuid * uuid)46 CoverageRecord::CoverageRecord(string tipc_dev, struct uuid* uuid)
47 : tipc_dev_(std::move(tipc_dev)),
48 coverage_srv_fd_(-1),
49 uuid_(*uuid),
50 sancov_filename_(),
51 record_len_(0),
52 shm_(NULL),
53 shm_len_(0) {}
54
CoverageRecord(string tipc_dev,struct uuid * uuid,string module_name)55 CoverageRecord::CoverageRecord(string tipc_dev, struct uuid* uuid, string module_name)
56 : tipc_dev_(std::move(tipc_dev)),
57 coverage_srv_fd_(-1),
58 uuid_(*uuid),
59 sancov_filename_(module_name + "." + to_string(getpid()) + ".sancov"),
60 record_len_(0),
61 shm_(NULL),
62 shm_len_(0) {}
63
~CoverageRecord()64 CoverageRecord::~CoverageRecord() {
65 if (shm_) {
66 if (sancov_filename_) {
67 auto res = SaveSancovFile(*sancov_filename_);
68 if (!res.ok()) {
69 ALOGE("Could not write sancov file for module: %s\n", sancov_filename_->c_str());
70 }
71 }
72
73 munmap((void*)shm_, shm_len_);
74 }
75 }
76
Rpc(coverage_client_req * req,int req_fd,coverage_client_resp * resp)77 Result<void> CoverageRecord::Rpc(coverage_client_req* req, int req_fd, coverage_client_resp* resp) {
78 int rc;
79
80 if (req_fd < 0) {
81 rc = write(coverage_srv_fd_, req, sizeof(*req));
82 } else {
83 iovec iov = {
84 .iov_base = req,
85 .iov_len = sizeof(*req),
86 };
87
88 trusty_shm shm = {
89 .fd = req_fd,
90 .transfer = TRUSTY_SHARE,
91 };
92
93 rc = tipc_send(coverage_srv_fd_, &iov, 1, &shm, 1);
94 }
95
96 if (rc != (int)sizeof(*req)) {
97 return ErrnoError() << "failed to send request to coverage server: ";
98 }
99
100 rc = read(coverage_srv_fd_, resp, sizeof(*resp));
101 if (rc != (int)sizeof(*resp)) {
102 return ErrnoError() << "failed to read reply from coverage server: ";
103 }
104
105 if (resp->hdr.cmd != (req->hdr.cmd | COVERAGE_CLIENT_CMD_RESP_BIT)) {
106 return ErrnoError() << "unknown response cmd: " << resp->hdr.cmd;
107 }
108
109 return {};
110 }
111
Open()112 Result<void> CoverageRecord::Open() {
113 coverage_client_req req;
114 coverage_client_resp resp;
115
116 if (shm_) {
117 return {}; /* already initialized */
118 }
119
120 int fd = tipc_connect(tipc_dev_.c_str(), COVERAGE_CLIENT_PORT);
121 if (fd < 0) {
122 // Don't error out to support fuzzing builds without coverage, e.g. for repros.
123 std::cerr << "WARNING!!! Failed to connect to Trusty coverarge server." << std::endl;
124 return {};
125 }
126 coverage_srv_fd_.reset(fd);
127
128 req.hdr.cmd = COVERAGE_CLIENT_CMD_OPEN;
129 req.open_args.uuid = uuid_;
130 auto ret = Rpc(&req, -1, &resp);
131 if (!ret.ok()) {
132 return Error() << "failed to open coverage client: " << ret.error();
133 }
134 record_len_ = resp.open_args.record_len;
135 shm_len_ = record_len_;
136
137 BufferAllocator allocator;
138
139 fd = allocator.Alloc("system", shm_len_);
140 if (fd < 0) {
141 return ErrnoError() << "failed to create dmabuf of size " << shm_len_
142 << " err code: " << fd;
143 }
144 unique_fd dma_buf(fd);
145
146 void* shm = mmap(0, shm_len_, PROT_READ | PROT_WRITE, MAP_SHARED, dma_buf, 0);
147 if (shm == MAP_FAILED) {
148 return ErrnoError() << "failed to map memfd: ";
149 }
150
151 req.hdr.cmd = COVERAGE_CLIENT_CMD_SHARE_RECORD;
152 req.share_record_args.shm_len = shm_len_;
153 ret = Rpc(&req, dma_buf, &resp);
154 if (!ret.ok()) {
155 return Error() << "failed to send shared memory: " << ret.error();
156 }
157
158 shm_ = shm;
159 return {};
160 }
161
IsOpen()162 bool CoverageRecord::IsOpen() {
163 return shm_;
164 }
165
ResetFullRecord()166 void CoverageRecord::ResetFullRecord() {
167 auto header_region = GetRegionBounds(COV_START);
168 if (!header_region.ok()) {
169 // If the header cannot be parsed, we can't reset the proper region yet.
170 return;
171 }
172
173 for (size_t i = header_region->second; i < shm_len_; i++) {
174 *((volatile uint8_t*)shm_ + i) = 0;
175 }
176 }
177
ResetCounts()178 void CoverageRecord::ResetCounts() {
179 volatile uint8_t* begin = nullptr;
180 volatile uint8_t* end = nullptr;
181 GetRawCounts(&begin, &end);
182
183 for (volatile uint8_t* x = begin; x < end; x++) {
184 *x = 0;
185 }
186 }
187
ResetPCs()188 void CoverageRecord::ResetPCs() {
189 volatile uintptr_t* begin = nullptr;
190 volatile uintptr_t* end = nullptr;
191 GetRawPCs(&begin, &end);
192
193 for (volatile uintptr_t* x = begin; x < end; x++) {
194 *x = 0;
195 }
196 }
197
GetRegionBounds(uint32_t region_type)198 Result<std::pair<size_t, size_t>> CoverageRecord::GetRegionBounds(uint32_t region_type) {
199 assert(shm_);
200
201 auto header = (volatile struct coverage_record_header*)shm_;
202
203 if (header->type != COV_START) {
204 return Error() << "Header not yet valid";
205 }
206
207 for (++header; header->type != COV_TOTAL_LENGTH; ++header) {
208 if (header->type == region_type) {
209 // Coverage record must end with a COV_TOTAL_LENGTH header entry, so
210 // it is always safe to read the next entry since we don't iterate
211 // over the COV_TOTAL_LENGTH entry.
212 return {{header->offset, (header + 1)->offset}};
213 }
214 }
215
216 return Error() << "Could not find coverage region type: " << region_type;
217 }
218
GetRawData(volatile void ** begin,volatile void ** end)219 void CoverageRecord::GetRawData(volatile void** begin, volatile void** end) {
220 assert(shm_);
221
222 *begin = shm_;
223 *end = (uint8_t*)(*begin) + record_len_;
224 }
225
GetRawCounts(volatile uint8_t ** begin,volatile uint8_t ** end)226 void CoverageRecord::GetRawCounts(volatile uint8_t** begin, volatile uint8_t** end) {
227 auto region = GetRegionBounds(COV_8BIT_COUNTERS);
228 if (!region.ok()) {
229 *begin = 0;
230 *end = 0;
231 return;
232 }
233
234 assert(region->second <= record_len_);
235
236 *begin = (volatile uint8_t*)shm_ + region->first;
237 *end = (volatile uint8_t*)shm_ + region->second;
238 }
239
GetRawPCs(volatile uintptr_t ** begin,volatile uintptr_t ** end)240 void CoverageRecord::GetRawPCs(volatile uintptr_t** begin, volatile uintptr_t** end) {
241 auto region = GetRegionBounds(COV_INSTR_PCS);
242 if (!region.ok()) {
243 *begin = 0;
244 *end = 0;
245 return;
246 }
247
248 assert(region->second <= record_len_);
249
250 *begin = (volatile uintptr_t*)((volatile uint8_t*)shm_ + region->first);
251 *end = (volatile uintptr_t*)((volatile uint8_t*)shm_ + region->second);
252 }
253
TotalEdgeCounts()254 uint64_t CoverageRecord::TotalEdgeCounts() {
255 assert(shm_);
256
257 uint64_t counter = 0;
258
259 volatile uint8_t* begin = NULL;
260 volatile uint8_t* end = NULL;
261
262 GetRawCounts(&begin, &end);
263
264 for (volatile uint8_t* x = begin; x < end; x++) {
265 counter += *x;
266 }
267
268 return counter;
269 }
270
SaveSancovFile(const std::string & filename)271 Result<void> CoverageRecord::SaveSancovFile(const std::string& filename) {
272 android::base::unique_fd output_fd(TEMP_FAILURE_RETRY(creat(filename.c_str(), 00644)));
273 if (!output_fd.ok()) {
274 return ErrnoError() << "Could not open sancov file";
275 }
276
277 uint64_t magic;
278 if (sizeof(uintptr_t) == 8) {
279 magic = 0xC0BFFFFFFFFFFF64;
280 } else if (sizeof(uintptr_t) == 4) {
281 magic = 0xC0BFFFFFFFFFFF32;
282 }
283 WriteFully(output_fd, &magic, sizeof(magic));
284
285 volatile uintptr_t* begin = nullptr;
286 volatile uintptr_t* end = nullptr;
287
288 GetRawPCs(&begin, &end);
289
290 for (volatile uintptr_t* pc_ptr = begin; pc_ptr < end; pc_ptr++) {
291 uintptr_t pc = *pc_ptr;
292 if (pc) {
293 WriteFully(output_fd, &pc, sizeof(pc));
294 }
295 }
296
297 return {};
298 }
299
300 } // namespace coverage
301 } // namespace trusty
302 } // namespace android
303