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