1 /*
2  * Copyright (C) 2023 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 "line-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/line-coverage/coverage.h>
29 #include <trusty/line-coverage/tipc.h>
30 #include <trusty/tipc.h>
31 #include <iostream>
32 
33 #define LINE_COVERAGE_CLIENT_PORT "com.android.trusty.linecoverage.client"
34 
35 struct control {
36     /* Written by controller, read by instrumented TA */
37     uint64_t        cntrl_flags;
38 
39     /* Written by instrumented TA, read by controller */
40     uint64_t        oper_flags;
41     uint64_t        write_buffer_start_count;
42     uint64_t        write_buffer_complete_count;
43 };
44 
45 namespace android {
46 namespace trusty {
47 namespace line_coverage {
48 
49 using ::android::base::ErrnoError;
50 using ::android::base::Error;
51 using ::std::string;
52 
CoverageRecord(string tipc_dev,struct uuid * uuid)53 CoverageRecord::CoverageRecord(string tipc_dev, struct uuid* uuid)
54     : tipc_dev_(std::move(tipc_dev)),
55       coverage_srv_fd_(-1),
56       uuid_(*uuid),
57       record_len_(0),
58       shm_(NULL),
59       shm_len_(0) {}
60 
~CoverageRecord()61 CoverageRecord::~CoverageRecord() {
62     if (shm_) {
63         munmap((void*)shm_, shm_len_);
64     }
65 }
66 
getShm()67 volatile void *CoverageRecord::getShm() {
68     if(!IsOpen()) {
69         fprintf(stderr, "Warning! SHM is NULL!\n");
70     }
71     return shm_;
72 }
73 
Rpc(struct line_coverage_client_req * req,int req_fd,struct line_coverage_client_resp * resp)74 Result<void> CoverageRecord::Rpc(struct line_coverage_client_req* req, \
75                                   int req_fd, \
76                                   struct line_coverage_client_resp* resp) {
77     int rc;
78 
79     if (req_fd < 0) {
80         rc = write(coverage_srv_fd_, req, sizeof(*req));
81     } else {
82         iovec iov = {
83                 .iov_base = req,
84                 .iov_len = sizeof(*req),
85         };
86 
87         trusty_shm shm = {
88                 .fd = req_fd,
89                 .transfer = TRUSTY_SHARE,
90         };
91 
92         rc = tipc_send(coverage_srv_fd_, &iov, 1, &shm, 1);
93     }
94 
95     if (rc != (int)sizeof(*req)) {
96         return ErrnoError() << "failed to send request to coverage server: ";
97     }
98 
99     rc = read(coverage_srv_fd_, resp, sizeof(*resp));
100     if (rc != (int)sizeof(*resp)) {
101         return ErrnoError() << "failed to read reply from coverage server: ";
102     }
103 
104     if (resp->hdr.cmd != (req->hdr.cmd | LINE_COVERAGE_CLIENT_CMD_RESP_BIT)) {
105         return ErrnoError() << "unknown response cmd: " << resp->hdr.cmd;
106     }
107 
108     return {};
109 }
110 
Open(int fd)111 Result<void> CoverageRecord::Open(int fd) {
112     struct line_coverage_client_req req;
113     struct line_coverage_client_resp resp;
114 
115     if (shm_) {
116         return {}; /* already initialized */
117     }
118 
119     coverage_srv_fd_= fd;
120 
121     req.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_OPEN;
122     req.open_args.uuid = uuid_;
123     auto ret = Rpc(&req, -1, &resp);
124     if (!ret.ok()) {
125         return Error() << "failed to open coverage client: " << ret.error();
126     }
127     record_len_ = resp.open_args.record_len;
128     shm_len_ = record_len_;
129 
130     BufferAllocator allocator;
131 
132     fd = allocator.Alloc("system", shm_len_);
133     if (fd < 0) {
134         return ErrnoError() << "failed to create dmabuf of size " << shm_len_
135                             << " err code: " << fd;
136     }
137     unique_fd dma_buf(fd);
138 
139     void* shm = mmap(0, shm_len_, PROT_READ | PROT_WRITE, MAP_SHARED, dma_buf, 0);
140     if (shm == MAP_FAILED) {
141         return ErrnoError() << "failed to map memfd: ";
142     }
143 
144     req.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_SHARE_RECORD;
145     req.share_record_args.shm_len = shm_len_;
146     ret = Rpc(&req, dma_buf, &resp);
147     if (!ret.ok()) {
148         return Error() << "failed to send shared memory: " << ret.error();
149     }
150 
151     shm_ = shm;
152 
153     req.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_OPEN;
154     req.open_args.uuid = uuid_;
155     ret = Rpc(&req, -1, &resp);
156     if (!ret.ok()) {
157         return Error() << "failed to open coverage client: " << ret.error();
158     }
159 
160     return {};
161 }
162 
IsOpen()163 bool CoverageRecord::IsOpen() {
164     return shm_;
165 }
166 
SaveFile(const std::string & filename)167 Result<void> CoverageRecord::SaveFile(const std::string& filename) {
168     if(!IsOpen()) {
169         return ErrnoError() << "Warning! SHM is NULL!";
170     }
171     android::base::unique_fd output_fd(TEMP_FAILURE_RETRY(creat(filename.c_str(), 00644)));
172     if (!output_fd.ok()) {
173         return ErrnoError() << "Could not open output file";
174     }
175 
176     uintptr_t* begin = (uintptr_t*)((char *)shm_ + sizeof(struct control));
177     bool ret = WriteFully(output_fd, begin, record_len_ - sizeof(struct control));
178     if(!ret) {
179         fprintf(stderr, "Coverage write to file failed\n");
180     }
181 
182     return {};
183 }
184 
185 }  // namespace line_coverage
186 }  // namespace trusty
187 }  // namespace android
188