• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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