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