1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 #include <trusty/avb.h>
26 #include <trusty/rpmb.h>
27 #include <trusty/trusty_ipc.h>
28 #include <trusty/util.h>
29
30 #define LOCAL_LOG 0
31
32 static bool initialized;
33 static int avb_tipc_version = 1;
34 static struct trusty_ipc_chan avb_chan;
35
avb_send_request(struct avb_message * msg,void * req,size_t req_len)36 static int avb_send_request(struct avb_message* msg,
37 void* req,
38 size_t req_len) {
39 struct trusty_ipc_iovec req_iovs[2] = {
40 {.base = msg, .len = sizeof(*msg)},
41 {.base = req, .len = req_len},
42 };
43
44 return trusty_ipc_send(&avb_chan, req_iovs, req ? 2 : 1, true);
45 }
46
avb_read_response(struct avb_message * msg,uint32_t cmd,void * resp,size_t resp_len)47 static int avb_read_response(struct avb_message* msg,
48 uint32_t cmd,
49 void* resp,
50 size_t resp_len) {
51 int rc;
52 struct trusty_ipc_iovec resp_iovs[2] = {
53 {.base = msg, .len = sizeof(*msg)},
54 {.base = resp, .len = resp_len},
55 };
56
57 rc = trusty_ipc_recv(&avb_chan, resp_iovs, resp ? 2 : 1, true);
58 if (rc < 0) {
59 trusty_error("failed (%d) to recv response\n", rc);
60 return rc;
61 }
62 if (msg->cmd != (cmd | AVB_RESP_BIT)) {
63 trusty_error("malformed response\n");
64 return TRUSTY_ERR_GENERIC;
65 }
66 /* return payload size */
67 return rc - sizeof(*msg);
68 }
69
70 /*
71 * Convenience function to send a request to the AVB service and read the
72 * response.
73 *
74 * @cmd: the command
75 * @req: the request buffer
76 * @req_size: size of the request buffer
77 * @resp: the response buffer
78 * @resp_size_p: pointer to the size of the response buffer. changed to the
79 actual size of the response read from the secure side
80 */
avb_do_tipc(uint32_t cmd,void * req,uint32_t req_size,void * resp,uint32_t * resp_size_p)81 static int avb_do_tipc(uint32_t cmd,
82 void* req,
83 uint32_t req_size,
84 void* resp,
85 uint32_t* resp_size_p) {
86 int rc;
87 struct avb_message msg = {.cmd = cmd};
88
89 if (!initialized && cmd != AVB_GET_VERSION) {
90 trusty_error("%s: AVB TIPC client not initialized\n", __func__);
91 return TRUSTY_ERR_GENERIC;
92 }
93
94 rc = avb_send_request(&msg, req, req_size);
95 if (rc < 0) {
96 trusty_error("%s: failed (%d) to send AVB request\n", __func__, rc);
97 return rc;
98 }
99
100 uint32_t resp_size = resp_size_p ? *resp_size_p : 0;
101 rc = avb_read_response(&msg, cmd, resp, resp_size);
102 if (rc < 0) {
103 trusty_error("%s: failed (%d) to read AVB response\n", __func__, rc);
104 return rc;
105 }
106 /* change response size to actual response size */
107 if (resp_size_p && rc != *resp_size_p) {
108 *resp_size_p = rc;
109 }
110 if (msg.result != AVB_ERROR_NONE) {
111 trusty_error("%s: AVB service returned error (%d)\n", __func__,
112 msg.result);
113 return TRUSTY_ERR_GENERIC;
114 }
115 return TRUSTY_ERR_NONE;
116 }
117
avb_get_version(uint32_t * version)118 static int avb_get_version(uint32_t* version) {
119 int rc;
120 struct avb_get_version_resp resp;
121 uint32_t resp_size = sizeof(resp);
122
123 rc = avb_do_tipc(AVB_GET_VERSION, NULL, 0, &resp, &resp_size);
124
125 *version = resp.version;
126 return rc;
127 }
128
avb_tipc_init(struct trusty_ipc_dev * dev)129 int avb_tipc_init(struct trusty_ipc_dev* dev) {
130 int rc;
131 uint32_t version = 0;
132
133 trusty_assert(dev);
134 trusty_assert(!initialized);
135
136 trusty_ipc_chan_init(&avb_chan, dev);
137 trusty_debug("Connecting to AVB service\n");
138
139 /* connect to AVB service and wait for connect to complete */
140 rc = trusty_ipc_connect(&avb_chan, AVB_PORT, true);
141 if (rc < 0) {
142 trusty_error("failed (%d) to connect to '%s'\n", rc, AVB_PORT);
143 return rc;
144 }
145
146 /* check for version mismatch */
147 rc = avb_get_version(&version);
148 if (rc != 0) {
149 trusty_error("Error getting version");
150 return TRUSTY_ERR_GENERIC;
151 }
152 if (version != avb_tipc_version) {
153 trusty_error("AVB TIPC version mismatch. Expected %u, received %u\n",
154 avb_tipc_version, version);
155 return TRUSTY_ERR_GENERIC;
156 }
157
158 /* mark as initialized */
159 initialized = true;
160
161 return TRUSTY_ERR_NONE;
162 }
163
avb_tipc_shutdown(struct trusty_ipc_dev * dev)164 void avb_tipc_shutdown(struct trusty_ipc_dev* dev) {
165 if (!initialized)
166 return; /* nothing to do */
167
168 /* close channel */
169 trusty_ipc_close(&avb_chan);
170
171 initialized = false;
172 }
173
trusty_read_rollback_index(uint32_t slot,uint64_t * value)174 int trusty_read_rollback_index(uint32_t slot, uint64_t* value) {
175 int rc;
176 struct avb_rollback_req req = {.slot = slot, .value = 0};
177 struct avb_rollback_resp resp;
178 uint32_t resp_size = sizeof(resp);
179
180 rc = avb_do_tipc(READ_ROLLBACK_INDEX, &req, sizeof(req), &resp, &resp_size);
181
182 *value = resp.value;
183 return rc;
184 }
185
trusty_write_rollback_index(uint32_t slot,uint64_t value)186 int trusty_write_rollback_index(uint32_t slot, uint64_t value) {
187 int rc;
188 struct avb_rollback_req req = {.slot = slot, .value = value};
189 struct avb_rollback_resp resp;
190 uint32_t resp_size = sizeof(resp);
191
192 rc = avb_do_tipc(WRITE_ROLLBACK_INDEX, &req, sizeof(req), &resp,
193 &resp_size);
194 return rc;
195 }
196
trusty_read_permanent_attributes(uint8_t * attributes,uint32_t size)197 int trusty_read_permanent_attributes(uint8_t* attributes, uint32_t size) {
198 uint8_t resp_buf[AVB_MAX_BUFFER_LENGTH];
199 uint32_t resp_size = AVB_MAX_BUFFER_LENGTH;
200 int rc = avb_do_tipc(READ_PERMANENT_ATTRIBUTES, NULL, 0, resp_buf,
201 &resp_size);
202 if (rc != 0) {
203 return rc;
204 }
205 /* ensure caller passed size matches size returned by Trusty */
206 if (size != resp_size) {
207 return TRUSTY_ERR_INVALID_ARGS;
208 }
209 trusty_memcpy(attributes, resp_buf, resp_size);
210 return rc;
211 }
212
trusty_write_permanent_attributes(uint8_t * attributes,uint32_t size)213 int trusty_write_permanent_attributes(uint8_t* attributes, uint32_t size) {
214 return avb_do_tipc(WRITE_PERMANENT_ATTRIBUTES, attributes, size, NULL,
215 NULL);
216 }
217
trusty_read_lock_state(uint8_t * lock_state)218 int trusty_read_lock_state(uint8_t* lock_state) {
219 uint32_t resp_size = sizeof(*lock_state);
220 return avb_do_tipc(READ_LOCK_STATE, NULL, 0, lock_state, &resp_size);
221 }
222
trusty_write_lock_state(uint8_t lock_state)223 int trusty_write_lock_state(uint8_t lock_state) {
224 return avb_do_tipc(WRITE_LOCK_STATE, &lock_state, sizeof(lock_state), NULL,
225 NULL);
226 }
227
trusty_lock_boot_state(void)228 int trusty_lock_boot_state(void) {
229 return avb_do_tipc(LOCK_BOOT_STATE, NULL, 0, NULL, NULL);
230 }
231