static int tee_supp_fs_readdir(struct tee_fs_rpc *fsrpc) { DIR *dir = handle_lookup(&dir_handle_db, fsrpc->arg); struct dirent *dirent; size_t len; do dirent = readdir(dir); while (dirent != NULL && dirent->d_name[0] == '.'); if (dirent == NULL) { fsrpc->len = 0; return -1; } len = strlen(dirent->d_name); if (len > PATH_MAX) return -1; len++; memcpy((char *)(fsrpc + 1), dirent->d_name, len); fsrpc->len = len; return 0; }
void KVServer::run() { while (1) { socklen_t remote_addr_len = sizeof(remote_addr); printf("Waiting for a packet ...\n"); fflush(stdout); int rc = recvfrom(sock, buffer, MAX_KV_SIZE, 0, (sockaddr*)&remote_addr, &remote_addr_len); if (-1 == rc) { fprintf(stderr, "(KeyValueServer) Failed to receive packet!\n"); exit(1); } lite_assert(rc<MAX_KV_SIZE); // darn -- MAX_KV_SIZE too small for actual usage. lite_assert(rc>=(int)sizeof(KVRequest)); KVRequest* request = (KVRequest*)buffer; switch (request->type) { case TYPE_LOOKUP: handle_lookup(request); break; case TYPE_INSERT: handle_insert(request); break; default: fprintf(stderr, "(KeyValueServer) Dropping malformed request with type %04x.\n", request->type); continue; } } // TODO:Doesn't clean-up after itself yet hash_table_free_discard(&db); }
void web_handler( int rc, int sock ) { size_t clientfd; IP clientaddr; socklen_t addrlen_ret; char request_buf[1024]; char reply_buf[(MAX_ADDRS+1)*FULL_ADDSTRLEN+2]; char *cmd, *params; char *space, *delim; size_t n; addrlen_ret = sizeof(IP); clientfd = accept( sock, (struct sockaddr*)&clientaddr, &addrlen_ret ); n = recv( clientfd, request_buf, sizeof(request_buf) - 1, 0 ); /* Only handle GET requests. */ if( n < 6 || strncmp( "GET /", request_buf, 5 ) != 0 ) { goto done; } else { cmd = request_buf + 5; } /* Safety first */ request_buf[n] = '\0'; space = strchr( cmd, ' ' ); if( space == NULL ) { goto done; } else { *space = '\0'; } delim = strchr( cmd, '?' ); if( delim == NULL ) { goto done; } else { *delim = '\0'; params = delim + 1; } log_debug( "WEB: cmd: '%s', params: '%s'\n", cmd, params); reply_buf[0] = '\n'; reply_buf[1] = '\0'; if( match( cmd, "lookup" ) ) { handle_lookup( reply_buf, params ); } else if( match( cmd, "announce" ) ) { handle_announce( reply_buf, params ); } else if( match( cmd, "blacklist" ) ) { handle_blacklist( reply_buf, params ); } else { reply_buf[0] = '\0'; } sendto( clientfd, reply_buf, strlen( reply_buf ), 0, (struct sockaddr*) &clientaddr, sizeof(IP) ); done:; close( clientfd ); }
int tee_fs_write(int fd, const void *buf, size_t len) { int res = -1; struct tee_fs_fd *fdp = handle_lookup(&fs_handle_db, fd); struct tee_fs_rpc head = { 0 }; if (len == 0) { res = 0; goto exit; } if (buf == NULL) { res = -1; goto exit; } if (fdp == NULL) { res = -1; goto exit; } /* fill in parameters */ head.op = TEE_FS_WRITE; head.fd = fdp->nw_fd; head.len = len; res = tee_fs_send_cmd(&head, (void *)buf, len, TEE_FS_MODE_IN); if (res) goto exit; res = head.res; exit: return res; }
int tee_fs_read(int fd, void *buf, size_t len) { int res = -1; struct tee_fs_fd *fdp = handle_lookup(&fs_handle_db, fd); struct tee_fs_rpc head = { 0 }; if (len == 0) { res = 0; goto exit; } if (fdp == NULL || buf == NULL) { res = -1; goto exit; } /* fill in parameters */ head.op = TEE_FS_READ; head.fd = fdp->nw_fd; head.len = (uint32_t) len; res = tee_fs_send_cmd(&head, (void *)buf, len, TEE_FS_MODE_OUT); if (res) goto exit; res = head.res; exit: return res; }
static tee_fs_off_t sql_fs_lseek(TEE_Result *errno, int fd, tee_fs_off_t offset, int whence) { struct sql_fs_fd *fdp; tee_fs_off_t ret = -1; tee_fs_off_t raw_pos; tee_fs_off_t pos; DMSG("(fd: %d, offset: %" PRId64 ", whence: %d)...", fd, offset, whence); mutex_lock(&sql_fs_mutex); *errno = TEE_ERROR_GENERIC; fdp = handle_lookup(&fs_db, fd); if (!fdp) goto exit_ret; sql_fs_begin_transaction_rpc(); switch (whence) { case TEE_FS_SEEK_SET: pos = offset; break; case TEE_FS_SEEK_CUR: pos = fdp->pos + offset; break; case TEE_FS_SEEK_END: pos = fdp->meta.length + offset; break; default: *errno = TEE_ERROR_BAD_PARAMETERS; goto exit; } raw_pos = pos_to_raw(pos); if (raw_pos < 0) goto exit; raw_pos = tee_fs_rpc_lseek(OPTEE_MSG_RPC_CMD_SQL_FS, fd, raw_pos, TEE_FS_SEEK_SET); if (raw_pos < 0) goto exit; ret = raw_to_pos(raw_pos); if (ret < 0) goto exit; exit: sql_fs_end_transaction_rpc(ret < 0); fdp->pos = ret; exit_ret: mutex_unlock(&sql_fs_mutex); DMSG("...%" PRId64, ret); return ret; }
static int sql_fs_close(int fd) { struct sql_fs_fd *fdp; int ret = -1; DMSG("(fd: %d)...", fd); mutex_lock(&sql_fs_mutex); fdp = handle_lookup(&fs_db, fd); if (!fdp) goto exit; tee_fs_rpc_close(OPTEE_MSG_RPC_CMD_SQL_FS, fd); put_fdp(fdp); ret = 0; exit: mutex_unlock(&sql_fs_mutex); DMSG("...%d", ret); return ret; }
tee_fs_off_t tee_fs_lseek(int fd, tee_fs_off_t offset, int whence) { tee_fs_off_t res = -1; struct tee_fs_fd *fdp = handle_lookup(&fs_handle_db, fd); struct tee_fs_rpc head = { 0 }; if (!fdp) goto exit; /* fill in parameters */ head.op = TEE_FS_SEEK; head.fd = fdp->nw_fd; head.arg = offset; head.flags = whence; res = tee_fs_send_cmd(&head, NULL, 0, TEE_FS_MODE_NONE); if (res) goto exit; res = head.res; exit: return res; }
int run_fuse_sideload(struct provider_vtab* vtab, void* cookie, uint64_t file_size, uint32_t block_size) { int result; uint64_t mem = 0; uint64_t avail = 0; // If something's already mounted on our mountpoint, try to remove // it. (Mostly in case of a previous abnormal exit.) umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_FORCE); if (block_size < 1024) { fprintf(stderr, "block size (%u) is too small\n", block_size); return -1; } if (block_size > (1<<22)) { // 4 MiB fprintf(stderr, "block size (%u) is too large\n", block_size); return -1; } struct fuse_data fd; memset(&fd, 0, sizeof(fd)); fd.vtab = vtab; fd.cookie = cookie; fd.file_size = file_size; fd.block_size = block_size; fd.file_blocks = (file_size == 0) ? 0 : (((file_size-1) / block_size) + 1); if (fd.file_blocks > (1<<18)) { fprintf(stderr, "file has too many blocks (%u)\n", fd.file_blocks); result = -1; goto done; } fd.hashes = (uint8_t*)calloc(fd.file_blocks, SHA256_DIGEST_SIZE); if (fd.hashes == NULL) { fprintf(stderr, "failed to allocate %d bites for hashes\n", fd.file_blocks * SHA256_DIGEST_SIZE); result = -1; goto done; } fd.uid = getuid(); fd.gid = getgid(); fd.curr_block = -1; fd.block_data = (uint8_t*)malloc(block_size); if (fd.block_data == NULL) { fprintf(stderr, "failed to allocate %d bites for block_data\n", block_size); result = -1; goto done; } fd.extra_block = (uint8_t*)malloc(block_size); if (fd.extra_block == NULL) { fprintf(stderr, "failed to allocate %d bites for extra_block\n", block_size); result = -1; goto done; } fd.block_cache_max_size = 0; fd.block_cache_size = 0; fd.block_cache = NULL; mem = free_memory(); avail = mem - (INSTALL_REQUIRED_MEMORY + fd.file_blocks * sizeof(uint8_t*)); if (mem > avail) { uint32_t max_size = avail / fd.block_size; if (max_size > fd.file_blocks) { max_size = fd.file_blocks; } // The cache must be at least 1% of the file size or two blocks, // whichever is larger. if (max_size >= fd.file_blocks/100 && max_size >= 2) { fd.block_cache_max_size = max_size; fd.block_cache = (uint8_t**)calloc(fd.file_blocks, sizeof(uint8_t*)); } } signal(SIGTERM, sig_term); fd.ffd = open("/dev/fuse", O_RDWR); if (fd.ffd < 0) { perror("open /dev/fuse"); result = -1; goto done; } char opts[256]; snprintf(opts, sizeof(opts), ("fd=%d,user_id=%d,group_id=%d,max_read=%u," "allow_other,rootmode=040000"), fd.ffd, fd.uid, fd.gid, block_size); result = mount("/dev/fuse", FUSE_SIDELOAD_HOST_MOUNTPOINT, "fuse", MS_NOSUID | MS_NODEV | MS_RDONLY | MS_NOEXEC, opts); if (result < 0) { perror("mount"); goto done; } uint8_t request_buffer[sizeof(struct fuse_in_header) + PATH_MAX*8]; while (!terminated) { fd_set fds; struct timeval tv; FD_ZERO(&fds); FD_SET(fd.ffd, &fds); tv.tv_sec = 1; tv.tv_usec = 0; int rc = select(fd.ffd+1, &fds, NULL, NULL, &tv); if (rc <= 0) { continue; } ssize_t len = TEMP_FAILURE_RETRY(read(fd.ffd, request_buffer, sizeof(request_buffer))); if (len < 0) { if (errno != EINTR) { perror("read request"); if (errno == ENODEV) { result = -1; break; } } continue; } if ((size_t)len < sizeof(struct fuse_in_header)) { fprintf(stderr, "request too short: len=%zu\n", (size_t)len); continue; } struct fuse_in_header* hdr = (struct fuse_in_header*) request_buffer; void* data = request_buffer + sizeof(struct fuse_in_header); result = -ENOSYS; switch (hdr->opcode) { case FUSE_INIT: result = handle_init(data, &fd, hdr); break; case FUSE_LOOKUP: result = handle_lookup(data, &fd, hdr); break; case FUSE_GETATTR: result = handle_getattr(data, &fd, hdr); break; case FUSE_OPEN: result = handle_open(data, &fd, hdr); break; case FUSE_READ: result = handle_read(data, &fd, hdr); break; case FUSE_FLUSH: result = handle_flush(data, &fd, hdr); break; case FUSE_RELEASE: result = handle_release(data, &fd, hdr); break; default: fprintf(stderr, "unknown fuse request opcode %d\n", hdr->opcode); break; } if (result != NO_STATUS) { struct fuse_out_header outhdr; outhdr.len = sizeof(outhdr); outhdr.error = result; outhdr.unique = hdr->unique; TEMP_FAILURE_RETRY(write(fd.ffd, &outhdr, sizeof(outhdr))); } } done: fd.vtab->close(fd.cookie); result = umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_DETACH); if (result < 0) { printf("fuse_sideload umount failed: %s\n", strerror(errno)); } if (fd.ffd) close(fd.ffd); if (fd.block_cache) { uint32_t n; for (n = 0; n < fd.file_blocks; ++n) { free(fd.block_cache[n]); } free(fd.block_cache); } free(fd.hashes); free(fd.block_data); free(fd.extra_block); return result; }
/* * The actual main function. */ int sntp_main ( int argc, char **argv, const char *sntpVersion ) { int i; int exitcode; int optct; struct event_config * evcfg; /* Initialize logging system - sets up progname */ sntp_init_logging(argv[0]); if (!libevent_version_ok()) exit(EX_SOFTWARE); init_lib(); init_auth(); optct = ntpOptionProcess(&sntpOptions, argc, argv); argc -= optct; argv += optct; debug = OPT_VALUE_SET_DEBUG_LEVEL; TRACE(2, ("init_lib() done, %s%s\n", (ipv4_works) ? "ipv4_works " : "", (ipv6_works) ? "ipv6_works " : "")); ntpver = OPT_VALUE_NTPVERSION; steplimit = OPT_VALUE_STEPLIMIT / 1e3; gap.tv_usec = max(0, OPT_VALUE_GAP * 1000); gap.tv_usec = min(gap.tv_usec, 999999); if (HAVE_OPT(LOGFILE)) open_logfile(OPT_ARG(LOGFILE)); msyslog(LOG_INFO, "%s", sntpVersion); if (0 == argc && !HAVE_OPT(BROADCAST) && !HAVE_OPT(CONCURRENT)) { printf("%s: Must supply at least one of -b hostname, -c hostname, or hostname.\n", progname); exit(EX_USAGE); } /* ** Eventually, we probably want: ** - separate bcst and ucst timeouts (why?) ** - multiple --timeout values in the commandline */ response_timeout = OPT_VALUE_TIMEOUT; response_tv.tv_sec = response_timeout; response_tv.tv_usec = 0; /* IPv6 available? */ if (isc_net_probeipv6() != ISC_R_SUCCESS) { ai_fam_pref = AF_INET; TRACE(1, ("No ipv6 support available, forcing ipv4\n")); } else { /* Check for options -4 and -6 */ if (HAVE_OPT(IPV4)) ai_fam_pref = AF_INET; else if (HAVE_OPT(IPV6)) ai_fam_pref = AF_INET6; } /* TODO: Parse config file if declared */ /* ** Init the KOD system. ** For embedded systems with no writable filesystem, ** -K /dev/null can be used to disable KoD storage. */ kod_init_kod_db(OPT_ARG(KOD), FALSE); // HMS: Should we use arg-defalt for this too? if (HAVE_OPT(KEYFILE)) auth_init(OPT_ARG(KEYFILE), &keys); /* ** Considering employing a variable that prevents functions of doing ** anything until everything is initialized properly ** ** HMS: What exactly does the above mean? */ event_set_log_callback(&sntp_libevent_log_cb); if (debug > 0) event_enable_debug_mode(); #ifdef WORK_THREAD evthread_use_pthreads(); /* we use libevent from main thread only, locks should be academic */ if (debug > 0) evthread_enable_lock_debuging(); #endif evcfg = event_config_new(); if (NULL == evcfg) { printf("%s: event_config_new() failed!\n", progname); return -1; } #ifndef HAVE_SOCKETPAIR event_config_require_features(evcfg, EV_FEATURE_FDS); #endif /* all libevent calls are from main thread */ /* event_config_set_flag(evcfg, EVENT_BASE_FLAG_NOLOCK); */ base = event_base_new_with_config(evcfg); event_config_free(evcfg); if (NULL == base) { printf("%s: event_base_new() failed!\n", progname); return -1; } /* wire into intres resolver */ worker_per_query = TRUE; addremove_io_fd = &sntp_addremove_fd; open_sockets(); if (HAVE_OPT(BROADCAST)) { int cn = STACKCT_OPT( BROADCAST ); const char ** cp = STACKLST_OPT( BROADCAST ); while (cn-- > 0) { handle_lookup(*cp, CTX_BCST); cp++; } } if (HAVE_OPT(CONCURRENT)) { int cn = STACKCT_OPT( CONCURRENT ); const char ** cp = STACKLST_OPT( CONCURRENT ); while (cn-- > 0) { handle_lookup(*cp, CTX_UCST | CTX_CONC); cp++; } } for (i = 0; i < argc; ++i) handle_lookup(argv[i], CTX_UCST); gettimeofday_cached(base, &start_tv); event_base_dispatch(base); event_base_free(base); if (!time_adjusted && (ENABLED_OPT(STEP) || ENABLED_OPT(SLEW))) exitcode = 1; else exitcode = 0; return exitcode; }
static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler, const struct fuse_in_header *hdr, const void *data, size_t data_len) { switch (hdr->opcode) { case FUSE_LOOKUP: { /* bytez[] -> entry_out */ const char* name = data; return handle_lookup(fuse, handler, hdr, name); } case FUSE_FORGET: { const struct fuse_forget_in *req = data; return handle_forget(fuse, handler, hdr, req); } case FUSE_GETATTR: { /* getattr_in -> attr_out */ const struct fuse_getattr_in *req = data; return handle_getattr(fuse, handler, hdr, req); } case FUSE_SETATTR: { /* setattr_in -> attr_out */ const struct fuse_setattr_in *req = data; return handle_setattr(fuse, handler, hdr, req); } // case FUSE_READLINK: // case FUSE_SYMLINK: case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */ const struct fuse_mknod_in *req = data; const char *name = ((const char*) data) + sizeof(*req); return handle_mknod(fuse, handler, hdr, req, name); } case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */ const struct fuse_mkdir_in *req = data; const char *name = ((const char*) data) + sizeof(*req); return handle_mkdir(fuse, handler, hdr, req, name); } case FUSE_UNLINK: { /* bytez[] -> */ const char* name = data; return handle_unlink(fuse, handler, hdr, name); } case FUSE_RMDIR: { /* bytez[] -> */ const char* name = data; return handle_rmdir(fuse, handler, hdr, name); } case FUSE_RENAME: { /* rename_in, oldname, newname -> */ const struct fuse_rename_in *req = data; const char *old_name = ((const char*) data) + sizeof(*req); const char *new_name = old_name + strlen(old_name) + 1; return handle_rename(fuse, handler, hdr, req, old_name, new_name); } // case FUSE_LINK: case FUSE_OPEN: { /* open_in -> open_out */ const struct fuse_open_in *req = data; return handle_open(fuse, handler, hdr, req); } case FUSE_READ: { /* read_in -> byte[] */ const struct fuse_read_in *req = data; return handle_read(fuse, handler, hdr, req); } case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */ const struct fuse_write_in *req = data; const void* buffer = (const __u8*)data + sizeof(*req); return handle_write(fuse, handler, hdr, req, buffer); } case FUSE_STATFS: { /* getattr_in -> attr_out */ return handle_statfs(fuse, handler, hdr); } case FUSE_RELEASE: { /* release_in -> */ const struct fuse_release_in *req = data; return handle_release(fuse, handler, hdr, req); } case FUSE_FSYNC: { const struct fuse_fsync_in *req = data; return handle_fsync(fuse, handler, hdr, req); } // case FUSE_SETXATTR: // case FUSE_GETXATTR: // case FUSE_LISTXATTR: // case FUSE_REMOVEXATTR: case FUSE_FLUSH: { return handle_flush(fuse, handler, hdr); } case FUSE_OPENDIR: { /* open_in -> open_out */ const struct fuse_open_in *req = data; return handle_opendir(fuse, handler, hdr, req); } case FUSE_READDIR: { const struct fuse_read_in *req = data; return handle_readdir(fuse, handler, hdr, req); } case FUSE_RELEASEDIR: { /* release_in -> */ const struct fuse_release_in *req = data; return handle_releasedir(fuse, handler, hdr, req); } // case FUSE_FSYNCDIR: case FUSE_INIT: { /* init_in -> init_out */ const struct fuse_init_in *req = data; return handle_init(fuse, handler, hdr, req); } default: { TRACE("[%d] NOTIMPL op=%d uniq=%llx nid=%llx\n", handler->token, hdr->opcode, hdr->unique, hdr->nodeid); return -ENOSYS; } } }
static int sql_fs_write(TEE_Result *errno, int fd, const void *buf, size_t len) { struct sql_fs_fd *fdp; size_t remain_bytes = len; const uint8_t *data_ptr = buf; int start_block_num; int end_block_num; int res = -1; int ret; DMSG("(fd: %d, buf: %p, len: %zu)...", fd, (void *)buf, len); mutex_lock(&sql_fs_mutex); *errno = TEE_ERROR_GENERIC; fdp = handle_lookup(&fs_db, fd); if (!fdp) { *errno = TEE_ERROR_BAD_PARAMETERS; goto exit_ret; } if (!len) { res = 0; goto exit_ret; } if (!buf) { *errno = TEE_ERROR_BAD_PARAMETERS; goto exit_ret; } if (fdp->flags & TEE_FS_O_RDONLY) { *errno = TEE_ERROR_ACCESS_CONFLICT; goto exit_ret; } sql_fs_begin_transaction_rpc(); if (fdp->meta.length < (size_t)fdp->pos) { /* Fill hole */ res = sql_fs_ftruncate_internal(errno, fd, fdp->pos); if (res < 0) goto exit; } start_block_num = block_num(fdp->pos); end_block_num = block_num(fdp->pos + len - 1); while (start_block_num <= end_block_num) { tee_fs_off_t offset = fdp->pos % BLOCK_SIZE; size_t size_to_write = MIN(remain_bytes, (size_t)BLOCK_SIZE); if (size_to_write + offset > BLOCK_SIZE) size_to_write = BLOCK_SIZE - offset; res = write_block_partial(errno, fdp, start_block_num, data_ptr, size_to_write, offset); if (res < 0) goto exit; data_ptr += size_to_write; remain_bytes -= size_to_write; fdp->pos += size_to_write; start_block_num++; } fdp->meta.length = fdp->pos; res = write_meta(errno, fdp); exit: sql_fs_end_transaction_rpc(res < 0); exit_ret: mutex_unlock(&sql_fs_mutex); ret = (res < 0) ? res : (int)len; DMSG("...%d", ret); return ret; }
static int sql_fs_read(TEE_Result *errno, int fd, void *buf, size_t len) { struct sql_fs_fd *fdp; size_t remain_bytes = len; uint8_t *data_ptr = buf; uint8_t *block = NULL; int start_block_num; int end_block_num; int res = -1; int ret; DMSG("(fd: %d, buf: %p, len: %zu)...", fd, (void *)buf, len); mutex_lock(&sql_fs_mutex); *errno = TEE_ERROR_GENERIC; fdp = handle_lookup(&fs_db, fd); if (!fdp) { *errno = TEE_ERROR_BAD_PARAMETERS; goto exit_ret; } if ((fdp->pos + len) < len || fdp->pos > (tee_fs_off_t)fdp->meta.length) len = 0; else if (fdp->pos + len > fdp->meta.length) len = fdp->meta.length - fdp->pos; if (!len) { res = 0; goto exit_ret; } if (!buf) { *errno = TEE_ERROR_BAD_PARAMETERS; goto exit_ret; } if (fdp->flags & TEE_FS_O_WRONLY) { *errno = TEE_ERROR_ACCESS_CONFLICT; goto exit_ret; } start_block_num = block_num(fdp->pos); end_block_num = block_num(fdp->pos + len - 1); block = malloc(BLOCK_SIZE); if (!block) { *errno = TEE_ERROR_OUT_OF_MEMORY; goto exit_ret; } sql_fs_begin_transaction_rpc(); while (start_block_num <= end_block_num) { tee_fs_off_t offset = fdp->pos % BLOCK_SIZE; size_t size_to_read = MIN(remain_bytes, (size_t)BLOCK_SIZE); if (size_to_read + offset > BLOCK_SIZE) size_to_read = BLOCK_SIZE - offset; /* * REVISIT: implement read_block_partial() since we have * write_block_partial()? */ res = read_block(errno, fdp, start_block_num, block); if (res < 0) goto exit; memcpy(data_ptr, block + offset, size_to_read); data_ptr += size_to_read; remain_bytes -= size_to_read; fdp->pos += size_to_read; start_block_num++; } res = 0; exit: sql_fs_end_transaction_rpc(res < 0); free(block); exit_ret: mutex_unlock(&sql_fs_mutex); ret = (res < 0) ? res : (int)len; DMSG("...%d", ret); return ret; }
static int sql_fs_ftruncate_internal(TEE_Result *errno, int fd, tee_fs_off_t new_length) { struct sql_fs_fd *fdp; tee_fs_off_t old_length; int rc = -1; DMSG("(fd: %d, new_length: %" PRId64 ")...", fd, new_length); *errno = TEE_ERROR_GENERIC; fdp = handle_lookup(&fs_db, fd); if (!fdp) { *errno = TEE_ERROR_BAD_PARAMETERS; goto exit_ret; } old_length = (tee_fs_off_t)fdp->meta.length; if (new_length == old_length) { rc = 0; goto exit_ret; } sql_fs_begin_transaction_rpc(); if (new_length < old_length) { /* Trim unused blocks */ int old_last_block = block_num(old_length); int last_block = block_num(new_length); tee_fs_off_t off; if (last_block < old_last_block) { off = block_pos_raw(last_block); rc = tee_fs_rpc_ftruncate(OPTEE_MSG_RPC_CMD_SQL_FS, fd, off); if (rc < 0) goto exit; } } else { /* Extend file with zeroes */ tee_fs_off_t off = old_length % BLOCK_SIZE; size_t bnum = block_num(old_length); size_t end_bnum = block_num(new_length); while (bnum <= end_bnum) { size_t len = (size_t)BLOCK_SIZE - (size_t)off; rc = write_block_partial(errno, fdp, bnum, NULL, len, off); if (rc < 0) goto exit; off = 0; bnum++; } } fdp->meta.length = new_length; rc = write_meta(errno, fdp); exit: sql_fs_end_transaction_rpc(rc < 0); exit_ret: DMSG("...%d", rc); return rc; }
struct tee_fs_fd *tee_fs_fd_lookup(int fd) { return handle_lookup(&fs_handle_db, fd); }
int run_fuse_sideload(struct provider_vtab* vtab, void* cookie, uint64_t file_size, uint32_t block_size) { int result; // If something's already mounted on our mountpoint, try to remove // it. (Mostly in case of a previous abnormal exit.) umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_FORCE); if (block_size < 1024) { fprintf(stderr, "block size (%u) is too small\n", block_size); return -1; } if (block_size > (1<<22)) { // 4 MiB fprintf(stderr, "block size (%u) is too large\n", block_size); return -1; } struct fuse_data fd; memset(&fd, 0, sizeof(fd)); fd.vtab = vtab; fd.cookie = cookie; fd.file_size = file_size; fd.block_size = block_size; fd.file_blocks = (file_size == 0) ? 0 : (((file_size-1) / block_size) + 1); if (fd.file_blocks > (1<<18)) { fprintf(stderr, "file has too many blocks (%u)\n", fd.file_blocks); result = -1; goto done; } fd.hashes = (uint8_t*)calloc(fd.file_blocks, SHA256_DIGEST_SIZE); if (fd.hashes == NULL) { fprintf(stderr, "failed to allocate %d bites for hashes\n", fd.file_blocks * SHA256_DIGEST_SIZE); result = -1; goto done; } fd.uid = getuid(); fd.gid = getgid(); fd.curr_block = -1; fd.block_data = (uint8_t*)malloc(block_size); if (fd.block_data == NULL) { fprintf(stderr, "failed to allocate %d bites for block_data\n", block_size); result = -1; goto done; } fd.extra_block = (uint8_t*)malloc(block_size); if (fd.extra_block == NULL) { fprintf(stderr, "failed to allocate %d bites for extra_block\n", block_size); result = -1; goto done; } fd.ffd = open("/dev/fuse", O_RDWR); if (fd.ffd < 0) { perror("open /dev/fuse"); result = -1; goto done; } char opts[256]; snprintf(opts, sizeof(opts), ("fd=%d,user_id=%d,group_id=%d,max_read=%zu," "allow_other,rootmode=040000"), fd.ffd, fd.uid, fd.gid, block_size); result = mount("/dev/fuse", FUSE_SIDELOAD_HOST_MOUNTPOINT, "fuse", MS_NOSUID | MS_NODEV | MS_RDONLY | MS_NOEXEC, opts); if (result < 0) { perror("mount"); goto done; } uint8_t request_buffer[sizeof(struct fuse_in_header) + PATH_MAX*8]; for (;;) { ssize_t len = read(fd.ffd, request_buffer, sizeof(request_buffer)); if (len < 0) { if (errno != EINTR) { perror("read request"); if (errno == ENODEV) { result = -1; break; } } continue; } if ((size_t)len < sizeof(struct fuse_in_header)) { fprintf(stderr, "request too short: len=%zu\n", (size_t)len); continue; } struct fuse_in_header* hdr = (struct fuse_in_header*) request_buffer; void* data = request_buffer + sizeof(struct fuse_in_header); result = -ENOSYS; switch (hdr->opcode) { case FUSE_INIT: result = handle_init(data, &fd, hdr); break; case FUSE_LOOKUP: result = handle_lookup(data, &fd, hdr); break; case FUSE_GETATTR: result = handle_getattr(data, &fd, hdr); break; case FUSE_OPEN: result = handle_open(data, &fd, hdr); break; case FUSE_READ: result = handle_read(data, &fd, hdr); break; case FUSE_FLUSH: result = handle_flush(data, &fd, hdr); break; case FUSE_RELEASE: result = handle_release(data, &fd, hdr); break; default: fprintf(stderr, "unknown fuse request opcode %d\n", hdr->opcode); break; } if (result == NO_STATUS_EXIT) { result = 0; break; } if (result != NO_STATUS) { struct fuse_out_header outhdr; outhdr.len = sizeof(outhdr); outhdr.error = result; outhdr.unique = hdr->unique; write(fd.ffd, &outhdr, sizeof(outhdr)); } } done: fd.vtab->close(fd.cookie); result = umount2(FUSE_SIDELOAD_HOST_MOUNTPOINT, MNT_DETACH); if (result < 0) { printf("fuse_sideload umount failed: %s\n", strerror(errno)); } if (fd.ffd) close(fd.ffd); free(fd.hashes); free(fd.block_data); free(fd.extra_block); return result; }