linux-sgx: Implement SGX IPFS as POSIX backend for file interaction (#1489)
This PR integrates an Intel SGX feature called Intel Protection File System Library (IPFS) into the runtime to create, operate and delete files inside the enclave, while guaranteeing the confidentiality and integrity of the data persisted. IPFS can be referred to here: https://www.intel.com/content/www/us/en/developer/articles/technical/overview-of-intel-protected-file-system-library-using-software-guard-extensions.html Introduce a cmake variable `WAMR_BUILD_SGX_IPFS`, when enabled, the files interaction API of WASI will leverage IPFS, instead of the regular POSIX OCALLs. The implementation has been written with light changes to sgx platform layer, so all the security aspects WAMR relies on are conserved. In addition to this integration, the following changes have been made: - The CI workflow has been adapted to test the compilation of the runtime and sample with the flag `WAMR_BUILD_SGX_IPFS` set to true - Introduction of a new sample that demonstrates the interaction of the files (called `file`), - Documentation of this new feature
This commit is contained in:
9
samples/file/CMakeLists.txt
Normal file
9
samples/file/CMakeLists.txt
Normal file
@ -0,0 +1,9 @@
|
||||
# Copyright (C) 2022 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
project(file)
|
||||
|
||||
################ wasm application ###############
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(wasm-app)
|
||||
112
samples/file/README.md
Normal file
112
samples/file/README.md
Normal file
@ -0,0 +1,112 @@
|
||||
# "file" sample introduction
|
||||
|
||||
This sample demonstrates the supported file interaction API of WASI.
|
||||
This sample can also demonstrate the SGX IPFS (Intel Protected File System), enabling an enclave to seal and unseal data at rest.
|
||||
|
||||
## Preparation
|
||||
|
||||
Please install WASI SDK, download the [wasi-sdk release](https://github.com/CraneStation/wasi-sdk/releases) and extract the archive to default path `/opt/wasi-sdk`.
|
||||
For testing with SGX IPFS, follow the instructions in [the documentation of SGX for WAMR](../../doc/linux_sgx.md#sgx-intel-protected-file-system).
|
||||
|
||||
## Build the sample
|
||||
|
||||
```bash
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
```
|
||||
|
||||
The WebAssembly application is the file located at `wasm-app/file.wasm`.
|
||||
|
||||
## Run workload
|
||||
|
||||
Either use [iwasm-sample](../../product-mini/platforms/linux/) for Linux, or [enclave-sample](../../product-mini/platforms/linux-sgx/enclave-sample/) for Intel SGX to run the sample, with the argument to allow the file system interaction with the current folder (`--dir=.`).
|
||||
|
||||
The output with Linux and POSIX is like:
|
||||
|
||||
```bash
|
||||
Opening a file..
|
||||
[Test] File opening passed.
|
||||
Writing to the file..
|
||||
[Test] File writing passed.
|
||||
Moving the cursor to the start of the file..
|
||||
Reading from the file, up to 1000 characters..
|
||||
Text read: Hello, world!
|
||||
[Test] File reading passed.
|
||||
Determine whether we reach the end of the file..
|
||||
Is the end of file? 1
|
||||
[Test] End of file detection passed.
|
||||
Getting the plaintext size..
|
||||
The plaintext size is 13.
|
||||
[Test] Retrieving file offset passed.
|
||||
Force actual write of all the cached data to the disk..
|
||||
[Test] Retrieving file offset passed.
|
||||
Writing 5 characters at offset 7..
|
||||
File current offset: 13
|
||||
[Test] Writing at specified offset passed.
|
||||
Reading 5 characters at offset 7..
|
||||
Text read: James
|
||||
File current offset: 13
|
||||
[Test] Reading at specified offset passed.
|
||||
Allocate more space to the file..
|
||||
File current offset: 13
|
||||
Moving to the end..
|
||||
File current offset: 23
|
||||
[Test] Allocation or more space passed.
|
||||
Extend the file size of 10 bytes using ftruncate..
|
||||
File current offset: 23
|
||||
Moving to the end..
|
||||
File current offset: 33
|
||||
[Test] Extension of the file size passed.
|
||||
Closing from the file..
|
||||
[Test] Closing file passed.
|
||||
Getting the size of the file on disk..
|
||||
The file size is 33.
|
||||
All the tests passed!
|
||||
```
|
||||
|
||||
The output with SGX and IPFS is like:
|
||||
|
||||
```bash
|
||||
Opening a file..
|
||||
[Test] File opening passed.
|
||||
Writing to the file..
|
||||
[Test] File writing passed.
|
||||
Moving the cursor to the start of the file..
|
||||
Reading from the file, up to 1000 characters..
|
||||
Text read: Hello, world!
|
||||
[Test] File reading passed.
|
||||
Determine whether we reach the end of the file..
|
||||
Is the end of file? 1
|
||||
[Test] End of file detection passed.
|
||||
Getting the plaintext size..
|
||||
The plaintext size is 13.
|
||||
[Test] Retrieving file offset passed.
|
||||
Force actual write of all the cached data to the disk..
|
||||
[Test] Retrieving file offset passed.
|
||||
Writing 5 characters at offset 7..
|
||||
File current offset: 13
|
||||
[Test] Writing at specified offset passed.
|
||||
Reading 5 characters at offset 7..
|
||||
Text read: James
|
||||
File current offset: 13
|
||||
[Test] Reading at specified offset passed.
|
||||
Allocate more space to the file..
|
||||
File current offset: 23
|
||||
Moving to the end..
|
||||
File current offset: 23
|
||||
[Test] Allocation or more space passed.
|
||||
Extend the file size of 10 bytes using ftruncate..
|
||||
File current offset: 23
|
||||
Moving to the end..
|
||||
File current offset: 33
|
||||
[Test] Extension of the file size passed.
|
||||
Closing from the file..
|
||||
[Test] Closing file passed.
|
||||
Getting the size of the file on disk..
|
||||
The file size is 4096.
|
||||
All the tests passed!
|
||||
```
|
||||
|
||||
For SGX IPFS, refer to [SGX Intel Protected File System](../../doc/linux_sgx.md#sgx-intel-protected-file-system) for more details.
|
||||
87
samples/file/src/CMakeLists.txt
Normal file
87
samples/file/src/CMakeLists.txt
Normal file
@ -0,0 +1,87 @@
|
||||
# Copyright (C) 2022 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
cmake_minimum_required (VERSION 3.0)
|
||||
|
||||
if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows")
|
||||
project (iwasm)
|
||||
else()
|
||||
project (iwasm C ASM)
|
||||
enable_language (ASM_MASM)
|
||||
endif()
|
||||
|
||||
################ runtime settings ################
|
||||
string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM)
|
||||
if (APPLE)
|
||||
add_definitions(-DBH_PLATFORM_DARWIN)
|
||||
endif ()
|
||||
|
||||
# Reset default linker flags
|
||||
set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
|
||||
set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
|
||||
|
||||
# WAMR features switch
|
||||
|
||||
# Set WAMR_BUILD_TARGET, currently values supported:
|
||||
# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]",
|
||||
# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]"
|
||||
if (NOT DEFINED WAMR_BUILD_TARGET)
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)")
|
||||
set (WAMR_BUILD_TARGET "AARCH64")
|
||||
elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64")
|
||||
set (WAMR_BUILD_TARGET "RISCV64")
|
||||
elseif (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
# Build as X86_64 by default in 64-bit platform
|
||||
set (WAMR_BUILD_TARGET "X86_64")
|
||||
elseif (CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
# Build as X86_32 by default in 32-bit platform
|
||||
set (WAMR_BUILD_TARGET "X86_32")
|
||||
else ()
|
||||
message(SEND_ERROR "Unsupported build target platform!")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set (CMAKE_BUILD_TYPE Release)
|
||||
endif ()
|
||||
|
||||
set (WAMR_BUILD_INTERP 1)
|
||||
set (WAMR_BUILD_AOT 1)
|
||||
set (WAMR_BUILD_JIT 0)
|
||||
set (WAMR_BUILD_LIBC_BUILTIN 1)
|
||||
|
||||
if (NOT MSVC)
|
||||
set (WAMR_BUILD_LIBC_WASI 1)
|
||||
endif ()
|
||||
|
||||
if (NOT MSVC)
|
||||
# linker flags
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE")
|
||||
if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang"))
|
||||
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
|
||||
endif ()
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security")
|
||||
if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64")
|
||||
if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang"))
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register")
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# build out vmlib
|
||||
set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..)
|
||||
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
|
||||
|
||||
add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE})
|
||||
|
||||
################ application related ################
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR})
|
||||
include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
|
||||
|
||||
add_executable (iwasm main.c ${UNCOMMON_SHARED_SOURCE})
|
||||
|
||||
if (APPLE)
|
||||
target_link_libraries (iwasm vmlib -lm -ldl -lpthread)
|
||||
else ()
|
||||
target_link_libraries (iwasm vmlib -lm -ldl -lpthread -lrt)
|
||||
endif ()
|
||||
117
samples/file/src/main.c
Normal file
117
samples/file/src/main.c
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "wasm_export.h"
|
||||
#include "bh_read_file.h"
|
||||
|
||||
void
|
||||
print_usage(void)
|
||||
{
|
||||
fprintf(stdout, "Required arguments:\r\n");
|
||||
fprintf(stdout, " -f [path of wasm file] \n");
|
||||
fprintf(stdout, " -d [path of host directory] \n");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv_main[])
|
||||
{
|
||||
static char global_heap_buf[512 * 1024];
|
||||
char *buffer, error_buf[128];
|
||||
const char *wasm_path = NULL, *wasi_dir = NULL;
|
||||
int opt;
|
||||
|
||||
wasm_module_t module = NULL;
|
||||
wasm_module_inst_t module_inst = NULL;
|
||||
wasm_exec_env_t exec_env = NULL;
|
||||
uint32 buf_size, stack_size = 8092, heap_size = 8092;
|
||||
uint32_t wasm_buffer = 0;
|
||||
|
||||
RuntimeInitArgs init_args;
|
||||
memset(&init_args, 0, sizeof(RuntimeInitArgs));
|
||||
|
||||
while ((opt = getopt(argc, argv_main, "hf:d:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
wasm_path = optarg;
|
||||
break;
|
||||
case 'd':
|
||||
wasi_dir = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
print_usage();
|
||||
return 0;
|
||||
case '?':
|
||||
print_usage();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (wasm_path == NULL || wasi_dir == NULL) {
|
||||
print_usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
init_args.mem_alloc_type = Alloc_With_Pool;
|
||||
init_args.mem_alloc_option.pool.heap_buf = global_heap_buf;
|
||||
init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf);
|
||||
|
||||
if (!wasm_runtime_full_init(&init_args)) {
|
||||
printf("Init runtime environment failed.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
buffer = bh_read_file_to_buffer(wasm_path, &buf_size);
|
||||
|
||||
if (!buffer) {
|
||||
printf("Open wasm app file [%s] failed.\n", wasm_path);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
module = wasm_runtime_load(buffer, buf_size, error_buf, sizeof(error_buf));
|
||||
if (!module) {
|
||||
printf("Load wasm module failed. error: %s\n", error_buf);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
wasm_runtime_set_wasi_args_ex(module, &wasi_dir, 1, NULL, 0, NULL, 0, NULL,
|
||||
0, 0, 1, 2);
|
||||
|
||||
module_inst = wasm_runtime_instantiate(module, stack_size, heap_size,
|
||||
error_buf, sizeof(error_buf));
|
||||
|
||||
if (!module_inst) {
|
||||
printf("Instantiate wasm module failed. error: %s\n", error_buf);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
exec_env = wasm_runtime_create_exec_env(module_inst, stack_size);
|
||||
if (!exec_env) {
|
||||
printf("Create wasm execution environment failed.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (wasm_application_execute_main(module_inst, 0, NULL)) {
|
||||
printf("Main wasm function successfully finished.\n");
|
||||
}
|
||||
else {
|
||||
printf("call wasm function main failed. error: %s\n",
|
||||
wasm_runtime_get_exception(module_inst));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
if (exec_env)
|
||||
wasm_runtime_destroy_exec_env(exec_env);
|
||||
if (module_inst) {
|
||||
if (wasm_buffer)
|
||||
wasm_runtime_module_free(module_inst, wasm_buffer);
|
||||
wasm_runtime_deinstantiate(module_inst);
|
||||
}
|
||||
if (module)
|
||||
wasm_runtime_unload(module);
|
||||
if (buffer)
|
||||
BH_FREE(buffer);
|
||||
wasm_runtime_destroy();
|
||||
return 0;
|
||||
}
|
||||
26
samples/file/wasm-app/CMakeLists.txt
Normal file
26
samples/file/wasm-app/CMakeLists.txt
Normal file
@ -0,0 +1,26 @@
|
||||
# Copyright (C) 2022 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
project(wasm-app)
|
||||
|
||||
set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
|
||||
|
||||
if (APPLE)
|
||||
set (HAVE_FLAG_SEARCH_PATHS_FIRST 0)
|
||||
set (CMAKE_C_LINK_FLAGS "")
|
||||
set (CMAKE_CXX_LINK_FLAGS "")
|
||||
endif ()
|
||||
|
||||
set (CMAKE_SYSTEM_PROCESSOR wasm32)
|
||||
|
||||
if (NOT DEFINED WASI_SDK_DIR)
|
||||
set (WASI_SDK_DIR "/opt/wasi-sdk")
|
||||
endif ()
|
||||
|
||||
set (CMAKE_C_COMPILER_TARGET "wasm32-wasi")
|
||||
set (CMAKE_C_COMPILER "${WASI_SDK_DIR}/bin/clang")
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Wno-unused-command-line-argument")
|
||||
|
||||
add_executable(file.wasm main.c)
|
||||
target_link_libraries(file.wasm)
|
||||
132
samples/file/wasm-app/main.c
Normal file
132
samples/file/wasm-app/main.c
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define PATH_TEST_FILE "test.txt"
|
||||
#define FILE_TEXT "Hello, world!"
|
||||
#define WORLD_OFFSET 7
|
||||
#define NAME_REPLACMENT "James"
|
||||
#define NAME_REPLACMENT_LEN (sizeof(NAME_REPLACMENT) - 1)
|
||||
#define ADDITIONAL_SPACE 10
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
FILE *file;
|
||||
const char *text = FILE_TEXT;
|
||||
char buffer[1000];
|
||||
int ret;
|
||||
|
||||
// Test: File opening (fopen)
|
||||
printf("Opening a file..\n");
|
||||
file = fopen(PATH_TEST_FILE, "w+");
|
||||
if (file == NULL) {
|
||||
printf("Error! errno: %d\n", errno);
|
||||
}
|
||||
assert(file != NULL);
|
||||
printf("[Test] File opening passed.\n");
|
||||
|
||||
// Test: Writing to a file (fprintf)
|
||||
printf("Writing to the file..\n");
|
||||
ret = fprintf(file, "%s", text);
|
||||
assert(ret == strlen(text));
|
||||
printf("[Test] File writing passed.\n");
|
||||
|
||||
// Test: Reading from a file (fseek)
|
||||
printf("Moving the cursor to the start of the file..\n");
|
||||
ret = fseek(file, 0, SEEK_SET);
|
||||
assert(ret == 0);
|
||||
|
||||
printf("Reading from the file, up to 1000 characters..\n");
|
||||
fread(buffer, 1, sizeof(buffer), file);
|
||||
printf("Text read: %s\n", buffer);
|
||||
assert(strncmp(text, buffer, strlen(text)) == 0);
|
||||
printf("[Test] File reading passed.\n");
|
||||
|
||||
// Test: end of file detection (feof)
|
||||
printf("Determine whether we reach the end of the file..\n");
|
||||
int is_end_of_file = feof(file);
|
||||
printf("Is the end of file? %d\n", is_end_of_file);
|
||||
assert(is_end_of_file == 1);
|
||||
printf("[Test] End of file detection passed.\n");
|
||||
|
||||
// Test: retrieving file offset (ftell)
|
||||
printf("Getting the plaintext size..\n");
|
||||
long plaintext_size = ftell(file);
|
||||
printf("The plaintext size is %ld.\n", plaintext_size);
|
||||
assert(plaintext_size == 13);
|
||||
printf("[Test] Retrieving file offset passed.\n");
|
||||
|
||||
// Test: persist changes on disk (fflush)
|
||||
printf("Force actual write of all the cached data to the disk..\n");
|
||||
ret = fflush(file);
|
||||
assert(ret == 0);
|
||||
printf("[Test] Retrieving file offset passed.\n");
|
||||
|
||||
// Test: writing at specified offset (pwrite)
|
||||
printf("Writing 5 characters at offset %d..\n", WORLD_OFFSET);
|
||||
ret = pwrite(fileno(file), NAME_REPLACMENT, NAME_REPLACMENT_LEN,
|
||||
WORLD_OFFSET);
|
||||
printf("File current offset: %ld\n", ftell(file));
|
||||
assert(ret == NAME_REPLACMENT_LEN);
|
||||
assert(ftell(file) == strlen(FILE_TEXT));
|
||||
printf("[Test] Writing at specified offset passed.\n");
|
||||
|
||||
// Test: reading at specified offset (pread)
|
||||
printf("Reading %ld characters at offset %d..\n", NAME_REPLACMENT_LEN,
|
||||
WORLD_OFFSET);
|
||||
buffer[NAME_REPLACMENT_LEN] = '\0';
|
||||
pread(fileno(file), buffer, NAME_REPLACMENT_LEN, WORLD_OFFSET);
|
||||
printf("Text read: %s\n", buffer);
|
||||
printf("File current offset: %ld\n", ftell(file));
|
||||
assert(strcmp(NAME_REPLACMENT, buffer) == 0);
|
||||
assert(ftell(file) == strlen(FILE_TEXT));
|
||||
printf("[Test] Reading at specified offset passed.\n");
|
||||
|
||||
// Test: allocate more space to the file (posix_fallocate)
|
||||
printf("Allocate more space to the file..\n");
|
||||
posix_fallocate(fileno(file), ftell(file), ADDITIONAL_SPACE);
|
||||
printf("File current offset: %ld\n", ftell(file));
|
||||
printf("Moving to the end..\n");
|
||||
fseek(file, 0, SEEK_END);
|
||||
printf("File current offset: %ld\n", ftell(file));
|
||||
assert(ftell(file) == strlen(text) + ADDITIONAL_SPACE);
|
||||
printf("[Test] Allocation or more space passed.\n");
|
||||
|
||||
// Test: allocate more space to the file (ftruncate)
|
||||
printf("Extend the file size of 10 bytes using ftruncate..\n");
|
||||
ftruncate(fileno(file), ftell(file) + 10);
|
||||
assert(ftell(file) == strlen(text) + ADDITIONAL_SPACE);
|
||||
printf("File current offset: %ld\n", ftell(file));
|
||||
printf("Moving to the end..\n");
|
||||
fseek(file, 0, SEEK_END);
|
||||
printf("File current offset: %ld\n", ftell(file));
|
||||
assert(ftell(file) == strlen(text) + 2 * ADDITIONAL_SPACE);
|
||||
printf("[Test] Extension of the file size passed.\n");
|
||||
|
||||
// Test: closing the file (fclose)
|
||||
printf("Closing from the file..\n");
|
||||
ret = fclose(file);
|
||||
assert(ret == 0);
|
||||
printf("[Test] Closing file passed.\n");
|
||||
|
||||
// Display some debug information
|
||||
printf("Getting the size of the file on disk..\n");
|
||||
struct stat st;
|
||||
stat(PATH_TEST_FILE, &st);
|
||||
printf("The file size is %lld.\n", st.st_size);
|
||||
|
||||
printf("All the tests passed!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user