/* This implements svn_editor_cb_copy_t */ static svn_error_t * copy_cb(void *baton, const char *src_relpath, svn_revnum_t src_revision, const char *dst_relpath, svn_revnum_t replaces_rev, apr_pool_t *scratch_pool) { struct edit_baton *eb = baton; const char *src_fspath = FSPATH(src_relpath, scratch_pool); const char *dst_fspath = FSPATH(dst_relpath, scratch_pool); svn_fs_root_t *root; svn_fs_root_t *src_root; SVN_ERR(get_root(&root, eb)); /* Check if we can we replace the maybe-specified destination (revision). */ if (SVN_IS_VALID_REVNUM(replaces_rev)) { SVN_ERR(can_modify(root, dst_fspath, replaces_rev, scratch_pool)); SVN_ERR(svn_fs_delete(root, dst_fspath, scratch_pool)); } else { SVN_ERR(can_create(root, dst_fspath, scratch_pool)); } SVN_ERR(svn_fs_revision_root(&src_root, svn_fs_root_fs(root), src_revision, scratch_pool)); SVN_ERR(svn_fs_copy(src_root, src_fspath, root, dst_fspath, scratch_pool)); svn_fs_close_root(src_root); return SVN_NO_ERROR; }
/* This implements svn_editor_cb_alter_file_t */ static svn_error_t * alter_file_cb(void *baton, const char *relpath, svn_revnum_t revision, apr_hash_t *props, const svn_checksum_t *checksum, svn_stream_t *contents, apr_pool_t *scratch_pool) { struct edit_baton *eb = baton; const char *fspath = FSPATH(relpath, scratch_pool); svn_fs_root_t *root; SVN_ERR(get_root(&root, eb)); SVN_ERR(can_modify(root, fspath, revision, scratch_pool)); if (contents != NULL) { SVN_ERR_ASSERT(checksum != NULL); SVN_ERR(set_text(root, fspath, checksum, contents, eb->cancel_func, eb->cancel_baton, scratch_pool)); } if (props != NULL) { SVN_ERR(alter_props(root, fspath, props, scratch_pool)); } return SVN_NO_ERROR; }
/* This implements svn_editor_cb_add_file_t */ static svn_error_t * add_file_cb(void *baton, const char *relpath, const svn_checksum_t *checksum, svn_stream_t *contents, apr_hash_t *props, svn_revnum_t replaces_rev, apr_pool_t *scratch_pool) { struct edit_baton *eb = baton; const char *fspath = FSPATH(relpath, scratch_pool); svn_fs_root_t *root; SVN_ERR(get_root(&root, eb)); if (SVN_IS_VALID_REVNUM(replaces_rev)) { SVN_ERR(can_modify(root, fspath, replaces_rev, scratch_pool)); SVN_ERR(svn_fs_delete(root, fspath, scratch_pool)); } else { SVN_ERR(can_create(root, fspath, scratch_pool)); } SVN_ERR(svn_fs_make_file(root, fspath, scratch_pool)); SVN_ERR(set_text(root, fspath, checksum, contents, eb->cancel_func, eb->cancel_baton, scratch_pool)); SVN_ERR(add_new_props(root, fspath, props, scratch_pool)); return SVN_NO_ERROR; }
/* This implements svn_editor_cb_add_directory_t */ static svn_error_t * add_directory_cb(void *baton, const char *relpath, const apr_array_header_t *children, apr_hash_t *props, svn_revnum_t replaces_rev, apr_pool_t *scratch_pool) { struct edit_baton *eb = baton; const char *fspath = FSPATH(relpath, scratch_pool); svn_fs_root_t *root; /* Note: we ignore CHILDREN. We have no "incomplete" state to worry about, so we don't need to be aware of what children will be created. */ SVN_ERR(get_root(&root, eb)); if (SVN_IS_VALID_REVNUM(replaces_rev)) { SVN_ERR(can_modify(root, fspath, replaces_rev, scratch_pool)); SVN_ERR(svn_fs_delete(root, fspath, scratch_pool)); } else { SVN_ERR(can_create(root, fspath, scratch_pool)); } SVN_ERR(svn_fs_make_dir(root, fspath, scratch_pool)); SVN_ERR(add_new_props(root, fspath, props, scratch_pool)); return SVN_NO_ERROR; }
/* This implements svn_editor_cb_move_t */ static svn_error_t * move_cb(void *baton, const char *src_relpath, svn_revnum_t src_revision, const char *dst_relpath, svn_revnum_t replaces_rev, apr_pool_t *scratch_pool) { struct edit_baton *eb = baton; const char *src_fspath = FSPATH(src_relpath, scratch_pool); const char *dst_fspath = FSPATH(dst_relpath, scratch_pool); svn_fs_root_t *root; svn_fs_root_t *src_root; SVN_ERR(get_root(&root, eb)); /* Check if we delete the specified source (revision), and can we replace the maybe-specified destination (revision). */ SVN_ERR(can_modify(root, src_fspath, src_revision, scratch_pool)); if (SVN_IS_VALID_REVNUM(replaces_rev)) { SVN_ERR(can_modify(root, dst_fspath, replaces_rev, scratch_pool)); SVN_ERR(svn_fs_delete(root, dst_fspath, scratch_pool)); } else { SVN_ERR(can_create(root, dst_fspath, scratch_pool)); } /* ### would be nice to have svn_fs_move() */ /* Copy the src to the dst. */ SVN_ERR(svn_fs_revision_root(&src_root, svn_fs_root_fs(root), src_revision, scratch_pool)); SVN_ERR(svn_fs_copy(src_root, src_fspath, root, dst_fspath, scratch_pool)); svn_fs_close_root(src_root); /* Notice: we're deleting the src repos path from the dst root. */ SVN_ERR(svn_fs_delete(root, src_fspath, scratch_pool)); return SVN_NO_ERROR; }
/* This implements svn_editor_cb_delete_t */ static svn_error_t * delete_cb(void *baton, const char *relpath, svn_revnum_t revision, apr_pool_t *scratch_pool) { struct edit_baton *eb = baton; const char *fspath = FSPATH(relpath, scratch_pool); svn_fs_root_t *root; SVN_ERR(get_root(&root, eb)); SVN_ERR(can_modify(root, fspath, revision, scratch_pool)); SVN_ERR(svn_fs_delete(root, fspath, scratch_pool)); return SVN_NO_ERROR; }
/* This implements svn_editor_cb_add_symlink_t */ static svn_error_t * add_symlink_cb(void *baton, const char *relpath, const char *target, apr_hash_t *props, svn_revnum_t replaces_rev, apr_pool_t *scratch_pool) { struct edit_baton *eb = baton; const char *fspath = FSPATH(relpath, scratch_pool); svn_fs_root_t *root; SVN_ERR(get_root(&root, eb)); if (SVN_IS_VALID_REVNUM(replaces_rev)) { SVN_ERR(can_modify(root, fspath, replaces_rev, scratch_pool)); SVN_ERR(svn_fs_delete(root, fspath, scratch_pool)); } else { SVN_ERR(can_create(root, fspath, scratch_pool)); } /* ### we probably need to construct a file with specific contents ### (until the FS grows some symlink APIs) */ #if 0 SVN_ERR(svn_fs_make_file(root, fspath, scratch_pool)); SVN_ERR(svn_fs_apply_text(&fs_contents, root, fspath, NULL /* result_checksum */, scratch_pool)); /* ### SVN_ERR(svn_stream_printf(fs_contents, ..., scratch_pool)); */ apr_hash_set(props, SVN_PROP_SPECIAL, APR_HASH_KEY_STRING, SVN_PROP_SPECIAL_VALUE); SVN_ERR(add_new_props(root, fspath, props, scratch_pool)); #endif SVN__NOT_IMPLEMENTED(); }
/* This implements svn_editor_cb_alter_directory_t */ static svn_error_t * alter_directory_cb(void *baton, const char *relpath, svn_revnum_t revision, const apr_array_header_t *children, apr_hash_t *props, apr_pool_t *scratch_pool) { struct edit_baton *eb = baton; const char *fspath = FSPATH(relpath, scratch_pool); svn_fs_root_t *root; /* Note: we ignore CHILDREN. We have no "incomplete" state to worry about, so we don't need to be aware of what children will be created. */ SVN_ERR(get_root(&root, eb)); SVN_ERR(can_modify(root, fspath, revision, scratch_pool)); if (props) SVN_ERR(alter_props(root, fspath, props, scratch_pool)); return SVN_NO_ERROR; }
/* * @func encrypt_or_clear_ip_sections modifies the content of some sections. * 1. If section content cannot be modified without disrupting enclave signing or loading flows * then section content is not modified * 2. Allocable sections (copied to application address space at shared object's load time) * are encrypted. * 3. The content of sections that are not allocable is zeroed * @param IN pcl_data_t* dat, ELF data * @param IN uint8_t* key, the AES key for GCM encrypt * @param INOUT uint8_t* elf_buf, base address of ELF binary buffer * @param OUT pcl_table_t* tbl, pointer to PCL table * @param OUT uint32_t* num_rvas_out, total number of sections that are encrypted * @param bool debug, true iff enclave is requried to support debug * @return encip_ret_e: * ENCIP_ERROR_ENCSECS_INVALID_PARAM any input parameter is NULL * PCL_MAX_NUM_ENCRYPTED_SECTIONS if out of entires in PCL table * Respective error results in case any of the functions encrypt or update_flags fail. * ENCIP_SUCCESS if success */ static encip_ret_e encrypt_or_clear_ip_sections( IN pcl_data_t* dat, IN uint8_t* key, INOUT uint8_t* elf_buf, size_t elf_size, OUT pcl_table_t* tbl, OUT uint32_t* num_rvas_out, bool debug) { if( NULL == dat || NULL == key || NULL == elf_buf || NULL == tbl || NULL == num_rvas_out) return ENCIP_ERROR_ENCSECS_INVALID_PARAM; uint32_t num_rvas = 0; // Go over sections headers to find sections to encrypt or clear: char* sec_name = NULL; for(uint16_t secidx = 1; secidx < dat->nsections; secidx++) { if(dat->elf_sec[secidx].sh_name >= dat->elf_sec[dat->shstrndx].sh_size) return ENCIP_ERROR_PARSE_ELF_INVALID_IMAGE; sec_name = dat->sections_names + dat->elf_sec[secidx].sh_name; /* * Verifying string starts before end of section. Assuming (but not checking) * that string ends before end of section. Additional check will complicate code. * Assuming the platform this application is running on is not compromized. */ if((uint8_t*)sec_name > elf_buf + elf_size) return ENCIP_ERROR_PARSE_ELF_INVALID_IMAGE; if(can_modify(sec_name, debug)) { uint8_t* va = (uint8_t *)(elf_buf + dat->elf_sec[secidx].sh_offset); size_t size = dat->elf_sec[secidx].sh_size; if((va >= elf_buf + elf_size) || (va + size < va) || (va + size > elf_buf + elf_size)) return ENCIP_ERROR_PARSE_ELF_INVALID_IMAGE; // If section is allocable (mapped into process's virtual memory), decrypt it: if(SHF_ALLOC & dat->elf_sec[secidx].sh_flags) { if(PCL_MAX_NUM_ENCRYPTED_SECTIONS <= num_rvas) { /* * No more empty entries in PCL table. * To fix - redefine PCL_MAX_NUM_ENCRYPTED_SECTIONS in pcl_common.h */ printf("Error: No more empty entries in Intel(R) SGX PCL table\n"); printf("To fix - redefine PCL_MAX_NUM_ENCRYPTED_SECTIONS in pcl_common.h\n"); return ENCIP_ERROR_ENCSECS_RVAS_OVERFLOW; } if(PCL_GCM_NUM_BLOCKS(size) > PCL_GCM_MAX_NUM_BLOCKS) { /* * Size in 16-bytes-blocks exceeds (2^32 - 2). * Only happen if cipher-text size is ~64GB. */ return ENCIP_ERROR_ENCSECS_COUNTER_OVERFLOW; } uint8_t* iv = (uint8_t*)&(tbl->rvas_sizes_tags_ivs[num_rvas].iv.val); encip_ret_e ret = init_random_iv(iv); if(ENCIP_ERROR(ret)) return ret; uint8_t* tag = (uint8_t*)&(tbl->rvas_sizes_tags_ivs[num_rvas].tag); ret = gcm_encrypt(va, size, NULL, 0, (uint8_t *)key, iv, va, tag); if(ENCIP_ERROR(ret)) { printf("Failed to gcm-encrypt section %s\n", sec_name); return ret; } // Insert entry to table: tbl->rvas_sizes_tags_ivs[num_rvas].rva = dat->elf_sec[secidx].sh_addr; tbl->rvas_sizes_tags_ivs[num_rvas].size = size; // Update flags to writable: ret = update_flags(secidx, dat); if(ENCIP_ERROR(ret)) return ret; // Increment num_rvas: num_rvas++; } // Else (section is not allocable), zero it: else { memset(va, 0, size); } } } *num_rvas_out = num_rvas; return ENCIP_SUCCESS; }