1 /*
2  * Copyright (C) 2021 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 #include <trusty/hwbcc.h>
18 #include <trusty/trusty_ipc.h>
19 #include <trusty/util.h>
20 
21 #include <uapi/uapi/err.h>
22 
23 static struct trusty_ipc_chan hwbcc_chan;
24 static bool initialized;
25 
26 #ifndef MIN
27 #define MIN(a, b) ((a) < (b) ? (a) : (b))
28 #endif
29 
hwbcc_tipc_init(struct trusty_ipc_dev * dev)30 int hwbcc_tipc_init(struct trusty_ipc_dev* dev) {
31     trusty_assert(dev);
32     trusty_ipc_chan_init(&hwbcc_chan, dev);
33 
34     trusty_debug("In hwbcc_tipc_init: connecting to hwbcc service.\n");
35     int rc = trusty_ipc_connect(&hwbcc_chan, HWBCC_PORT, true /*wait*/);
36     if (rc < 0) {
37         trusty_error("In hwbcc_tipc_init:: failed (%d) to connect to '%s'.\n",
38                      rc, HWBCC_PORT);
39         return rc;
40     }
41     initialized = true;
42     return TRUSTY_ERR_NONE;
43 }
44 
hwbcc_tipc_shutdown(void)45 void hwbcc_tipc_shutdown(void) {
46     if (!initialized) {
47         return;
48     }
49     trusty_ipc_close(&hwbcc_chan);
50     initialized = false;
51 }
52 
send_header_only_request(struct hwbcc_req_hdr * hdr,size_t hdr_size)53 static int send_header_only_request(struct hwbcc_req_hdr* hdr,
54                                     size_t hdr_size) {
55     int num_iovec = 1;
56     struct trusty_ipc_iovec req_iov = {.base = hdr, .len = hdr_size};
57     return trusty_ipc_send(&hwbcc_chan, &req_iov, num_iovec, true);
58 }
59 
read_response_with_data(struct hwbcc_req_hdr * hdr,uint8_t * buf,size_t buf_size,size_t * out_size)60 static int read_response_with_data(struct hwbcc_req_hdr* hdr,
61                                    uint8_t* buf,
62                                    size_t buf_size,
63                                    size_t* out_size) {
64     struct hwbcc_resp_hdr resp_hdr = {};
65 
66     trusty_assert(buf);
67     trusty_assert(out_size);
68 
69     int num_iovec = 2;
70     struct trusty_ipc_iovec resp_iovecs[2] = {
71             {.base = &resp_hdr, .len = sizeof(resp_hdr)},
72             {.base = buf, .len = buf_size},
73     };
74 
75     int rc = trusty_ipc_recv(&hwbcc_chan, resp_iovecs, num_iovec, true);
76     if (rc < 0) {
77         trusty_error("Failure on receiving response: %d\n", rc);
78         return rc;
79     }
80 
81     if ((size_t)rc < sizeof(resp_hdr)) {
82         trusty_error("Invalid response size (%d).\n", rc);
83         return TRUSTY_ERR_GENERIC;
84     }
85 
86     if (resp_hdr.cmd != (hdr->cmd | HWBCC_CMD_RESP_BIT)) {
87         trusty_error("Unknown response cmd: %x\n", resp_hdr.cmd);
88         return TRUSTY_ERR_GENERIC;
89     }
90 
91     if (resp_hdr.status != NO_ERROR) {
92         trusty_error("Status (%d) is not SUCCESS.\n", resp_hdr.status);
93         return TRUSTY_ERR_GENERIC;
94     }
95 
96     if (resp_hdr.payload_size != (size_t)rc - sizeof(resp_hdr)) {
97         trusty_error("Invalid payload size: %d.", resp_hdr.payload_size);
98         return TRUSTY_ERR_GENERIC;
99     }
100 
101     *out_size = resp_hdr.payload_size;
102     return rc;
103 }
104 
read_header_only_response(struct hwbcc_req_hdr * hdr)105 static int read_header_only_response(struct hwbcc_req_hdr* hdr) {
106     struct hwbcc_resp_hdr resp_hdr = {};
107 
108     struct trusty_ipc_iovec resp_iovec = {.base = &resp_hdr,
109                                           .len = sizeof(resp_hdr)};
110 
111     int rc = trusty_ipc_recv(&hwbcc_chan, &resp_iovec, 1, true);
112     if (rc < 0) {
113         trusty_error("Failure on receiving response: %d\n", rc);
114         return rc;
115     }
116 
117     if ((size_t)rc < sizeof(resp_hdr)) {
118         trusty_error("Invalid response size (%d).\n", rc);
119         return TRUSTY_ERR_GENERIC;
120     }
121 
122     if (resp_hdr.cmd != (hdr->cmd | HWBCC_CMD_RESP_BIT)) {
123         trusty_error("Unknown response cmd: %x\n", resp_hdr.cmd);
124         return TRUSTY_ERR_GENERIC;
125     }
126 
127     if (resp_hdr.status != NO_ERROR) {
128         trusty_error("Status (%d) is not SUCCESS.\n", resp_hdr.status);
129         return TRUSTY_ERR_GENERIC;
130     }
131 
132     return rc;
133 }
134 
hwbcc_get_dice_artifacts(uint64_t context,uint8_t * dice_artifacts,size_t dice_artifacts_buf_size,size_t * dice_artifacts_size)135 int hwbcc_get_dice_artifacts(uint64_t context,
136                              uint8_t* dice_artifacts,
137                              size_t dice_artifacts_buf_size,
138                              size_t* dice_artifacts_size) {
139     trusty_assert(dice_artifacts);
140     trusty_assert(dice_artifacts_size);
141 
142     struct hwbcc_req_hdr hdr;
143     hdr.cmd = HWBCC_CMD_GET_DICE_ARTIFACTS;
144     hdr.context = context;
145 
146     int rc = send_header_only_request(&hdr, sizeof(hdr));
147 
148     if (rc < 0) {
149         trusty_error(
150                 "In hwbcc_get_dice_artifacts: failed (%d) to send request to HWBCC.",
151                 rc);
152         return rc;
153     }
154 
155     rc = read_response_with_data(&hdr, dice_artifacts, dice_artifacts_buf_size,
156                                  dice_artifacts_size);
157 
158     if (rc < 0) {
159         trusty_error(
160                 "In hwbcc_get_dice_artifacts: failed (%d) to read the response.",
161                 rc);
162         return rc;
163     }
164 
165     return TRUSTY_ERR_NONE;
166 }
167 
hwbcc_ns_deprivilege(void)168 int hwbcc_ns_deprivilege(void) {
169     struct hwbcc_req_hdr hdr = {.cmd = HWBCC_CMD_NS_DEPRIVILEGE};
170     int rc = send_header_only_request(&hdr, sizeof(hdr));
171 
172     if (rc < 0) {
173         trusty_error(
174                 "In hwbcc_deprivilege: failed (%d) to send request to HWBCC.",
175                 rc);
176         return rc;
177     }
178 
179     rc = read_header_only_response(&hdr);
180 
181     if (rc < 0) {
182         trusty_error("In hwbcc_deprivilege: failed (%d) to read the response.",
183                      rc);
184         return rc;
185     }
186 
187     return TRUSTY_ERR_NONE;
188 }
189