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