1 /* 2 * Copyright (C) 2016 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 "trusty_storage_client" 18 19 #include <errno.h> 20 #include <stdarg.h> 21 #include <stdbool.h> 22 #include <stdint.h> 23 #include <string.h> 24 #include <sys/uio.h> 25 26 #include <log/log.h> 27 #include <trusty/tipc.h> 28 #include <trusty/lib/storage.h> 29 30 #define MAX_CHUNK_SIZE 4040 31 32 static inline file_handle_t make_file_handle(storage_session_t s, uint32_t fid) 33 { 34 return ((uint64_t)s << 32) | fid; 35 } 36 37 static inline storage_session_t _to_session(file_handle_t fh) 38 { 39 return (storage_session_t)(fh >> 32); 40 } 41 42 static inline uint32_t _to_handle(file_handle_t fh) 43 { 44 return (uint32_t) fh; 45 } 46 47 static inline uint32_t _to_msg_flags(uint32_t opflags) 48 { 49 uint32_t msg_flags = 0; 50 51 if (opflags & STORAGE_OP_COMPLETE) 52 msg_flags |= STORAGE_MSG_FLAG_TRANSACT_COMPLETE; 53 54 return msg_flags; 55 } 56 57 static ssize_t check_response(struct storage_msg *msg, ssize_t res) 58 { 59 if (res < 0) 60 return res; 61 62 if ((size_t)res < sizeof(*msg)) { 63 ALOGE("invalid msg length (%zd < %zd)\n", res, sizeof(*msg)); 64 return -EIO; 65 } 66 67 ALOGV("cmd 0x%x: server returned %u\n", msg->cmd, msg->result); 68 69 switch(msg->result) { 70 case STORAGE_NO_ERROR: 71 return res - sizeof(*msg); 72 73 case STORAGE_ERR_NOT_FOUND: 74 return -ENOENT; 75 76 case STORAGE_ERR_EXIST: 77 return -EEXIST; 78 79 case STORAGE_ERR_NOT_VALID: 80 return -EINVAL; 81 82 case STORAGE_ERR_UNIMPLEMENTED: 83 ALOGE("cmd 0x%x: is unhandles command\n", msg->cmd); 84 return -EINVAL; 85 86 case STORAGE_ERR_ACCESS: 87 return -EACCES; 88 89 case STORAGE_ERR_TRANSACT: 90 return -EBUSY; 91 92 case STORAGE_ERR_GENERIC: 93 ALOGE("cmd 0x%x: internal server error\n", msg->cmd); 94 return -EIO; 95 96 default: 97 ALOGE("cmd 0x%x: unhandled server response %u\n", 98 msg->cmd, msg->result); 99 } 100 101 return -EIO; 102 } 103 104 static ssize_t send_reqv(storage_session_t session, 105 const struct iovec *tx_iovs, uint tx_iovcnt, 106 const struct iovec *rx_iovs, uint rx_iovcnt) 107 { 108 ssize_t rc; 109 110 rc = writev(session, tx_iovs, tx_iovcnt); 111 if (rc < 0) { 112 rc = -errno; 113 ALOGE("failed to send request: %s\n", strerror(errno)); 114 return rc; 115 } 116 117 rc = readv(session, rx_iovs, rx_iovcnt); 118 if (rc < 0) { 119 rc = -errno; 120 ALOGE("failed to recv response: %s\n", strerror(errno)); 121 return rc; 122 } 123 124 return rc; 125 } 126 127 int storage_open_session(const char *device, storage_session_t *session_p, 128 const char *port) 129 { 130 int rc = tipc_connect(device, port); 131 if (rc < 0) 132 return rc; 133 *session_p = (storage_session_t) rc; 134 return 0; 135 } 136 137 void storage_close_session(storage_session_t session) 138 { 139 tipc_close(session); 140 } 141 142 143 int storage_open_file(storage_session_t session, file_handle_t *handle_p, const char *name, 144 uint32_t flags, uint32_t opflags) 145 { 146 struct storage_msg msg = { .cmd = STORAGE_FILE_OPEN, .flags = _to_msg_flags(opflags)}; 147 struct storage_file_open_req req = { .flags = flags }; 148 struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)name, strlen(name)}}; 149 struct storage_file_open_resp rsp = { 0 }; 150 struct iovec rx[2] = {{&msg, sizeof(msg)}, {&rsp, sizeof(rsp)}}; 151 152 ssize_t rc = send_reqv(session, tx, 3, rx, 2); 153 rc = check_response(&msg, rc); 154 if (rc < 0) 155 return rc; 156 157 if ((size_t)rc != sizeof(rsp)) { 158 ALOGE("%s: invalid response length (%zd != %zd)\n", __func__, rc, sizeof(rsp)); 159 return -EIO; 160 } 161 162 *handle_p = make_file_handle(session, rsp.handle); 163 return 0; 164 } 165 166 void storage_close_file(file_handle_t fh) 167 { 168 struct storage_msg msg = { .cmd = STORAGE_FILE_CLOSE }; 169 struct storage_file_close_req req = { .handle = _to_handle(fh)}; 170 struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}}; 171 struct iovec rx[1] = {{&msg, sizeof(msg)}}; 172 173 ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 1); 174 rc = check_response(&msg, rc); 175 if (rc < 0) { 176 ALOGE("close file failed (%d)\n", (int)rc); 177 } 178 } 179 180 int storage_delete_file(storage_session_t session, const char *name, uint32_t opflags) 181 { 182 struct storage_msg msg = { .cmd = STORAGE_FILE_DELETE, .flags = _to_msg_flags(opflags)}; 183 struct storage_file_delete_req req = { .flags = 0, }; 184 struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)name, strlen(name)}}; 185 struct iovec rx[1] = {{&msg, sizeof(msg)}}; 186 187 ssize_t rc = send_reqv(session, tx, 3, rx, 1); 188 return check_response(&msg, rc); 189 } 190 191 static int _read_chunk(file_handle_t fh, storage_off_t off, void *buf, size_t size) 192 { 193 struct storage_msg msg = { .cmd = STORAGE_FILE_READ }; 194 struct storage_file_read_req req = { .handle = _to_handle(fh), .size = size, .offset = off }; 195 struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}}; 196 struct iovec rx[2] = {{&msg, sizeof(msg)}, {buf, size}}; 197 198 ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 2); 199 return check_response(&msg, rc); 200 } 201 202 ssize_t storage_read(file_handle_t fh, storage_off_t off, void *buf, size_t size) 203 { 204 int rc; 205 size_t bytes_read = 0; 206 size_t chunk = MAX_CHUNK_SIZE; 207 uint8_t *ptr = buf; 208 209 while (size) { 210 if (chunk > size) 211 chunk = size; 212 rc = _read_chunk(fh, off, ptr, chunk); 213 if (rc < 0) 214 return rc; 215 if (rc == 0) 216 break; 217 off += rc; 218 ptr += rc; 219 bytes_read += rc; 220 size -= rc; 221 } 222 return bytes_read; 223 } 224 225 static int _write_req(file_handle_t fh, storage_off_t off, 226 const void *buf, size_t size, uint32_t msg_flags) 227 { 228 struct storage_msg msg = { .cmd = STORAGE_FILE_WRITE, .flags = msg_flags, }; 229 struct storage_file_write_req req = { .handle = _to_handle(fh), .offset = off, }; 230 struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)buf, size}}; 231 struct iovec rx[1] = {{&msg, sizeof(msg)}}; 232 233 ssize_t rc = send_reqv(_to_session(fh), tx, 3, rx, 1); 234 rc = check_response(&msg, rc); 235 return rc < 0 ? rc : size; 236 } 237 238 ssize_t storage_write(file_handle_t fh, storage_off_t off, 239 const void *buf, size_t size, uint32_t opflags) 240 { 241 int rc; 242 size_t bytes_written = 0; 243 size_t chunk = MAX_CHUNK_SIZE; 244 const uint8_t *ptr = buf; 245 uint32_t msg_flags = _to_msg_flags(opflags & ~STORAGE_OP_COMPLETE); 246 247 while (size) { 248 if (chunk >= size) { 249 /* last chunk in sequence */ 250 chunk = size; 251 msg_flags = _to_msg_flags(opflags); 252 } 253 rc = _write_req(fh, off, ptr, chunk, msg_flags); 254 if (rc < 0) 255 return rc; 256 if ((size_t)rc != chunk) { 257 ALOGE("got partial write (%d)\n", (int)rc); 258 return -EIO; 259 } 260 off += chunk; 261 ptr += chunk; 262 bytes_written += chunk; 263 size -= chunk; 264 } 265 return bytes_written; 266 } 267 268 int storage_set_file_size(file_handle_t fh, storage_off_t file_size, uint32_t opflags) 269 { 270 struct storage_msg msg = { .cmd = STORAGE_FILE_SET_SIZE, .flags = _to_msg_flags(opflags)}; 271 struct storage_file_set_size_req req = { .handle = _to_handle(fh), .size = file_size, }; 272 struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}}; 273 struct iovec rx[1] = {{&msg, sizeof(msg)}}; 274 275 ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 1); 276 return check_response(&msg, rc); 277 } 278 279 int storage_get_file_size(file_handle_t fh, storage_off_t *size_p) 280 { 281 struct storage_msg msg = { .cmd = STORAGE_FILE_GET_SIZE }; 282 struct storage_file_get_size_req req = { .handle = _to_handle(fh), }; 283 struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}}; 284 struct storage_file_get_size_resp rsp; 285 struct iovec rx[2] = {{&msg, sizeof(msg)}, {&rsp, sizeof(rsp)}}; 286 287 ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 2); 288 rc = check_response(&msg, rc); 289 if (rc < 0) 290 return rc; 291 292 if ((size_t)rc != sizeof(rsp)) { 293 ALOGE("%s: invalid response length (%zd != %zd)\n", __func__, rc, sizeof(rsp)); 294 return -EIO; 295 } 296 297 *size_p = rsp.size; 298 return 0; 299 } 300 301 int storage_end_transaction(storage_session_t session, bool complete) 302 { 303 struct storage_msg msg = { 304 .cmd = STORAGE_END_TRANSACTION, 305 .flags = complete ? STORAGE_MSG_FLAG_TRANSACT_COMPLETE : 0, 306 }; 307 struct iovec iov = {&msg, sizeof(msg)}; 308 309 ssize_t rc = send_reqv(session, &iov, 1, &iov, 1); 310 return check_response(&msg, rc); 311 } 312