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 #include <cutils/properties.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <inttypes.h>
20 #include <libgen.h>
21 #include <stdbool.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <sys/syscall.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28
29 #include "checkpoint_handling.h"
30 #include "ipc.h"
31 #include "log.h"
32 #include "storage.h"
33
34 #define FD_TBL_SIZE 64
35 #define MAX_READ_SIZE 4096
36
37 #define ALTERNATE_DATA_DIR "alternate/"
38
39 enum sync_state {
40 SS_UNUSED = -1,
41 SS_CLEAN = 0,
42 SS_DIRTY = 1,
43 };
44
45 static const char *ssdir_name;
46
47 /*
48 * Property set to 1 after we have opened a file under ssdir_name. The backing
49 * files for both TD and TDP are currently located under /data/vendor/ss and can
50 * only be opened once userdata is mounted. This storageproxyd service is
51 * restarted when userdata is available, which causes the Trusty storage service
52 * to reconnect and attempt to open the backing files for TD and TDP. Once we
53 * set this property, other users can expect that the Trusty storage service
54 * ports will be available (although they may block if still being initialized),
55 * and connections will not be reset after this point (assuming the
56 * storageproxyd service stays running).
57 */
58 #define FS_READY_PROPERTY "ro.vendor.trusty.storage.fs_ready"
59
60 /* has FS_READY_PROPERTY been set? */
61 static bool fs_ready_initialized = false;
62
63 static enum sync_state fs_state;
64 static enum sync_state fd_state[FD_TBL_SIZE];
65
66 static bool alternate_mode;
67
68 static struct {
69 struct storage_file_read_resp hdr;
70 uint8_t data[MAX_READ_SIZE];
71 } read_rsp;
72
insert_fd(int open_flags,int fd)73 static uint32_t insert_fd(int open_flags, int fd)
74 {
75 uint32_t handle = fd;
76
77 if (handle < FD_TBL_SIZE) {
78 fd_state[fd] = SS_CLEAN; /* fd clean */
79 if (open_flags & O_TRUNC) {
80 fd_state[fd] = SS_DIRTY; /* set fd dirty */
81 }
82 } else {
83 ALOGW("%s: untracked fd %u\n", __func__, fd);
84 if (open_flags & (O_TRUNC | O_CREAT)) {
85 fs_state = SS_DIRTY;
86 }
87 }
88 return handle;
89 }
90
lookup_fd(uint32_t handle,bool dirty)91 static int lookup_fd(uint32_t handle, bool dirty)
92 {
93 if (dirty) {
94 if (handle < FD_TBL_SIZE) {
95 fd_state[handle] = SS_DIRTY;
96 } else {
97 fs_state = SS_DIRTY;
98 }
99 }
100 return handle;
101 }
102
remove_fd(uint32_t handle)103 static int remove_fd(uint32_t handle)
104 {
105 if (handle < FD_TBL_SIZE) {
106 fd_state[handle] = SS_UNUSED; /* set to uninstalled */
107 }
108 return handle;
109 }
110
translate_errno(int error)111 static enum storage_err translate_errno(int error)
112 {
113 enum storage_err result;
114 switch (error) {
115 case 0:
116 result = STORAGE_NO_ERROR;
117 break;
118 case EBADF:
119 case EINVAL:
120 case ENOTDIR:
121 case EISDIR:
122 case ENAMETOOLONG:
123 result = STORAGE_ERR_NOT_VALID;
124 break;
125 case ENOENT:
126 result = STORAGE_ERR_NOT_FOUND;
127 break;
128 case EEXIST:
129 result = STORAGE_ERR_EXIST;
130 break;
131 case EPERM:
132 case EACCES:
133 result = STORAGE_ERR_ACCESS;
134 break;
135 default:
136 result = STORAGE_ERR_GENERIC;
137 break;
138 }
139
140 return result;
141 }
142
write_with_retry(int fd,const void * buf_,size_t size,off_t offset)143 static ssize_t write_with_retry(int fd, const void *buf_, size_t size, off_t offset)
144 {
145 ssize_t rc;
146 const uint8_t *buf = buf_;
147
148 while (size > 0) {
149 rc = TEMP_FAILURE_RETRY(pwrite(fd, buf, size, offset));
150 if (rc < 0)
151 return rc;
152 size -= rc;
153 buf += rc;
154 offset += rc;
155 }
156 return 0;
157 }
158
read_with_retry(int fd,void * buf_,size_t size,off_t offset)159 static ssize_t read_with_retry(int fd, void *buf_, size_t size, off_t offset)
160 {
161 ssize_t rc;
162 size_t rcnt = 0;
163 uint8_t *buf = buf_;
164
165 while (size > 0) {
166 rc = TEMP_FAILURE_RETRY(pread(fd, buf, size, offset));
167 if (rc < 0)
168 return rc;
169 if (rc == 0)
170 break;
171 size -= rc;
172 buf += rc;
173 offset += rc;
174 rcnt += rc;
175 }
176 return rcnt;
177 }
178
storage_file_delete(struct storage_msg * msg,const void * r,size_t req_len)179 int storage_file_delete(struct storage_msg *msg,
180 const void *r, size_t req_len)
181 {
182 char *path = NULL;
183 const struct storage_file_delete_req *req = r;
184
185 if (req_len < sizeof(*req)) {
186 ALOGE("%s: invalid request length (%zd < %zd)\n",
187 __func__, req_len, sizeof(*req));
188 msg->result = STORAGE_ERR_NOT_VALID;
189 goto err_response;
190 }
191
192 size_t fname_len = strlen(req->name);
193 if (fname_len != req_len - sizeof(*req)) {
194 ALOGE("%s: invalid filename length (%zd != %zd)\n",
195 __func__, fname_len, req_len - sizeof(*req));
196 msg->result = STORAGE_ERR_NOT_VALID;
197 goto err_response;
198 }
199
200 int rc = asprintf(&path, "%s/%s", ssdir_name, req->name);
201 if (rc < 0) {
202 ALOGE("%s: asprintf failed\n", __func__);
203 msg->result = STORAGE_ERR_GENERIC;
204 goto err_response;
205 }
206
207 rc = unlink(path);
208 if (rc < 0) {
209 rc = errno;
210 if (errno == ENOENT) {
211 ALOGV("%s: error (%d) unlinking file '%s'\n",
212 __func__, rc, path);
213 } else {
214 ALOGE("%s: error (%d) unlinking file '%s'\n",
215 __func__, rc, path);
216 }
217 msg->result = translate_errno(rc);
218 goto err_response;
219 }
220
221 ALOGV("%s: \"%s\"\n", __func__, path);
222 msg->result = STORAGE_NO_ERROR;
223
224 err_response:
225 if (path)
226 free(path);
227 return ipc_respond(msg, NULL, 0);
228 }
229
sync_parent(const char * path)230 static void sync_parent(const char* path) {
231 int parent_fd;
232 char* parent_path = dirname(path);
233 parent_fd = TEMP_FAILURE_RETRY(open(parent_path, O_RDONLY));
234 if (parent_fd >= 0) {
235 fsync(parent_fd);
236 close(parent_fd);
237 } else {
238 ALOGE("%s: failed to open parent directory \"%s\" for sync: %s\n", __func__, parent_path,
239 strerror(errno));
240 }
241 }
242
storage_file_open(struct storage_msg * msg,const void * r,size_t req_len)243 int storage_file_open(struct storage_msg* msg, const void* r, size_t req_len) {
244 char* path = NULL;
245 const struct storage_file_open_req *req = r;
246 struct storage_file_open_resp resp = {0};
247
248 if (req_len < sizeof(*req)) {
249 ALOGE("%s: invalid request length (%zd < %zd)\n",
250 __func__, req_len, sizeof(*req));
251 msg->result = STORAGE_ERR_NOT_VALID;
252 goto err_response;
253 }
254
255 size_t fname_len = strlen(req->name);
256 if (fname_len != req_len - sizeof(*req)) {
257 ALOGE("%s: invalid filename length (%zd != %zd)\n",
258 __func__, fname_len, req_len - sizeof(*req));
259 msg->result = STORAGE_ERR_NOT_VALID;
260 goto err_response;
261 }
262
263 /*
264 * TODO(b/210501710): Expose GSI image running state to vendor
265 * storageproxyd. We want to control data file paths in vendor_init, but we
266 * don't have access to the necessary property there yet. When we have
267 * access to that property we can set the root data path read-only and only
268 * allow creation of files in alternate/. Checking paths here temporarily
269 * until that is fixed.
270 *
271 * We are just checking for "/" instead of "alternate/" because we still
272 * want to still allow access to "persist/" in alternate mode (for now, this
273 * may change in the future).
274 */
275 if (alternate_mode && !strchr(req->name, '/')) {
276 ALOGE("%s: Cannot open root data file \"%s\" in alternate mode\n", __func__, req->name);
277 msg->result = STORAGE_ERR_ACCESS;
278 goto err_response;
279 }
280
281 int rc = asprintf(&path, "%s/%s", ssdir_name, req->name);
282 if (rc < 0) {
283 ALOGE("%s: asprintf failed\n", __func__);
284 msg->result = STORAGE_ERR_GENERIC;
285 goto err_response;
286 }
287
288 int open_flags = O_RDWR;
289
290 if (req->flags & STORAGE_FILE_OPEN_TRUNCATE)
291 open_flags |= O_TRUNC;
292
293 if (req->flags & STORAGE_FILE_OPEN_CREATE) {
294 /*
295 * Create the alternate parent dir if needed & allowed.
296 *
297 * TODO(b/210501710): Expose GSI image running state to vendor
298 * storageproxyd. This directory should be created by vendor_init, once
299 * it has access to the necessary bit of information.
300 */
301 if (strstr(req->name, ALTERNATE_DATA_DIR) == req->name) {
302 char* parent_path = dirname(path);
303 rc = mkdir(parent_path, S_IRWXU);
304 if (rc == 0) {
305 sync_parent(parent_path);
306 } else if (errno != EEXIST) {
307 ALOGE("%s: Could not create parent directory \"%s\": %s\n", __func__, parent_path,
308 strerror(errno));
309 }
310 }
311
312 /* open or create */
313 if (req->flags & STORAGE_FILE_OPEN_CREATE_EXCLUSIVE) {
314 /* create exclusive */
315 open_flags |= O_CREAT | O_EXCL;
316 rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
317 } else {
318 /* try open first */
319 rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
320 if (rc == -1 && errno == ENOENT) {
321 /* then try open with O_CREATE */
322 open_flags |= O_CREAT;
323 rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
324 }
325
326 }
327 } else {
328 /* open an existing file */
329 rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
330 }
331
332 if (rc < 0) {
333 rc = errno;
334 if (errno == EEXIST || errno == ENOENT) {
335 ALOGV("%s: failed to open file \"%s\": %s\n",
336 __func__, path, strerror(errno));
337 } else {
338 ALOGE("%s: failed to open file \"%s\": %s\n",
339 __func__, path, strerror(errno));
340 }
341 msg->result = translate_errno(rc);
342 goto err_response;
343 }
344
345 if (open_flags & O_CREAT) {
346 sync_parent(path);
347 }
348 free(path);
349
350 /* at this point rc contains storage file fd */
351 msg->result = STORAGE_NO_ERROR;
352 resp.handle = insert_fd(open_flags, rc);
353 ALOGV("%s: \"%s\": fd = %u: handle = %d\n",
354 __func__, path, rc, resp.handle);
355
356 /* a backing file has been opened, notify any waiting init steps */
357 if (!fs_ready_initialized) {
358 rc = property_set(FS_READY_PROPERTY, "1");
359 if (rc == 0) {
360 fs_ready_initialized = true;
361 } else {
362 ALOGE("Could not set property %s, rc: %d\n", FS_READY_PROPERTY, rc);
363 }
364 }
365
366 return ipc_respond(msg, &resp, sizeof(resp));
367
368 err_response:
369 if (path)
370 free(path);
371 return ipc_respond(msg, NULL, 0);
372 }
373
storage_file_close(struct storage_msg * msg,const void * r,size_t req_len)374 int storage_file_close(struct storage_msg *msg,
375 const void *r, size_t req_len)
376 {
377 const struct storage_file_close_req *req = r;
378
379 if (req_len != sizeof(*req)) {
380 ALOGE("%s: invalid request length (%zd != %zd)\n",
381 __func__, req_len, sizeof(*req));
382 msg->result = STORAGE_ERR_NOT_VALID;
383 goto err_response;
384 }
385
386 int fd = remove_fd(req->handle);
387 ALOGV("%s: handle = %u: fd = %u\n", __func__, req->handle, fd);
388
389 int rc = fsync(fd);
390 if (rc < 0) {
391 rc = errno;
392 ALOGE("%s: fsync failed for fd=%u: %s\n",
393 __func__, fd, strerror(errno));
394 msg->result = translate_errno(rc);
395 goto err_response;
396 }
397
398 rc = close(fd);
399 if (rc < 0) {
400 rc = errno;
401 ALOGE("%s: close failed for fd=%u: %s\n",
402 __func__, fd, strerror(errno));
403 msg->result = translate_errno(rc);
404 goto err_response;
405 }
406
407 msg->result = STORAGE_NO_ERROR;
408
409 err_response:
410 return ipc_respond(msg, NULL, 0);
411 }
412
413
storage_file_write(struct storage_msg * msg,const void * r,size_t req_len)414 int storage_file_write(struct storage_msg *msg,
415 const void *r, size_t req_len)
416 {
417 int rc;
418 const struct storage_file_write_req *req = r;
419
420 if (req_len < sizeof(*req)) {
421 ALOGE("%s: invalid request length (%zd < %zd)\n",
422 __func__, req_len, sizeof(*req));
423 msg->result = STORAGE_ERR_NOT_VALID;
424 goto err_response;
425 }
426
427 int fd = lookup_fd(req->handle, true);
428 if (write_with_retry(fd, &req->data[0], req_len - sizeof(*req),
429 req->offset) < 0) {
430 rc = errno;
431 ALOGW("%s: error writing file (fd=%d): %s\n",
432 __func__, fd, strerror(errno));
433 msg->result = translate_errno(rc);
434 goto err_response;
435 }
436
437 if (msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) {
438 rc = storage_sync_checkpoint();
439 if (rc < 0) {
440 msg->result = STORAGE_ERR_SYNC_FAILURE;
441 goto err_response;
442 }
443 }
444
445 msg->result = STORAGE_NO_ERROR;
446
447 err_response:
448 return ipc_respond(msg, NULL, 0);
449 }
450
451
storage_file_read(struct storage_msg * msg,const void * r,size_t req_len)452 int storage_file_read(struct storage_msg *msg,
453 const void *r, size_t req_len)
454 {
455 int rc;
456 const struct storage_file_read_req *req = r;
457
458 if (req_len != sizeof(*req)) {
459 ALOGE("%s: invalid request length (%zd != %zd)\n",
460 __func__, req_len, sizeof(*req));
461 msg->result = STORAGE_ERR_NOT_VALID;
462 goto err_response;
463 }
464
465 if (req->size > MAX_READ_SIZE) {
466 ALOGW("%s: request is too large (%u > %d) - refusing\n",
467 __func__, req->size, MAX_READ_SIZE);
468 msg->result = STORAGE_ERR_NOT_VALID;
469 goto err_response;
470 }
471
472 int fd = lookup_fd(req->handle, false);
473 ssize_t read_res = read_with_retry(fd, read_rsp.hdr.data, req->size,
474 (off_t)req->offset);
475 if (read_res < 0) {
476 rc = errno;
477 ALOGW("%s: error reading file (fd=%d): %s\n",
478 __func__, fd, strerror(errno));
479 msg->result = translate_errno(rc);
480 goto err_response;
481 }
482
483 msg->result = STORAGE_NO_ERROR;
484 return ipc_respond(msg, &read_rsp, read_res + sizeof(read_rsp.hdr));
485
486 err_response:
487 return ipc_respond(msg, NULL, 0);
488 }
489
490
storage_file_get_size(struct storage_msg * msg,const void * r,size_t req_len)491 int storage_file_get_size(struct storage_msg *msg,
492 const void *r, size_t req_len)
493 {
494 const struct storage_file_get_size_req *req = r;
495 struct storage_file_get_size_resp resp = {0};
496
497 if (req_len != sizeof(*req)) {
498 ALOGE("%s: invalid request length (%zd != %zd)\n",
499 __func__, req_len, sizeof(*req));
500 msg->result = STORAGE_ERR_NOT_VALID;
501 goto err_response;
502 }
503
504 struct stat stat;
505 int fd = lookup_fd(req->handle, false);
506 int rc = fstat(fd, &stat);
507 if (rc < 0) {
508 rc = errno;
509 ALOGE("%s: error stat'ing file (fd=%d): %s\n",
510 __func__, fd, strerror(errno));
511 msg->result = translate_errno(rc);
512 goto err_response;
513 }
514
515 resp.size = stat.st_size;
516 msg->result = STORAGE_NO_ERROR;
517 return ipc_respond(msg, &resp, sizeof(resp));
518
519 err_response:
520 return ipc_respond(msg, NULL, 0);
521 }
522
523
storage_file_set_size(struct storage_msg * msg,const void * r,size_t req_len)524 int storage_file_set_size(struct storage_msg *msg,
525 const void *r, size_t req_len)
526 {
527 const struct storage_file_set_size_req *req = r;
528
529 if (req_len != sizeof(*req)) {
530 ALOGE("%s: invalid request length (%zd != %zd)\n",
531 __func__, req_len, sizeof(*req));
532 msg->result = STORAGE_ERR_NOT_VALID;
533 goto err_response;
534 }
535
536 int fd = lookup_fd(req->handle, true);
537 int rc = TEMP_FAILURE_RETRY(ftruncate(fd, req->size));
538 if (rc < 0) {
539 rc = errno;
540 ALOGE("%s: error truncating file (fd=%d): %s\n",
541 __func__, fd, strerror(errno));
542 msg->result = translate_errno(rc);
543 goto err_response;
544 }
545
546 msg->result = STORAGE_NO_ERROR;
547
548 err_response:
549 return ipc_respond(msg, NULL, 0);
550 }
551
storage_init(const char * dirname)552 int storage_init(const char *dirname)
553 {
554 /* If there is an active DSU image, use the alternate fs mode. */
555 alternate_mode = is_gsi_running();
556
557 fs_state = SS_CLEAN;
558 for (uint i = 0; i < FD_TBL_SIZE; i++) {
559 fd_state[i] = SS_UNUSED; /* uninstalled */
560 }
561
562 ssdir_name = dirname;
563 return 0;
564 }
565
storage_sync_checkpoint(void)566 int storage_sync_checkpoint(void)
567 {
568 int rc;
569
570 /* sync fd table and reset it to clean state first */
571 for (uint fd = 0; fd < FD_TBL_SIZE; fd++) {
572 if (fd_state[fd] == SS_DIRTY) {
573 if (fs_state == SS_CLEAN) {
574 /* need to sync individual fd */
575 rc = fsync(fd);
576 if (rc < 0) {
577 ALOGE("fsync for fd=%d failed: %s\n", fd, strerror(errno));
578 return rc;
579 }
580 }
581 fd_state[fd] = SS_CLEAN; /* set to clean */
582 }
583 }
584
585 /* check if we need to sync all filesystems */
586 if (fs_state == SS_DIRTY) {
587 /*
588 * We sync all filesystems here because we don't know what filesystem
589 * needs syncing if there happen to be other filesystems symlinked under
590 * the root data directory. This should not happen in the normal case
591 * because our fd table is large enough to handle the few open files we
592 * use.
593 */
594 sync();
595 fs_state = SS_CLEAN;
596 }
597
598 return 0;
599 }
600
601