bool protected_fs_file::flush(/*bool mc*/) { bool result = false; int32_t result32 = sgx_thread_mutex_lock(&mutex); if (result32 != 0) { last_error = result32; file_status = SGX_FILE_STATUS_MEMORY_CORRUPTED; return false; } if (file_status != SGX_FILE_STATUS_OK) { last_error = SGX_ERROR_FILE_BAD_STATUS; sgx_thread_mutex_unlock(&mutex); return false; } result = internal_flush(/*mc,*/ true); if (result == false) { assert(file_status != SGX_FILE_STATUS_OK); if (file_status == SGX_FILE_STATUS_OK) file_status = SGX_FILE_STATUS_FLUSH_ERROR; // for release set this anyway } sgx_thread_mutex_unlock(&mutex); return result; }
size_t protected_fs_file::write(const void* ptr, size_t size, size_t count) { if (ptr == NULL || size == 0 || count == 0) return 0; int32_t result32 = sgx_thread_mutex_lock(&mutex); if (result32 != 0) { last_error = result32; file_status = SGX_FILE_STATUS_MEMORY_CORRUPTED; return 0; } size_t data_left_to_write = size * count; // prevent overlap... #if defined(_WIN64) || defined(__x86_64__) if (size > UINT32_MAX || count > UINT32_MAX) { last_error = EINVAL; sgx_thread_mutex_unlock(&mutex); return 0; } #else if (((uint64_t)((uint64_t)size * (uint64_t)count)) != (uint64_t)data_left_to_write) { last_error = EINVAL; sgx_thread_mutex_unlock(&mutex); return 0; } #endif if (sgx_is_outside_enclave(ptr, data_left_to_write)) { last_error = SGX_ERROR_INVALID_PARAMETER; sgx_thread_mutex_unlock(&mutex); return 0; } if (file_status != SGX_FILE_STATUS_OK) { last_error = SGX_ERROR_FILE_BAD_STATUS; sgx_thread_mutex_unlock(&mutex); return 0; } if (open_mode.append == 0 && open_mode.update == 0 && open_mode.write == 0) { last_error = EACCES; sgx_thread_mutex_unlock(&mutex); return 0; } if (open_mode.append == 1) offset = encrypted_part_plain.size; // add at the end of the file const unsigned char* data_to_write = (const unsigned char*)ptr; // the first block of user data is written in the meta-data encrypted part if (offset < MD_USER_DATA_SIZE) { size_t empty_place_left_in_md = MD_USER_DATA_SIZE - (size_t)offset; // offset is smaller than MD_USER_DATA_SIZE if (data_left_to_write <= empty_place_left_in_md) { memcpy(&encrypted_part_plain.data[offset], data_to_write, data_left_to_write); offset += data_left_to_write; data_to_write += data_left_to_write; // not needed, to prevent future errors data_left_to_write = 0; } else { memcpy(&encrypted_part_plain.data[offset], data_to_write, empty_place_left_in_md); offset += empty_place_left_in_md; data_to_write += empty_place_left_in_md; data_left_to_write -= empty_place_left_in_md; } if (offset > encrypted_part_plain.size) encrypted_part_plain.size = offset; // file grew, update the new file size need_writing = true; } while (data_left_to_write > 0) { file_data_node_t* file_data_node = NULL; file_data_node = get_data_node(); // return the data node of the current offset, will read it from disk or create new one if needed (and also the mht node if needed) if (file_data_node == NULL) break; size_t offset_in_node = (size_t)((offset - MD_USER_DATA_SIZE) % NODE_SIZE); size_t empty_place_left_in_node = NODE_SIZE - offset_in_node; if (data_left_to_write <= empty_place_left_in_node) { // this will be the last write memcpy(&file_data_node->plain.data[offset_in_node], data_to_write, data_left_to_write); offset += data_left_to_write; data_to_write += data_left_to_write; // not needed, to prevent future errors data_left_to_write = 0; } else { memcpy(&file_data_node->plain.data[offset_in_node], data_to_write, empty_place_left_in_node); offset += empty_place_left_in_node; data_to_write += empty_place_left_in_node; data_left_to_write -= empty_place_left_in_node; } if (offset > encrypted_part_plain.size) encrypted_part_plain.size = offset; // file grew, update the new file size if (file_data_node->need_writing == false) { file_data_node->need_writing = true; file_mht_node_t* file_mht_node = file_data_node->parent; while (file_mht_node->mht_node_number != 0) // set all the mht parent nodes as 'need writing' { file_mht_node->need_writing = true; file_mht_node = file_mht_node->parent; } root_mht.need_writing = true; need_writing = true; } } sgx_thread_mutex_unlock(&mutex); size_t ret_count = ((size * count) - data_left_to_write) / size; return ret_count; }
size_t protected_fs_file::read(void* ptr, size_t size, size_t count) { if (ptr == NULL || size == 0 || count == 0) return 0; int32_t result32 = sgx_thread_mutex_lock(&mutex); if (result32 != 0) { last_error = result32; file_status = SGX_FILE_STATUS_MEMORY_CORRUPTED; return 0; } size_t data_left_to_read = size * count; // prevent overlap... #if defined(_WIN64) || defined(__x86_64__) if (size > UINT32_MAX || count > UINT32_MAX) { last_error = EINVAL; sgx_thread_mutex_unlock(&mutex); return 0; } #else if (((uint64_t)((uint64_t)size * (uint64_t)count)) != (uint64_t)data_left_to_read) { last_error = EINVAL; sgx_thread_mutex_unlock(&mutex); return 0; } #endif if (sgx_is_outside_enclave(ptr, data_left_to_read)) { last_error = EINVAL; sgx_thread_mutex_unlock(&mutex); return 0; } if (file_status != SGX_FILE_STATUS_OK) { last_error = SGX_ERROR_FILE_BAD_STATUS; sgx_thread_mutex_unlock(&mutex); return 0; } if (open_mode.read == 0 && open_mode.update == 0) { last_error = EACCES; sgx_thread_mutex_unlock(&mutex); return 0; } if (end_of_file == true) {// not an error sgx_thread_mutex_unlock(&mutex); return 0; } // this check is not really needed, can go on with the code and it will do nothing until the end, but it's more 'right' to check it here if (offset == encrypted_part_plain.size) { end_of_file = true; sgx_thread_mutex_unlock(&mutex); return 0; } if (((uint64_t)data_left_to_read) > (uint64_t)(encrypted_part_plain.size - offset)) // the request is bigger than what's left in the file { data_left_to_read = (size_t)(encrypted_part_plain.size - offset); } size_t data_attempted_to_read = data_left_to_read; // used at the end to return how much we actually read unsigned char* out_buffer = (unsigned char*)ptr; // the first block of user data is read from the meta-data encrypted part if (offset < MD_USER_DATA_SIZE) { size_t data_left_in_md = MD_USER_DATA_SIZE - (size_t)offset; // offset is smaller than MD_USER_DATA_SIZE if (data_left_to_read <= data_left_in_md) { memcpy(out_buffer, &encrypted_part_plain.data[offset], data_left_to_read); offset += data_left_to_read; out_buffer += data_left_to_read; // not needed, to prevent future errors data_left_to_read = 0; } else { memcpy(out_buffer, &encrypted_part_plain.data[offset], data_left_in_md); offset += data_left_in_md; out_buffer += data_left_in_md; data_left_to_read -= data_left_in_md; } } while (data_left_to_read > 0) { file_data_node_t* file_data_node = NULL; file_data_node = get_data_node(); // return the data node of the current offset, will read it from disk if needed (and also the mht node if needed) if (file_data_node == NULL) break; size_t offset_in_node = (offset - MD_USER_DATA_SIZE) % NODE_SIZE; size_t data_left_in_node = NODE_SIZE - offset_in_node; if (data_left_to_read <= data_left_in_node) { memcpy(out_buffer, &file_data_node->plain.data[offset_in_node], data_left_to_read); offset += data_left_to_read; out_buffer += data_left_to_read; // not needed, to prevent future errors data_left_to_read = 0; } else { memcpy(out_buffer, &file_data_node->plain.data[offset_in_node], data_left_in_node); offset += data_left_in_node; out_buffer += data_left_in_node; data_left_to_read -= data_left_in_node; } } sgx_thread_mutex_unlock(&mutex); if (data_left_to_read == 0 && data_attempted_to_read != (size * count)) // user wanted to read more and we had to shrink the request { assert(offset == encrypted_part_plain.size); end_of_file = true; } size_t ret_count = (data_attempted_to_read - data_left_to_read) / size; return ret_count; }