xref: /aosp_15_r20/system/core/trusty/coverage/coverage.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
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