Loading trusty/storage/proxy/proxy.c +70 −3 Original line number Diff line number Diff line Loading @@ -41,9 +41,13 @@ static const char* ss_data_root; static const char* trusty_devname; static const char* rpmb_devname; static const char* ss_srv_name = STORAGE_DISK_PROXY_PORT; static const char* max_file_size_from; static enum dev_type dev_type = MMC_RPMB; /* List head for storage mapping, elements added at init, and never removed */ static struct storage_mapping_node* storage_mapping_head; static enum dev_type parse_dev_type(const char* dev_type_name) { if (!strcmp(dev_type_name, "mmc")) { return MMC_RPMB; Loading @@ -58,17 +62,61 @@ static enum dev_type parse_dev_type(const char* dev_type_name) { } } static const char* _sopts = "hp:d:r:t:"; static int parse_and_append_file_mapping(const char* file_mapping) { if (file_mapping == NULL) { ALOGE("Provided file mapping is null\n"); return -1; } char* file_mapping_dup = strdup(file_mapping); if (file_mapping_dup == NULL) { ALOGE("Couldn't duplicate string: %s\n", file_mapping); return -1; } const char* file_name = strtok(file_mapping_dup, ":"); if (file_name == NULL) { ALOGE("No file name found\n"); return -1; } const char* backing_storage = strtok(NULL, ":"); if (backing_storage == NULL) { ALOGE("No backing storage found\n"); return -1; } struct storage_mapping_node* new_node = malloc(sizeof(struct storage_mapping_node)); if (new_node == NULL) { ALOGE("Couldn't allocate additional storage_mapping_node\n"); return -1; } *new_node = (struct storage_mapping_node){.file_name = file_name, .backing_storage = backing_storage, .next = storage_mapping_head, .fd = -1}; storage_mapping_head = new_node; return 0; } static const char* _sopts = "hp:d:r:t:m:f:"; static const struct option _lopts[] = {{"help", no_argument, NULL, 'h'}, {"trusty_dev", required_argument, NULL, 'd'}, {"data_path", required_argument, NULL, 'p'}, {"rpmb_dev", required_argument, NULL, 'r'}, {"dev_type", required_argument, NULL, 't'}, {"max_file_size_from", required_argument, NULL, 'm'}, {"file_storage_mapping", required_argument, NULL, 'f'}, {0, 0, 0, 0}}; static void show_usage_and_exit(int code) { ALOGE("usage: storageproxyd -d <trusty_dev> -p <data_path> -r <rpmb_dev> -t <dev_type>\n"); ALOGE("usage: storageproxyd -d <trusty_dev> -p <data_path> -r <rpmb_dev> -t <dev_type> [-m " "<file>] [-f <file>:<mapping>]\n"); ALOGE("Available dev types: mmc, virt\n"); ALOGE("-f = Maps secure storage files like `0` and `persist/0`\n" "to block devices. Storageproxyd will handle creating the\n" "appropriate symlinks in the root datapath.\n"); ALOGE("-m = Specifies the max size constraint for file backed storages.\n" "The constraint is chosen by giving a file, this allows for passing a\n" "block device for which a max file size can be queried. File based\n" "storages will be constrained to that size as well.\n"); exit(code); } Loading Loading @@ -187,6 +235,7 @@ static int proxy_loop(void) { static void parse_args(int argc, char* argv[]) { int opt; int oidx = 0; int rc = 0; while ((opt = getopt_long(argc, argv, _sopts, _lopts, &oidx)) != -1) { switch (opt) { Loading @@ -210,6 +259,18 @@ static void parse_args(int argc, char* argv[]) { } break; case 'f': rc = parse_and_append_file_mapping(optarg); if (rc < 0) { ALOGE("Failed to parse file mapping: %s\n", optarg); show_usage_and_exit(EXIT_FAILURE); } break; case 'm': max_file_size_from = strdup(optarg); break; default: ALOGE("unrecognized option (%c):\n", opt); show_usage_and_exit(EXIT_FAILURE); Loading @@ -225,6 +286,12 @@ static void parse_args(int argc, char* argv[]) { ALOGI("storage data root: %s\n", ss_data_root); ALOGI("trusty dev: %s\n", trusty_devname); ALOGI("rpmb dev: %s\n", rpmb_devname); ALOGI("File Mappings: \n"); const struct storage_mapping_node* curr = storage_mapping_head; for (; curr != NULL; curr = curr->next) { ALOGI("\t%s -> %s\n", curr->file_name, curr->backing_storage); } ALOGI("max file size from: %s\n", max_file_size_from ? max_file_size_from : "(unset)"); } int main(int argc, char* argv[]) { Loading Loading @@ -252,7 +319,7 @@ int main(int argc, char* argv[]) { ABinderProcess_startThreadPool(); /* initialize secure storage directory */ rc = storage_init(ss_data_root); rc = storage_init(ss_data_root, storage_mapping_head, max_file_size_from); if (rc < 0) return EXIT_FAILURE; /* open rpmb device */ Loading trusty/storage/proxy/storage.c +260 −27 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ #include <assert.h> #include <cutils/properties.h> #include <errno.h> #include <fcntl.h> Loading @@ -39,16 +40,20 @@ #define ALTERNATE_DATA_DIR "alternate/" /* Maximum file size for filesystem backed storage (i.e. not block dev backed storage) */ #define MAX_FILE_SIZE (0x10000000000) static size_t max_file_size = 0x10000000000; enum sync_state { SS_UNUSED = -1, SS_CLEAN = 0, SS_DIRTY = 1, SS_CLEAN_NEED_SYMLINK = 2, }; static const char *ssdir_name; /* List head for storage mapping, elements added at init, and never removed */ static struct storage_mapping_node* storage_mapping_head; /* * Property set to 1 after we have opened a file under ssdir_name. The backing * files for both TD and TDP are currently located under /data/vendor/ss and can Loading @@ -75,24 +80,103 @@ static struct { uint8_t data[MAX_READ_SIZE]; } read_rsp; static uint32_t insert_fd(int open_flags, int fd) { static uint32_t insert_fd(int open_flags, int fd, struct storage_mapping_node* node) { uint32_t handle = fd; if (handle < FD_TBL_SIZE) { fd_state[fd] = SS_CLEAN; /* fd clean */ if (open_flags & O_TRUNC) { assert(node == NULL); fd_state[fd] = SS_DIRTY; /* set fd dirty */ } if (node != NULL) { fd_state[fd] = SS_CLEAN_NEED_SYMLINK; } } else { ALOGW("%s: untracked fd %u\n", __func__, fd); if (open_flags & (O_TRUNC | O_CREAT)) { fs_state = SS_DIRTY; } } if (node != NULL) { node->fd = fd; } return handle; } static void clear_fd_symlink_status(uint32_t handle, struct storage_mapping_node* entry) { /* Always clear FD, in case fd is not in FD_TBL */ entry->fd = -1; if (handle >= FD_TBL_SIZE) { ALOGE("%s: untracked fd=%u\n", __func__, handle); return; } if (fd_state[handle] == SS_CLEAN_NEED_SYMLINK) { fd_state[handle] = SS_CLEAN; } } static struct storage_mapping_node* get_pending_symlink_mapping(uint32_t handle) { /* Fast lookup failure, is it in FD TBL */ if (handle < FD_TBL_SIZE && fd_state[handle] != SS_CLEAN_NEED_SYMLINK) { return NULL; } /* Go find our mapping */ struct storage_mapping_node* curr = storage_mapping_head; for (; curr != NULL; curr = curr->next) { if (curr->fd == handle) { return curr; } } /* Safety check: state inconsistent if we get here with handle inside table range */ assert(handle >= FD_TBL_SIZE); return NULL; }; static int possibly_symlink_and_clear_mapping(uint32_t handle) { struct storage_mapping_node* entry = get_pending_symlink_mapping(handle); if (entry == NULL) { /* No mappings pending */ return 0; } /* Create full path */ char* path = NULL; int rc = asprintf(&path, "%s/%s", ssdir_name, entry->file_name); if (rc < 0) { ALOGE("%s: asprintf failed\n", __func__); return -1; } /* Try and setup the symlinking */ ALOGI("Creating symlink %s->%s\n", path, entry->backing_storage); rc = symlink(entry->backing_storage, path); if (rc < 0) { ALOGE("%s: error symlinking %s->%s (%s)\n", __func__, path, entry->backing_storage, strerror(errno)); free(path); return rc; } free(path); clear_fd_symlink_status(handle, entry); return rc; } static bool is_pending_symlink(uint32_t handle) { struct storage_mapping_node* entry = get_pending_symlink_mapping(handle); return entry != NULL; } static int lookup_fd(uint32_t handle, bool dirty) { if (dirty) { Loading @@ -107,6 +191,12 @@ static int lookup_fd(uint32_t handle, bool dirty) static int remove_fd(uint32_t handle) { /* Cleanup fd in symlink mapping if it exists */ struct storage_mapping_node* entry = get_pending_symlink_mapping(handle); if (entry != NULL) { entry->fd = -1; } if (handle < FD_TBL_SIZE) { fd_state[handle] = SS_UNUSED; /* set to uninstalled */ } Loading Loading @@ -247,11 +337,73 @@ static void sync_parent(const char* path, struct watcher* watcher) { watch_progress(watcher, "done syncing parent"); } static struct storage_mapping_node* get_storage_mapping_entry(const char* source) { struct storage_mapping_node* curr = storage_mapping_head; for (; curr != NULL; curr = curr->next) { if (!strcmp(source, curr->file_name)) { ALOGI("Found backing file %s for %s\n", curr->backing_storage, source); return curr; } } return NULL; } static bool is_backing_storage_mapped(const char* source) { const struct storage_mapping_node* curr = storage_mapping_head; for (; curr != NULL; curr = curr->next) { if (!strcmp(source, curr->backing_storage)) { ALOGI("Backed storage mapping exists for %s\n", curr->backing_storage); return true; } } return false; } /* Attempts to open a backed file, if mapped, without creating the symlink. Symlink will be created * later on the first write. This allows us to continue reporting zero read sizes until the first * write. */ static int open_possibly_mapped_file(const char* short_path, const char* full_path, int open_flags, struct storage_mapping_node** entry) { /* See if mapping exists, report upstream if there is no mapping. */ struct storage_mapping_node* mapping_entry = get_storage_mapping_entry(short_path); if (mapping_entry == NULL) { return TEMP_FAILURE_RETRY(open(full_path, open_flags, S_IRUSR | S_IWUSR)); } /* Check for existence of root path, we don't allow mappings during early boot */ struct stat buf = {0}; if (stat(ssdir_name, &buf) != 0) { ALOGW("Root path not accessible yet, refuse to open mappings for now.\n"); return -1; } /* We don't support exclusive opening of mapped files */ if (open_flags & O_EXCL) { ALOGE("Requesting exclusive open on backed storage isn't supported: %s\n", full_path); return -1; } /* Try and open mapping file */ open_flags &= ~(O_CREAT | O_EXCL); ALOGI("%s Attempting to open mapped file: %s\n", __func__, mapping_entry->backing_storage); int fd = TEMP_FAILURE_RETRY(open(mapping_entry->backing_storage, open_flags, S_IRUSR | S_IWUSR)); if (fd < 0) { ALOGE("%s Failed to open mapping file: %s\n", __func__, mapping_entry->backing_storage); return -1; } /* Let caller know which entry we used for opening */ *entry = mapping_entry; return fd; } int storage_file_open(struct storage_msg* msg, const void* r, size_t req_len, struct watcher* watcher) { char* path = NULL; const struct storage_file_open_req *req = r; struct storage_file_open_resp resp = {0}; struct storage_mapping_node* mapping_entry = NULL; if (req_len < sizeof(*req)) { ALOGE("%s: invalid request length (%zd < %zd)\n", Loading Loading @@ -321,14 +473,18 @@ int storage_file_open(struct storage_msg* msg, const void* r, size_t req_len, if (req->flags & STORAGE_FILE_OPEN_CREATE_EXCLUSIVE) { /* create exclusive */ open_flags |= O_CREAT | O_EXCL; rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR)); /* Look for and attempt opening a mapping, else just do normal open. */ rc = open_possibly_mapped_file(req->name, path, open_flags, &mapping_entry); } else { /* try open first */ rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR)); if (rc == -1 && errno == ENOENT) { /* then try open with O_CREATE */ open_flags |= O_CREAT; rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR)); /* Look for and attempt opening a mapping, else just do normal open. */ rc = open_possibly_mapped_file(req->name, path, open_flags, &mapping_entry); } } Loading Loading @@ -356,7 +512,7 @@ int storage_file_open(struct storage_msg* msg, const void* r, size_t req_len, /* at this point rc contains storage file fd */ msg->result = STORAGE_NO_ERROR; resp.handle = insert_fd(open_flags, rc); resp.handle = insert_fd(open_flags, rc, mapping_entry); ALOGV("%s: \"%s\": fd = %u: handle = %d\n", __func__, path, rc, resp.handle); Loading Loading @@ -433,6 +589,14 @@ int storage_file_write(struct storage_msg* msg, const void* r, size_t req_len, goto err_response; } /* Handle any delayed symlinking for this handle if any */ rc = possibly_symlink_and_clear_mapping(req->handle); if (rc < 0) { ALOGE("Failed to symlink storage\n"); msg->result = STORAGE_ERR_GENERIC; goto err_response; } int fd = lookup_fd(req->handle, true); watch_progress(watcher, "writing"); if (write_with_retry(fd, &req->data[0], req_len - sizeof(*req), Loading Loading @@ -479,6 +643,14 @@ int storage_file_read(struct storage_msg* msg, const void* r, size_t req_len, goto err_response; } /* If this handle has a delayed symlink we should report 0 size reads until first write occurs */ if (is_pending_symlink(req->handle)) { ALOGI("Pending symlink: Forcing read result 0.\n"); msg->result = STORAGE_NO_ERROR; return ipc_respond(msg, &read_rsp, sizeof(read_rsp.hdr)); } int fd = lookup_fd(req->handle, false); watch_progress(watcher, "reading"); ssize_t read_res = read_with_retry(fd, read_rsp.hdr.data, req->size, Loading Loading @@ -592,7 +764,7 @@ int storage_file_get_max_size(struct storage_msg* msg, const void* r, size_t req goto err_response; } } else { max_size = MAX_FILE_SIZE; max_size = max_file_size; } resp.max_size = max_size; Loading @@ -603,8 +775,60 @@ err_response: return ipc_respond(msg, NULL, 0); } int storage_init(const char *dirname) { int determine_max_file_size(const char* max_file_size_from) { /* Use default if none passed in */ if (max_file_size_from == NULL) { ALOGI("No max file source given, continuing to use default: 0x%lx\n", max_file_size); return 0; } /* Check that max_file_size_from is part of our mapping list. */ if (!is_backing_storage_mapped(max_file_size_from)) { ALOGE("%s: file doesn't match mapped storages (filename=%s)\n", __func__, max_file_size_from); return -1; } ALOGI("Using %s to determine max file size.\n", max_file_size_from); /* Error if max file size source not found, possible misconfig. */ struct stat buf = {0}; int rc = stat(max_file_size_from, &buf); if (rc < 0) { ALOGE("%s: error stat'ing file (filename=%s): %s\n", __func__, max_file_size_from, strerror(errno)); return -1; } /* Currently only support block device as max file size source */ if ((buf.st_mode & S_IFMT) != S_IFBLK) { ALOGE("Unsupported max file size source type: %d\n", buf.st_mode); return -1; } ALOGI("%s is a block device, determining block device size\n", max_file_size_from); uint64_t max_size = 0; int fd = TEMP_FAILURE_RETRY(open(max_file_size_from, O_RDONLY | O_NONBLOCK)); if (fd < 0) { ALOGE("%s: failed to open backing file %s for ioctl: %s\n", __func__, max_file_size_from, strerror(errno)); return -1; } rc = ioctl(fd, BLKGETSIZE64, &max_size); if (rc < 0) { ALOGE("%s: error calling ioctl on file (fd=%d): %s\n", __func__, fd, strerror(errno)); close(fd); return -1; } close(fd); max_file_size = max_size; ALOGI("Using 0x%lx as max file size\n", max_file_size); return 0; } int storage_init(const char* dirname, struct storage_mapping_node* mappings, const char* max_file_size_from) { /* If there is an active DSU image, use the alternate fs mode. */ alternate_mode = is_gsi_running(); Loading @@ -614,6 +838,15 @@ int storage_init(const char *dirname) } ssdir_name = dirname; storage_mapping_head = mappings; /* Set the max file size based on incoming configuration */ int rc = determine_max_file_size(max_file_size_from); if (rc < 0) { return rc; } return 0; } Loading trusty/storage/proxy/storage.h +10 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,14 @@ /* Defined in watchdog.h */ struct watcher; /* Is used for managing alternate backing storage, generally will be a block device. */ struct storage_mapping_node { struct storage_mapping_node* next; const char* file_name; const char* backing_storage; int fd; }; int storage_file_delete(struct storage_msg* msg, const void* req, size_t req_len, struct watcher* watcher); Loading @@ -45,6 +53,7 @@ int storage_file_set_size(struct storage_msg* msg, const void* req, size_t req_l int storage_file_get_max_size(struct storage_msg* msg, const void* req, size_t req_len, struct watcher* watcher); int storage_init(const char* dirname); int storage_init(const char* dirname, struct storage_mapping_node* head, const char* max_file_size_from); int storage_sync_checkpoint(struct watcher* watcher); Loading
trusty/storage/proxy/proxy.c +70 −3 Original line number Diff line number Diff line Loading @@ -41,9 +41,13 @@ static const char* ss_data_root; static const char* trusty_devname; static const char* rpmb_devname; static const char* ss_srv_name = STORAGE_DISK_PROXY_PORT; static const char* max_file_size_from; static enum dev_type dev_type = MMC_RPMB; /* List head for storage mapping, elements added at init, and never removed */ static struct storage_mapping_node* storage_mapping_head; static enum dev_type parse_dev_type(const char* dev_type_name) { if (!strcmp(dev_type_name, "mmc")) { return MMC_RPMB; Loading @@ -58,17 +62,61 @@ static enum dev_type parse_dev_type(const char* dev_type_name) { } } static const char* _sopts = "hp:d:r:t:"; static int parse_and_append_file_mapping(const char* file_mapping) { if (file_mapping == NULL) { ALOGE("Provided file mapping is null\n"); return -1; } char* file_mapping_dup = strdup(file_mapping); if (file_mapping_dup == NULL) { ALOGE("Couldn't duplicate string: %s\n", file_mapping); return -1; } const char* file_name = strtok(file_mapping_dup, ":"); if (file_name == NULL) { ALOGE("No file name found\n"); return -1; } const char* backing_storage = strtok(NULL, ":"); if (backing_storage == NULL) { ALOGE("No backing storage found\n"); return -1; } struct storage_mapping_node* new_node = malloc(sizeof(struct storage_mapping_node)); if (new_node == NULL) { ALOGE("Couldn't allocate additional storage_mapping_node\n"); return -1; } *new_node = (struct storage_mapping_node){.file_name = file_name, .backing_storage = backing_storage, .next = storage_mapping_head, .fd = -1}; storage_mapping_head = new_node; return 0; } static const char* _sopts = "hp:d:r:t:m:f:"; static const struct option _lopts[] = {{"help", no_argument, NULL, 'h'}, {"trusty_dev", required_argument, NULL, 'd'}, {"data_path", required_argument, NULL, 'p'}, {"rpmb_dev", required_argument, NULL, 'r'}, {"dev_type", required_argument, NULL, 't'}, {"max_file_size_from", required_argument, NULL, 'm'}, {"file_storage_mapping", required_argument, NULL, 'f'}, {0, 0, 0, 0}}; static void show_usage_and_exit(int code) { ALOGE("usage: storageproxyd -d <trusty_dev> -p <data_path> -r <rpmb_dev> -t <dev_type>\n"); ALOGE("usage: storageproxyd -d <trusty_dev> -p <data_path> -r <rpmb_dev> -t <dev_type> [-m " "<file>] [-f <file>:<mapping>]\n"); ALOGE("Available dev types: mmc, virt\n"); ALOGE("-f = Maps secure storage files like `0` and `persist/0`\n" "to block devices. Storageproxyd will handle creating the\n" "appropriate symlinks in the root datapath.\n"); ALOGE("-m = Specifies the max size constraint for file backed storages.\n" "The constraint is chosen by giving a file, this allows for passing a\n" "block device for which a max file size can be queried. File based\n" "storages will be constrained to that size as well.\n"); exit(code); } Loading Loading @@ -187,6 +235,7 @@ static int proxy_loop(void) { static void parse_args(int argc, char* argv[]) { int opt; int oidx = 0; int rc = 0; while ((opt = getopt_long(argc, argv, _sopts, _lopts, &oidx)) != -1) { switch (opt) { Loading @@ -210,6 +259,18 @@ static void parse_args(int argc, char* argv[]) { } break; case 'f': rc = parse_and_append_file_mapping(optarg); if (rc < 0) { ALOGE("Failed to parse file mapping: %s\n", optarg); show_usage_and_exit(EXIT_FAILURE); } break; case 'm': max_file_size_from = strdup(optarg); break; default: ALOGE("unrecognized option (%c):\n", opt); show_usage_and_exit(EXIT_FAILURE); Loading @@ -225,6 +286,12 @@ static void parse_args(int argc, char* argv[]) { ALOGI("storage data root: %s\n", ss_data_root); ALOGI("trusty dev: %s\n", trusty_devname); ALOGI("rpmb dev: %s\n", rpmb_devname); ALOGI("File Mappings: \n"); const struct storage_mapping_node* curr = storage_mapping_head; for (; curr != NULL; curr = curr->next) { ALOGI("\t%s -> %s\n", curr->file_name, curr->backing_storage); } ALOGI("max file size from: %s\n", max_file_size_from ? max_file_size_from : "(unset)"); } int main(int argc, char* argv[]) { Loading Loading @@ -252,7 +319,7 @@ int main(int argc, char* argv[]) { ABinderProcess_startThreadPool(); /* initialize secure storage directory */ rc = storage_init(ss_data_root); rc = storage_init(ss_data_root, storage_mapping_head, max_file_size_from); if (rc < 0) return EXIT_FAILURE; /* open rpmb device */ Loading
trusty/storage/proxy/storage.c +260 −27 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ #include <assert.h> #include <cutils/properties.h> #include <errno.h> #include <fcntl.h> Loading @@ -39,16 +40,20 @@ #define ALTERNATE_DATA_DIR "alternate/" /* Maximum file size for filesystem backed storage (i.e. not block dev backed storage) */ #define MAX_FILE_SIZE (0x10000000000) static size_t max_file_size = 0x10000000000; enum sync_state { SS_UNUSED = -1, SS_CLEAN = 0, SS_DIRTY = 1, SS_CLEAN_NEED_SYMLINK = 2, }; static const char *ssdir_name; /* List head for storage mapping, elements added at init, and never removed */ static struct storage_mapping_node* storage_mapping_head; /* * Property set to 1 after we have opened a file under ssdir_name. The backing * files for both TD and TDP are currently located under /data/vendor/ss and can Loading @@ -75,24 +80,103 @@ static struct { uint8_t data[MAX_READ_SIZE]; } read_rsp; static uint32_t insert_fd(int open_flags, int fd) { static uint32_t insert_fd(int open_flags, int fd, struct storage_mapping_node* node) { uint32_t handle = fd; if (handle < FD_TBL_SIZE) { fd_state[fd] = SS_CLEAN; /* fd clean */ if (open_flags & O_TRUNC) { assert(node == NULL); fd_state[fd] = SS_DIRTY; /* set fd dirty */ } if (node != NULL) { fd_state[fd] = SS_CLEAN_NEED_SYMLINK; } } else { ALOGW("%s: untracked fd %u\n", __func__, fd); if (open_flags & (O_TRUNC | O_CREAT)) { fs_state = SS_DIRTY; } } if (node != NULL) { node->fd = fd; } return handle; } static void clear_fd_symlink_status(uint32_t handle, struct storage_mapping_node* entry) { /* Always clear FD, in case fd is not in FD_TBL */ entry->fd = -1; if (handle >= FD_TBL_SIZE) { ALOGE("%s: untracked fd=%u\n", __func__, handle); return; } if (fd_state[handle] == SS_CLEAN_NEED_SYMLINK) { fd_state[handle] = SS_CLEAN; } } static struct storage_mapping_node* get_pending_symlink_mapping(uint32_t handle) { /* Fast lookup failure, is it in FD TBL */ if (handle < FD_TBL_SIZE && fd_state[handle] != SS_CLEAN_NEED_SYMLINK) { return NULL; } /* Go find our mapping */ struct storage_mapping_node* curr = storage_mapping_head; for (; curr != NULL; curr = curr->next) { if (curr->fd == handle) { return curr; } } /* Safety check: state inconsistent if we get here with handle inside table range */ assert(handle >= FD_TBL_SIZE); return NULL; }; static int possibly_symlink_and_clear_mapping(uint32_t handle) { struct storage_mapping_node* entry = get_pending_symlink_mapping(handle); if (entry == NULL) { /* No mappings pending */ return 0; } /* Create full path */ char* path = NULL; int rc = asprintf(&path, "%s/%s", ssdir_name, entry->file_name); if (rc < 0) { ALOGE("%s: asprintf failed\n", __func__); return -1; } /* Try and setup the symlinking */ ALOGI("Creating symlink %s->%s\n", path, entry->backing_storage); rc = symlink(entry->backing_storage, path); if (rc < 0) { ALOGE("%s: error symlinking %s->%s (%s)\n", __func__, path, entry->backing_storage, strerror(errno)); free(path); return rc; } free(path); clear_fd_symlink_status(handle, entry); return rc; } static bool is_pending_symlink(uint32_t handle) { struct storage_mapping_node* entry = get_pending_symlink_mapping(handle); return entry != NULL; } static int lookup_fd(uint32_t handle, bool dirty) { if (dirty) { Loading @@ -107,6 +191,12 @@ static int lookup_fd(uint32_t handle, bool dirty) static int remove_fd(uint32_t handle) { /* Cleanup fd in symlink mapping if it exists */ struct storage_mapping_node* entry = get_pending_symlink_mapping(handle); if (entry != NULL) { entry->fd = -1; } if (handle < FD_TBL_SIZE) { fd_state[handle] = SS_UNUSED; /* set to uninstalled */ } Loading Loading @@ -247,11 +337,73 @@ static void sync_parent(const char* path, struct watcher* watcher) { watch_progress(watcher, "done syncing parent"); } static struct storage_mapping_node* get_storage_mapping_entry(const char* source) { struct storage_mapping_node* curr = storage_mapping_head; for (; curr != NULL; curr = curr->next) { if (!strcmp(source, curr->file_name)) { ALOGI("Found backing file %s for %s\n", curr->backing_storage, source); return curr; } } return NULL; } static bool is_backing_storage_mapped(const char* source) { const struct storage_mapping_node* curr = storage_mapping_head; for (; curr != NULL; curr = curr->next) { if (!strcmp(source, curr->backing_storage)) { ALOGI("Backed storage mapping exists for %s\n", curr->backing_storage); return true; } } return false; } /* Attempts to open a backed file, if mapped, without creating the symlink. Symlink will be created * later on the first write. This allows us to continue reporting zero read sizes until the first * write. */ static int open_possibly_mapped_file(const char* short_path, const char* full_path, int open_flags, struct storage_mapping_node** entry) { /* See if mapping exists, report upstream if there is no mapping. */ struct storage_mapping_node* mapping_entry = get_storage_mapping_entry(short_path); if (mapping_entry == NULL) { return TEMP_FAILURE_RETRY(open(full_path, open_flags, S_IRUSR | S_IWUSR)); } /* Check for existence of root path, we don't allow mappings during early boot */ struct stat buf = {0}; if (stat(ssdir_name, &buf) != 0) { ALOGW("Root path not accessible yet, refuse to open mappings for now.\n"); return -1; } /* We don't support exclusive opening of mapped files */ if (open_flags & O_EXCL) { ALOGE("Requesting exclusive open on backed storage isn't supported: %s\n", full_path); return -1; } /* Try and open mapping file */ open_flags &= ~(O_CREAT | O_EXCL); ALOGI("%s Attempting to open mapped file: %s\n", __func__, mapping_entry->backing_storage); int fd = TEMP_FAILURE_RETRY(open(mapping_entry->backing_storage, open_flags, S_IRUSR | S_IWUSR)); if (fd < 0) { ALOGE("%s Failed to open mapping file: %s\n", __func__, mapping_entry->backing_storage); return -1; } /* Let caller know which entry we used for opening */ *entry = mapping_entry; return fd; } int storage_file_open(struct storage_msg* msg, const void* r, size_t req_len, struct watcher* watcher) { char* path = NULL; const struct storage_file_open_req *req = r; struct storage_file_open_resp resp = {0}; struct storage_mapping_node* mapping_entry = NULL; if (req_len < sizeof(*req)) { ALOGE("%s: invalid request length (%zd < %zd)\n", Loading Loading @@ -321,14 +473,18 @@ int storage_file_open(struct storage_msg* msg, const void* r, size_t req_len, if (req->flags & STORAGE_FILE_OPEN_CREATE_EXCLUSIVE) { /* create exclusive */ open_flags |= O_CREAT | O_EXCL; rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR)); /* Look for and attempt opening a mapping, else just do normal open. */ rc = open_possibly_mapped_file(req->name, path, open_flags, &mapping_entry); } else { /* try open first */ rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR)); if (rc == -1 && errno == ENOENT) { /* then try open with O_CREATE */ open_flags |= O_CREAT; rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR)); /* Look for and attempt opening a mapping, else just do normal open. */ rc = open_possibly_mapped_file(req->name, path, open_flags, &mapping_entry); } } Loading Loading @@ -356,7 +512,7 @@ int storage_file_open(struct storage_msg* msg, const void* r, size_t req_len, /* at this point rc contains storage file fd */ msg->result = STORAGE_NO_ERROR; resp.handle = insert_fd(open_flags, rc); resp.handle = insert_fd(open_flags, rc, mapping_entry); ALOGV("%s: \"%s\": fd = %u: handle = %d\n", __func__, path, rc, resp.handle); Loading Loading @@ -433,6 +589,14 @@ int storage_file_write(struct storage_msg* msg, const void* r, size_t req_len, goto err_response; } /* Handle any delayed symlinking for this handle if any */ rc = possibly_symlink_and_clear_mapping(req->handle); if (rc < 0) { ALOGE("Failed to symlink storage\n"); msg->result = STORAGE_ERR_GENERIC; goto err_response; } int fd = lookup_fd(req->handle, true); watch_progress(watcher, "writing"); if (write_with_retry(fd, &req->data[0], req_len - sizeof(*req), Loading Loading @@ -479,6 +643,14 @@ int storage_file_read(struct storage_msg* msg, const void* r, size_t req_len, goto err_response; } /* If this handle has a delayed symlink we should report 0 size reads until first write occurs */ if (is_pending_symlink(req->handle)) { ALOGI("Pending symlink: Forcing read result 0.\n"); msg->result = STORAGE_NO_ERROR; return ipc_respond(msg, &read_rsp, sizeof(read_rsp.hdr)); } int fd = lookup_fd(req->handle, false); watch_progress(watcher, "reading"); ssize_t read_res = read_with_retry(fd, read_rsp.hdr.data, req->size, Loading Loading @@ -592,7 +764,7 @@ int storage_file_get_max_size(struct storage_msg* msg, const void* r, size_t req goto err_response; } } else { max_size = MAX_FILE_SIZE; max_size = max_file_size; } resp.max_size = max_size; Loading @@ -603,8 +775,60 @@ err_response: return ipc_respond(msg, NULL, 0); } int storage_init(const char *dirname) { int determine_max_file_size(const char* max_file_size_from) { /* Use default if none passed in */ if (max_file_size_from == NULL) { ALOGI("No max file source given, continuing to use default: 0x%lx\n", max_file_size); return 0; } /* Check that max_file_size_from is part of our mapping list. */ if (!is_backing_storage_mapped(max_file_size_from)) { ALOGE("%s: file doesn't match mapped storages (filename=%s)\n", __func__, max_file_size_from); return -1; } ALOGI("Using %s to determine max file size.\n", max_file_size_from); /* Error if max file size source not found, possible misconfig. */ struct stat buf = {0}; int rc = stat(max_file_size_from, &buf); if (rc < 0) { ALOGE("%s: error stat'ing file (filename=%s): %s\n", __func__, max_file_size_from, strerror(errno)); return -1; } /* Currently only support block device as max file size source */ if ((buf.st_mode & S_IFMT) != S_IFBLK) { ALOGE("Unsupported max file size source type: %d\n", buf.st_mode); return -1; } ALOGI("%s is a block device, determining block device size\n", max_file_size_from); uint64_t max_size = 0; int fd = TEMP_FAILURE_RETRY(open(max_file_size_from, O_RDONLY | O_NONBLOCK)); if (fd < 0) { ALOGE("%s: failed to open backing file %s for ioctl: %s\n", __func__, max_file_size_from, strerror(errno)); return -1; } rc = ioctl(fd, BLKGETSIZE64, &max_size); if (rc < 0) { ALOGE("%s: error calling ioctl on file (fd=%d): %s\n", __func__, fd, strerror(errno)); close(fd); return -1; } close(fd); max_file_size = max_size; ALOGI("Using 0x%lx as max file size\n", max_file_size); return 0; } int storage_init(const char* dirname, struct storage_mapping_node* mappings, const char* max_file_size_from) { /* If there is an active DSU image, use the alternate fs mode. */ alternate_mode = is_gsi_running(); Loading @@ -614,6 +838,15 @@ int storage_init(const char *dirname) } ssdir_name = dirname; storage_mapping_head = mappings; /* Set the max file size based on incoming configuration */ int rc = determine_max_file_size(max_file_size_from); if (rc < 0) { return rc; } return 0; } Loading
trusty/storage/proxy/storage.h +10 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,14 @@ /* Defined in watchdog.h */ struct watcher; /* Is used for managing alternate backing storage, generally will be a block device. */ struct storage_mapping_node { struct storage_mapping_node* next; const char* file_name; const char* backing_storage; int fd; }; int storage_file_delete(struct storage_msg* msg, const void* req, size_t req_len, struct watcher* watcher); Loading @@ -45,6 +53,7 @@ int storage_file_set_size(struct storage_msg* msg, const void* req, size_t req_l int storage_file_get_max_size(struct storage_msg* msg, const void* req, size_t req_len, struct watcher* watcher); int storage_init(const char* dirname); int storage_init(const char* dirname, struct storage_mapping_node* head, const char* max_file_size_from); int storage_sync_checkpoint(struct watcher* watcher);