xref: /aosp_15_r20/system/core/trusty/keymaster/ipc/trusty_keymaster_ipc.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
1 /*
2  * Copyright (C) 2015 The Android Open Source 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 "TrustyKeymaster"
18 
19 // TODO: make this generic in libtrusty
20 
21 #include <errno.h>
22 #include <poll.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/uio.h>
26 #include <unistd.h>
27 
28 #include <algorithm>
29 #include <variant>
30 #include <vector>
31 
32 #include <log/log.h>
33 #include <trusty/tipc.h>
34 
35 #include <trusty_keymaster/ipc/keymaster_ipc.h>
36 #include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
37 #include <utils/Timers.h>
38 
39 static const char* trusty_device_name = "/dev/trusty-ipc-dev0";
40 
41 static int handle_ = -1;
42 
43 static const int timeout_ms = 10 * 1000;
44 static const int max_timeout_ms = 60 * 1000;
45 
trusty_keymaster_set_dev_name(const char * device_name)46 void trusty_keymaster_set_dev_name(const char* device_name) {
47     trusty_device_name = device_name;
48 }
trusty_keymaster_connect()49 int trusty_keymaster_connect() {
50     int rc = tipc_connect(trusty_device_name, KEYMASTER_PORT);
51     if (rc < 0) {
52         return rc;
53     }
54 
55     handle_ = rc;
56     return 0;
57 }
58 
59 class VectorEraser {
60   public:
VectorEraser(std::vector<uint8_t> * v)61     VectorEraser(std::vector<uint8_t>* v) : _v(v) {}
~VectorEraser()62     ~VectorEraser() {
63         if (_v) {
64             std::fill(const_cast<volatile uint8_t*>(_v->data()),
65                       const_cast<volatile uint8_t*>(_v->data() + _v->size()), 0);
66         }
67     }
disarm()68     void disarm() { _v = nullptr; }
69     VectorEraser(const VectorEraser&) = delete;
70     VectorEraser& operator=(const VectorEraser&) = delete;
71     VectorEraser(VectorEraser&& other) = delete;
72     VectorEraser& operator=(VectorEraser&&) = delete;
73 
74   private:
75     std::vector<uint8_t>* _v;
76 };
77 
trusty_keymaster_call_2(uint32_t cmd,void * in,uint32_t in_size)78 std::variant<int, std::vector<uint8_t>> trusty_keymaster_call_2(uint32_t cmd, void* in,
79                                                                 uint32_t in_size) {
80     if (handle_ < 0) {
81         ALOGE("not connected\n");
82         return -EINVAL;
83     }
84 
85     size_t msg_size = in_size + sizeof(struct keymaster_message);
86     struct keymaster_message* msg = reinterpret_cast<struct keymaster_message*>(malloc(msg_size));
87     if (!msg) {
88         ALOGE("failed to allocate msg buffer\n");
89         return -EINVAL;
90     }
91 
92     msg->cmd = cmd;
93     memcpy(msg->payload, in, in_size);
94 
95     nsecs_t start_time_ns = systemTime(SYSTEM_TIME_MONOTONIC);
96     bool timed_out = false;
97     int poll_timeout_ms = timeout_ms;
98     while (true) {
99         struct pollfd pfd;
100         pfd.fd = handle_;
101         pfd.events = POLLOUT;
102         pfd.revents = 0;
103 
104         int p = poll(&pfd, 1, poll_timeout_ms);
105         if (p == 0) {
106             ALOGW("write for cmd %d is taking more than %lld nsecs", cmd,
107                   (long long)(systemTime(SYSTEM_TIME_MONOTONIC) - start_time_ns));
108             timed_out = true;
109             poll_timeout_ms *= 2;
110             if (poll_timeout_ms > max_timeout_ms) {
111                 poll_timeout_ms = max_timeout_ms;
112             }
113             continue;
114         } else if (p < 0) {
115             ALOGE("write poll error: %d", errno);
116         } else if (pfd.revents != POLLOUT) {
117             ALOGW("unexpected poll() result: %d", pfd.revents);
118         }
119         break;
120     }
121 
122     ssize_t rc = write(handle_, msg, msg_size);
123     if (timed_out) {
124         ALOGW("write for cmd %d finished after %lld nsecs", cmd,
125               (long long)(systemTime(SYSTEM_TIME_MONOTONIC) - start_time_ns));
126     }
127     free(msg);
128 
129     if (rc < 0) {
130         ALOGE("failed to send cmd (%d) to %s: %s\n", cmd, KEYMASTER_PORT, strerror(errno));
131         return -errno;
132     }
133 
134     std::vector<uint8_t> out(TRUSTY_KEYMASTER_RECV_BUF_SIZE);
135     VectorEraser out_eraser(&out);
136     uint8_t* write_pos = out.data();
137     uint8_t* out_end = out.data() + out.size();
138 
139     struct iovec iov[2];
140     struct keymaster_message header;
141     iov[0] = {.iov_base = &header, .iov_len = sizeof(struct keymaster_message)};
142     while (true) {
143         if (out_end - write_pos < KEYMASTER_MAX_BUFFER_LENGTH) {
144             // In stead of using std::vector.resize(), allocate a new one to have chance
145             // at zeroing the old buffer.
146             std::vector<uint8_t> new_out(out.size() + KEYMASTER_MAX_BUFFER_LENGTH);
147             // After the swap below this erases the old out buffer.
148             VectorEraser new_out_eraser(&new_out);
149             std::copy(out.data(), write_pos, new_out.begin());
150 
151             auto write_offset = write_pos - out.data();
152 
153             std::swap(new_out, out);
154 
155             write_pos = out.data() + write_offset;
156             out_end = out.data() + out.size();
157         }
158         size_t buffer_size = 0;
159         if (__builtin_sub_overflow(reinterpret_cast<uintptr_t>(out_end),
160                                    reinterpret_cast<uintptr_t>(write_pos), &buffer_size)) {
161             return -EOVERFLOW;
162         }
163         iov[1] = {.iov_base = write_pos, .iov_len = buffer_size};
164         start_time_ns = systemTime(SYSTEM_TIME_MONOTONIC);
165         timed_out = false;
166         poll_timeout_ms = timeout_ms;
167         while (true) {
168             struct pollfd pfd;
169             pfd.fd = handle_;
170             pfd.events = POLLIN;
171             pfd.revents = 0;
172 
173             int p = poll(&pfd, 1, poll_timeout_ms);
174             if (p == 0) {
175                 ALOGW("readv for cmd %d is taking more than %lld nsecs", cmd,
176                       (long long)(systemTime(SYSTEM_TIME_MONOTONIC) - start_time_ns));
177                 timed_out = true;
178                 poll_timeout_ms *= 2;
179                 if (poll_timeout_ms > max_timeout_ms) {
180                     poll_timeout_ms = max_timeout_ms;
181                 }
182                 continue;
183             } else if (p < 0) {
184                 ALOGE("read poll error: %d", errno);
185             } else if (pfd.revents != POLLIN) {
186                 ALOGW("unexpected poll() result: %d", pfd.revents);
187             }
188             break;
189         }
190         rc = readv(handle_, iov, 2);
191         if (timed_out) {
192             ALOGW("readv for cmd %d finished after %lld nsecs", cmd,
193                   (long long)(systemTime(SYSTEM_TIME_MONOTONIC) - start_time_ns));
194         }
195         if (rc < 0) {
196             ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n", cmd, KEYMASTER_PORT,
197                   strerror(errno));
198             return -errno;
199         }
200 
201         if ((size_t)rc < sizeof(struct keymaster_message)) {
202             ALOGE("invalid response size (%d)\n", (int)rc);
203             return -EINVAL;
204         }
205 
206         if ((cmd | KEYMASTER_RESP_BIT) != (header.cmd & ~(KEYMASTER_STOP_BIT))) {
207             ALOGE("invalid command (%d)", header.cmd);
208             return -EINVAL;
209         }
210         write_pos += ((size_t)rc - sizeof(struct keymaster_message));
211         if (header.cmd & KEYMASTER_STOP_BIT) {
212             break;
213         }
214     }
215 
216     out.resize(write_pos - out.data());
217     out_eraser.disarm();
218     return out;
219 }
220 
trusty_keymaster_call(uint32_t cmd,void * in,uint32_t in_size,uint8_t * out,uint32_t * out_size)221 int trusty_keymaster_call(uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
222                           uint32_t* out_size) {
223     auto result = trusty_keymaster_call_2(cmd, in, in_size);
224     if (auto out_buffer = std::get_if<std::vector<uint8_t>>(&result)) {
225         if (out_buffer->size() <= *out_size) {
226             std::copy(out_buffer->begin(), out_buffer->end(), out);
227             std::fill(const_cast<volatile uint8_t*>(&*out_buffer->begin()),
228                       const_cast<volatile uint8_t*>(&*out_buffer->end()), 0);
229 
230             *out_size = out_buffer->size();
231             return 0;
232         } else {
233             ALOGE("Message was to large (%zu) for the provided buffer (%u)", out_buffer->size(),
234                   *out_size);
235             return -EMSGSIZE;
236         }
237     } else {
238         return std::get<int>(result);
239     }
240 }
241 
trusty_keymaster_disconnect()242 void trusty_keymaster_disconnect() {
243     if (handle_ >= 0) {
244         tipc_close(handle_);
245     }
246     handle_ = -1;
247 }
248 
translate_error(int err)249 keymaster_error_t translate_error(int err) {
250     switch (err) {
251         case 0:
252             return KM_ERROR_OK;
253         case -EPERM:
254         case -EACCES:
255             return KM_ERROR_SECURE_HW_ACCESS_DENIED;
256 
257         case -ECANCELED:
258             return KM_ERROR_OPERATION_CANCELLED;
259 
260         case -ENODEV:
261             return KM_ERROR_UNIMPLEMENTED;
262 
263         case -ENOMEM:
264             return KM_ERROR_MEMORY_ALLOCATION_FAILED;
265 
266         case -EBUSY:
267             return KM_ERROR_SECURE_HW_BUSY;
268 
269         case -EIO:
270             return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
271 
272         case -EOVERFLOW:
273             return KM_ERROR_INVALID_INPUT_LENGTH;
274 
275         default:
276             return KM_ERROR_UNKNOWN_ERROR;
277     }
278 }
279 
trusty_keymaster_send(uint32_t command,const keymaster::Serializable & req,keymaster::KeymasterResponse * rsp)280 keymaster_error_t trusty_keymaster_send(uint32_t command, const keymaster::Serializable& req,
281                                         keymaster::KeymasterResponse* rsp) {
282     uint32_t req_size = req.SerializedSize();
283     if (req_size > TRUSTY_KEYMASTER_SEND_BUF_SIZE) {
284         ALOGE("Request too big: %u Max size: %u", req_size, TRUSTY_KEYMASTER_SEND_BUF_SIZE);
285         return KM_ERROR_INVALID_INPUT_LENGTH;
286     }
287 
288     uint8_t send_buf[TRUSTY_KEYMASTER_SEND_BUF_SIZE];
289     keymaster::Eraser send_buf_eraser(send_buf, TRUSTY_KEYMASTER_SEND_BUF_SIZE);
290     req.Serialize(send_buf, send_buf + req_size);
291 
292     // Send it
293     auto response = trusty_keymaster_call_2(command, send_buf, req_size);
294     if (auto response_buffer = std::get_if<std::vector<uint8_t>>(&response)) {
295         keymaster::Eraser response_buffer_erasor(response_buffer->data(), response_buffer->size());
296         ALOGV("Received %zu byte response\n", response_buffer->size());
297 
298         const uint8_t* p = response_buffer->data();
299         if (!rsp->Deserialize(&p, p + response_buffer->size())) {
300             ALOGE("Error deserializing response of size %zu\n", response_buffer->size());
301             return KM_ERROR_UNKNOWN_ERROR;
302         } else if (rsp->error != KM_ERROR_OK) {
303             ALOGE("Response of size %zu contained error code %d\n", response_buffer->size(),
304                   (int)rsp->error);
305         }
306         return rsp->error;
307     } else {
308         auto rc = std::get<int>(response);
309         // Reset the connection on tipc error
310         trusty_keymaster_disconnect();
311         trusty_keymaster_connect();
312         ALOGE("tipc error: %d\n", rc);
313         // TODO(swillden): Distinguish permanent from transient errors and set error_ appropriately.
314         return translate_error(rc);
315     }
316 }
317