Skip to content

Commit dfd16f8

Browse files
authoredSep 28, 2022
linux-sgx: Implement SGX IPFS as POSIX backend for file interaction (bytecodealliance#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
1 parent fa736d1 commit dfd16f8

File tree

20 files changed

+1211
-4
lines changed

20 files changed

+1211
-4
lines changed
 

‎.github/workflows/compilation_on_android_ubuntu.yml

+9
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,15 @@ jobs:
413413
./build.sh
414414
./run.sh
415415
416+
- name: Build Sample [file]
417+
if: ${{ matrix.light == 'green' }}
418+
run: |
419+
cd samples/file
420+
mkdir build && cd build
421+
cmake ..
422+
cmake --build . --config Release --parallel 4
423+
./src/iwasm -f wasm-app/file.wasm -d .
424+
416425
- name: Build Sample [multi-thread]
417426
if: ${{ matrix.light == 'green' }}
418427
run: |

‎.github/workflows/compilation_on_macos.yml

+9
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,15 @@ jobs:
356356
./build.sh
357357
./run.sh
358358
359+
- name: Build Sample [file]
360+
if: ${{ matrix.light == 'green' }}
361+
run: |
362+
cd samples/file
363+
mkdir build && cd build
364+
cmake ..
365+
cmake --build . --config Release --parallel 4
366+
./src/iwasm -f wasm-app/file.wasm -d .
367+
359368
- name: Build Sample [multi-thread]
360369
if: ${{ matrix.light == 'green' }}
361370
run: |

‎.github/workflows/compilation_on_sgx.yml

+10
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ jobs:
140140
# "-DWAMR_BUILD_SIMD=1",
141141
"-DWAMR_BUILD_TAIL_CALL=1",
142142
"-DWAMR_DISABLE_HW_BOUND_CHECK=1",
143+
"-DWAMR_BUILD_SGX_IPFS=1",
143144
]
144145
os: [ubuntu-20.04]
145146
platform: [linux-sgx]
@@ -363,6 +364,15 @@ jobs:
363364
./build.sh
364365
./run.sh
365366
367+
- name: Build Sample [file]
368+
if: ${{ matrix.light == 'green' }}
369+
run: |
370+
cd samples/file
371+
mkdir build && cd build
372+
cmake ..
373+
cmake --build . --config Release --parallel 4
374+
./src/iwasm -f wasm-app/file.wasm -d .
375+
366376
- name: Build Sample [multi-thread]
367377
if: ${{ matrix.light == 'green' }}
368378
run: |

‎README.md

+1
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ The WAMR [samples](./samples) integrate the iwasm VM core, application manager a
151151

152152
- [**basic**](./samples/basic): Demonstrating how to use runtime exposed API's to call WASM functions, how to register native functions and call them, and how to call WASM function from native function.
153153
- **[simple](./samples/simple/README.md)**: The runtime is integrated with most of the WAMR APP libraries, and a few WASM applications are provided for testing the WAMR APP API set. It uses **built-in libc** and executes apps in **interpreter** mode by default.
154+
- **[file](./samples/file/README.md)**: Demonstrating 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.
154155
- **[littlevgl](./samples/littlevgl/README.md)**: Demonstrating the graphic user interface application usage on WAMR. The whole [LVGL](https://github.com/lvgl/lvgl) 2D user graphic library and the UI application are built into WASM application. It uses **WASI libc** and executes apps in **AOT mode** by default.
155156
- **[gui](./samples/gui/README.md)**: Move the [LVGL](https://github.com/lvgl/lvgl) library into the runtime and define a WASM application interface by wrapping the littlevgl API. It uses **WASI libc** and executes apps in **interpreter** mode by default.
156157
- **[multi-thread](./samples/multi-thread/)**: Demonstrating how to run wasm application which creates multiple threads to execute wasm functions concurrently, and uses mutex/cond by calling pthread related API's.

‎build-scripts/config_common.cmake

+4
Original file line numberDiff line numberDiff line change
@@ -287,3 +287,7 @@ if (WAMR_BUILD_STACK_GUARD_SIZE GREATER 0)
287287
add_definitions (-DWASM_STACK_GUARD_SIZE=${WAMR_BUILD_STACK_GUARD_SIZE})
288288
message (" Custom stack guard size: " ${WAMR_BUILD_STACK_GUARD_SIZE})
289289
endif ()
290+
if (WAMR_BUILD_SGX_IPFS EQUAL 1)
291+
add_definitions (-DWASM_ENABLE_SGX_IPFS=1)
292+
message (" SGX IPFS enabled")
293+
endif ()

‎core/config.h

+4
Original file line numberDiff line numberDiff line change
@@ -407,4 +407,8 @@
407407
#define WASM_ENABLE_REF_TYPES 0
408408
#endif
409409

410+
#ifndef WASM_ENABLE_SGX_IPFS
411+
#define WASM_ENABLE_SGX_IPFS 0
412+
#endif
413+
410414
#endif /* end of _CONFIG_H_ */

‎core/shared/platform/linux-sgx/sgx_file.c

+64
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
#include "sgx_error.h"
88
#include "sgx_file.h"
99

10+
#if WASM_ENABLE_SGX_IPFS != 0
11+
#include "sgx_ipfs.h"
12+
#endif
13+
1014
#ifndef SGX_DISABLE_WASI
1115

1216
#define TRACE_FUNC() os_printf("undefined %s\n", __FUNCTION__)
@@ -184,6 +188,22 @@ openat(int dirfd, const char *pathname, int flags, ...)
184188

185189
if (fd == -1)
186190
errno = get_errno();
191+
192+
#if WASM_ENABLE_SGX_IPFS != 0
193+
// When WAMR uses Intel SGX IPFS to enabled, it opens a second
194+
// file descriptor to interact with the secure file.
195+
// The first file descriptor opened earlier is used to interact
196+
// with the metadata of the file (e.g., time, flags, etc.).
197+
int ret;
198+
void *file_ptr = ipfs_fopen(fd, pathname, flags);
199+
if (file_ptr == NULL) {
200+
if (ocall_close(&ret, fd) != SGX_SUCCESS) {
201+
TRACE_OCALL_FAIL();
202+
}
203+
return -1;
204+
}
205+
#endif
206+
187207
return fd;
188208
}
189209

@@ -192,6 +212,13 @@ close(int fd)
192212
{
193213
int ret;
194214

215+
#if WASM_ENABLE_SGX_IPFS != 0
216+
// Close the IPFS file pointer in addition of the file descriptor
217+
ret = ipfs_close(fd);
218+
if (ret == -1)
219+
errno = get_errno();
220+
#endif
221+
195222
if (ocall_close(&ret, fd) != SGX_SUCCESS) {
196223
TRACE_OCALL_FAIL();
197224
return -1;
@@ -345,6 +372,12 @@ readv_internal(int fd, const struct iovec *iov, int iovcnt, bool has_offset,
345372
if (total_size >= UINT32_MAX)
346373
return -1;
347374

375+
#if WASM_ENABLE_SGX_IPFS != 0
376+
if (fd > 2) {
377+
return ipfs_read(fd, iov, iovcnt, has_offset, offset);
378+
}
379+
#endif
380+
348381
iov1 = BH_MALLOC((uint32)total_size);
349382

350383
if (iov1 == NULL)
@@ -410,6 +443,12 @@ writev_internal(int fd, const struct iovec *iov, int iovcnt, bool has_offset,
410443
if (total_size >= UINT32_MAX)
411444
return -1;
412445

446+
#if WASM_ENABLE_SGX_IPFS != 0
447+
if (fd > 2) {
448+
return ipfs_write(fd, iov, iovcnt, has_offset, offset);
449+
}
450+
#endif
451+
413452
iov1 = BH_MALLOC((uint32)total_size);
414453

415454
if (iov1 == NULL)
@@ -468,12 +507,18 @@ off_t
468507
lseek(int fd, off_t offset, int whence)
469508
{
470509
off_t ret;
510+
511+
#if WASM_ENABLE_SGX_IPFS != 0
512+
ret = ipfs_lseek(fd, offset, whence);
513+
#else
471514
if (ocall_lseek(&ret, fd, (long)offset, whence) != SGX_SUCCESS) {
472515
TRACE_OCALL_FAIL();
473516
return -1;
474517
}
475518
if (ret == -1)
476519
errno = get_errno();
520+
#endif
521+
477522
return ret;
478523
}
479524

@@ -482,12 +527,17 @@ ftruncate(int fd, off_t length)
482527
{
483528
int ret;
484529

530+
#if WASM_ENABLE_SGX_IPFS != 0
531+
ret = ipfs_ftruncate(fd, length);
532+
#else
485533
if (ocall_ftruncate(&ret, fd, length) != SGX_SUCCESS) {
486534
TRACE_OCALL_FAIL();
487535
return -1;
488536
}
489537
if (ret == -1)
490538
errno = get_errno();
539+
#endif
540+
491541
return ret;
492542
}
493543

@@ -554,12 +604,17 @@ fsync(int fd)
554604
{
555605
int ret;
556606

607+
#if WASM_ENABLE_SGX_IPFS != 0
608+
ret = ipfs_fflush(fd);
609+
#else
557610
if (ocall_fsync(&ret, fd) != SGX_SUCCESS) {
558611
TRACE_OCALL_FAIL();
559612
return -1;
560613
}
561614
if (ret == -1)
562615
errno = get_errno();
616+
#endif
617+
563618
return ret;
564619
}
565620

@@ -568,12 +623,17 @@ fdatasync(int fd)
568623
{
569624
int ret;
570625

626+
#if WASM_ENABLE_SGX_IPFS != 0
627+
ret = ipfs_fflush(fd);
628+
#else
571629
if (ocall_fdatasync(&ret, fd) != SGX_SUCCESS) {
572630
TRACE_OCALL_FAIL();
573631
return -1;
574632
}
575633
if (ret == -1)
576634
errno = get_errno();
635+
#endif
636+
577637
return ret;
578638
}
579639

@@ -801,10 +861,14 @@ posix_fallocate(int fd, off_t offset, off_t len)
801861
{
802862
int ret;
803863

864+
#if WASM_ENABLE_SGX_IPFS != 0
865+
ret = ipfs_posix_fallocate(fd, offset, len);
866+
#else
804867
if (ocall_posix_fallocate(&ret, fd, offset, len) != SGX_SUCCESS) {
805868
TRACE_OCALL_FAIL();
806869
return -1;
807870
}
871+
#endif
808872

809873
return ret;
810874
}

‎core/shared/platform/linux-sgx/sgx_ipfs.c

+460
Large diffs are not rendered by default.
+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright (C) 2022 Intel Corporation. All rights reserved.
3+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
*/
5+
6+
#ifndef _LIBC_WASI_SGX_PFS_H
7+
#define _LIBC_WASI_SGX_PFS_H
8+
9+
#include "bh_hashmap.h"
10+
#include "wasmtime_ssp.h"
11+
12+
#ifdef __cplusplus
13+
extern "C" {
14+
#endif
15+
16+
int
17+
ipfs_init();
18+
void
19+
ipfs_destroy();
20+
int
21+
ipfs_posix_fallocate(int fd, off_t offset, size_t len);
22+
size_t
23+
ipfs_read(int fd, const struct iovec *iov, int iovcnt, bool has_offset,
24+
off_t offset);
25+
size_t
26+
ipfs_write(int fd, const struct iovec *iov, int iovcnt, bool has_offset,
27+
off_t offset);
28+
int
29+
ipfs_close(int fd);
30+
void *
31+
ipfs_fopen(int fd, const char *filename, int flags);
32+
int
33+
ipfs_fflush(int fd);
34+
off_t
35+
ipfs_lseek(int fd, off_t offset, int nwhence);
36+
int
37+
ipfs_ftruncate(int fd, off_t len);
38+
39+
/**
40+
* Whether two file descriptors are equal.
41+
*/
42+
inline static bool
43+
fd_equal(int left, int right)
44+
{
45+
return left == right ? true : false;
46+
}
47+
48+
/**
49+
* Returns the file descriptor as a hash value.
50+
*/
51+
inline static uint32
52+
fd_hash(int fd)
53+
{
54+
return (uint32)fd;
55+
}
56+
57+
#ifdef __cplusplus
58+
}
59+
#endif
60+
61+
#endif /* end of _LIBC_WASI_SGX_PFS_H */

‎core/shared/platform/linux-sgx/sgx_platform.c

+16-2
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,31 @@
77
#include "platform_api_extension.h"
88
#include "sgx_rsrv_mem_mngr.h"
99

10+
#if WASM_ENABLE_SGX_IPFS != 0
11+
#include "sgx_ipfs.h"
12+
#endif
13+
1014
static os_print_function_t print_function = NULL;
1115

1216
int
1317
bh_platform_init()
1418
{
15-
return 0;
19+
int ret = BHT_OK;
20+
21+
#if WASM_ENABLE_SGX_IPFS != 0
22+
ret = ipfs_init();
23+
#endif
24+
25+
return ret;
1626
}
1727

1828
void
1929
bh_platform_destroy()
20-
{}
30+
{
31+
#if WASM_ENABLE_SGX_IPFS != 0
32+
ipfs_destroy();
33+
#endif
34+
}
2135

2236
void *
2337
os_malloc(unsigned size)

‎doc/linux_sgx.md

+51
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,57 @@ typedef enum EcallCmd {
195195
};
196196
```
197197

198+
SGX Intel Protected File System
199+
-------------------------------
200+
Intel SGX introduced a feature called [Intel Protection File System Library (IPFS)](https://www.intel.com/content/www/us/en/developer/articles/technical/overview-of-intel-protected-file-system-library-using-software-guard-extensions.html) to create, operate and delete files inside the enclave.
201+
WAMR supports the mapping of IPFS on WASI functions related to file interactions, providing seamless persistence with confidentiality and integrity to the hosted WebAssembly applications in the enclave.
202+
203+
The usage of SGX IPFS is an optional feature.
204+
To opt-in, the support of IPFS requires the following changes:
205+
- set the flag `WAMR_BUILD_SGX_IPFS=1` when running `cmake`,
206+
- the enclave must be linked with the trusted IPFS library (`-lsgx_tprotected_fs`),
207+
- the application outside of the enclave must be linked with the untrusted IPFS library (`-lsgx_uprotected_fs`),
208+
- the EDL file must include the following import statement:
209+
210+
```edl
211+
from "sgx_tprotected_fs.edl" import *;
212+
```
213+
214+
When using the [enclave-sample](../product-mini/platforms/linux-sgx/enclave-sample/) project, setting the flag `WAMR_BUILD_SGX_IPFS=1` when running `cmake` enables these changes automatically.
215+
216+
217+
### Verification of SGX IPFS
218+
One can observe the usage of IPFS by running the [file sample](../samples/file/) WebAssembly application.
219+
Enabling the SGX IPFS on this sample project leads to the generation of an encrypted text file.
220+
221+
222+
### Mapping of WASI/POSIX to IPFS
223+
This table summarizes how WASI is mapped to POSIX and IPFS.
224+
Since IPFS is a subset of the WASI/POSIX, emulation is performed to fill the missing implementation.
225+
226+
| WASI | POSIX | IPFS |
227+
|------------------------|-------------------|-------------------------------------------------------------------------------------------------------------------------|
228+
| `fd_read` | `readv` | `sgx_fread` |
229+
| `fd_write` | `writev` | `sgx_fwrite` |
230+
| `fd_close` | `close` | `sgx_fclose` |
231+
| `path_open` | `openat` | `sgx_fopen` |
232+
| `fd_datasync` | `fsync` | `sgx_fflush` |
233+
| `fd_tell` | `lseek` | `sgx_ftell` |
234+
| `fd_filestat_set_size` | `ftruncate` | Shrinking files is not supported, nor emulated. Extending files is emulated using `sgx_fseek`/`sgx_ftell`/`sgx_fwrite`. |
235+
| `fd_seek` | `lseek` | The POSIX and IPFS behaviors differ. Emulated using `sgx_fseek`/`sgx_ftell`/`sgx_fwrite`. |
236+
| `fd_pwrite` | `pwrite` | Not supported. Emulated using `sgx_fseek`/`sgx_ftell`/`sgx_fwrite`. |
237+
| `fd_pread` | `pread` | Not supported. Emulated using `sgx_fseek`/`sgx_ftell`/`sgx_fread`. |
238+
| `fd_allocate` | `posix_fallocate` | Not supported. Emulated using `sgx_fseek`/`sgx_ftell`/`sgx_fwrite`/`sgx_fflush`. |
239+
240+
241+
### Performance overheads
242+
Many benchmarks have assessed the overheads caused by IPFS through WASI functions using Twine, an early and academic adaptation of WAMR in Intel SGX with WASI support.
243+
The results can be found in [this paper](https://arxiv.org/abs/2103.15860).
244+
245+
### Limitations
246+
The threat model and the limitations of SGX IPFS can be found in [the official documentation](https://www.intel.com/content/dam/develop/external/us/en/documents/overviewofintelprotectedfilesystemlibrary.pdf).
247+
248+
198249
Others
199250
------
200251

‎product-mini/platforms/linux-sgx/CMakeLists.txt

+25
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ if (NOT DEFINED WAMR_BUILD_SIMD)
8484
set (WAMR_BUILD_SIMD 0)
8585
endif ()
8686

87+
if (NOT DEFINED WAMR_BUILD_SGX_IPFS)
88+
# Disable SGX IPFS by default
89+
set (WAMR_BUILD_SGX_IPFS 0)
90+
endif ()
91+
8792
if (COLLECT_CODE_COVERAGE EQUAL 1)
8893
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage")
8994
endif ()
@@ -117,3 +122,23 @@ else()
117122
OUTPUT_VARIABLE cmdOutput
118123
)
119124
endif()
125+
126+
if (WAMR_BUILD_SGX_IPFS EQUAL 1)
127+
execute_process(
128+
COMMAND bash -c "sed -i -E 's/^#define SGX_IPFS 0/#define SGX_IPFS 1/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Enclave/Enclave.edl"
129+
OUTPUT_VARIABLE cmdOutput
130+
)
131+
execute_process(
132+
COMMAND bash -c "sed -i -E 's/^SGX_IPFS = 0/SGX_IPFS = 1/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Makefile"
133+
OUTPUT_VARIABLE cmdOutput
134+
)
135+
else()
136+
execute_process(
137+
COMMAND bash -c "sed -i -E 's/^#define SGX_IPFS 1/#define SGX_IPFS 0/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Enclave/Enclave.edl"
138+
OUTPUT_VARIABLE cmdOutput
139+
)
140+
execute_process(
141+
COMMAND bash -c "sed -i -E 's/^SGX_IPFS = 1/SGX_IPFS = 0/g' ${CMAKE_CURRENT_SOURCE_DIR}/enclave-sample/Makefile"
142+
OUTPUT_VARIABLE cmdOutput
143+
)
144+
endif()

‎product-mini/platforms/linux-sgx/enclave-sample/Enclave/Enclave.edl

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
#define LIB_RATS 0
7+
#define SGX_IPFS 0
78

89
enclave {
910
from "sgx_tstdc.edl" import *;
@@ -12,6 +13,9 @@ enclave {
1213
#if LIB_RATS != 0
1314
from "rats.edl" import *;
1415
#endif
16+
#if SGX_IPFS != 0
17+
from "sgx_tprotected_fs.edl" import *;
18+
#endif
1519

1620
trusted {
1721
/* define ECALLs here. */

‎product-mini/platforms/linux-sgx/enclave-sample/Makefile

+10-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ SGX_ARCH ?= x64
99
SGX_DEBUG ?= 0
1010
SPEC_TEST ?= 0
1111

12+
# This variable is automatically set by CMakeLists.txt
13+
SGX_IPFS = 0
14+
1215
VMLIB_BUILD_DIR ?= $(CURDIR)/../build
1316
LIB_RATS_SRC ?= $(VMLIB_BUILD_DIR)/_deps/librats-build
1417
LIB_RATS := $(shell if [ -d $(LIB_RATS_SRC) ]; then echo 1; else echo 0; fi)
@@ -106,6 +109,12 @@ else
106109
Trts_Library_Name := sgx_trts
107110
Service_Library_Name := sgx_tservice
108111
endif
112+
113+
ifeq ($(SGX_IPFS), 1)
114+
Intel_Ipfs_Trusted_Flag = -lsgx_tprotected_fs
115+
App_Link_Flags += -lsgx_uprotected_fs
116+
endif
117+
109118
Crypto_Library_Name := sgx_tcrypto
110119

111120
WAMR_ROOT := $(CURDIR)/../../../../
@@ -139,7 +148,7 @@ endif
139148

140149
Enclave_Cpp_Flags := $(Enclave_C_Flags) -std=c++11 -nostdinc++
141150
Enclave_Link_Flags := $(SGX_COMMON_CFLAGS) -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles -L$(SGX_LIBRARY_PATH) ${Rats_Lib_Link_Dirs} \
142-
-Wl,--whole-archive -l$(Trts_Library_Name) ${Rats_Lib_Link_libs} -Wl,--no-whole-archive \
151+
-Wl,--whole-archive -l$(Trts_Library_Name) ${Rats_Lib_Link_libs} $(Intel_Ipfs_Trusted_Flag) -Wl,--no-whole-archive \
143152
-Wl,--start-group -lsgx_tstdc -lsgx_tcxx -lsgx_pthread -lsgx_tkey_exchange -l$(Crypto_Library_Name) -l$(Service_Library_Name) -lsgx_dcap_tvl -Wl,--end-group \
144153
-Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \
145154
-Wl,-pie,-eenclave_entry -Wl,--export-dynamic \
@@ -217,7 +226,6 @@ $(App_Name): App/Enclave_u.o $(App_Cpp_Objects) libvmlib_untrusted.a
217226

218227

219228
######## Enclave Objects ########
220-
221229
Enclave/Enclave_t.c: $(SGX_EDGER8R) Enclave/Enclave.edl librats
222230
@cd Enclave && $(SGX_EDGER8R) --trusted ../Enclave/Enclave.edl $(Enclave_Edl_Search_Path)
223231
@echo "GEN => $@"

‎samples/file/CMakeLists.txt

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Copyright (C) 2022 Intel Corporation. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
cmake_minimum_required(VERSION 3.0)
5+
project(file)
6+
7+
################ wasm application ###############
8+
add_subdirectory(src)
9+
add_subdirectory(wasm-app)

‎samples/file/README.md

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# "file" sample introduction
2+
3+
This sample demonstrates the supported file interaction API of WASI.
4+
This sample can also demonstrate the SGX IPFS (Intel Protected File System), enabling an enclave to seal and unseal data at rest.
5+
6+
## Preparation
7+
8+
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`.
9+
For testing with SGX IPFS, follow the instructions in [the documentation of SGX for WAMR](../../doc/linux_sgx.md#sgx-intel-protected-file-system).
10+
11+
## Build the sample
12+
13+
```bash
14+
mkdir build
15+
cd build
16+
cmake ..
17+
make
18+
```
19+
20+
The WebAssembly application is the file located at `wasm-app/file.wasm`.
21+
22+
## Run workload
23+
24+
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=.`).
25+
26+
The output with Linux and POSIX is like:
27+
28+
```bash
29+
Opening a file..
30+
[Test] File opening passed.
31+
Writing to the file..
32+
[Test] File writing passed.
33+
Moving the cursor to the start of the file..
34+
Reading from the file, up to 1000 characters..
35+
Text read: Hello, world!
36+
[Test] File reading passed.
37+
Determine whether we reach the end of the file..
38+
Is the end of file? 1
39+
[Test] End of file detection passed.
40+
Getting the plaintext size..
41+
The plaintext size is 13.
42+
[Test] Retrieving file offset passed.
43+
Force actual write of all the cached data to the disk..
44+
[Test] Retrieving file offset passed.
45+
Writing 5 characters at offset 7..
46+
File current offset: 13
47+
[Test] Writing at specified offset passed.
48+
Reading 5 characters at offset 7..
49+
Text read: James
50+
File current offset: 13
51+
[Test] Reading at specified offset passed.
52+
Allocate more space to the file..
53+
File current offset: 13
54+
Moving to the end..
55+
File current offset: 23
56+
[Test] Allocation or more space passed.
57+
Extend the file size of 10 bytes using ftruncate..
58+
File current offset: 23
59+
Moving to the end..
60+
File current offset: 33
61+
[Test] Extension of the file size passed.
62+
Closing from the file..
63+
[Test] Closing file passed.
64+
Getting the size of the file on disk..
65+
The file size is 33.
66+
All the tests passed!
67+
```
68+
69+
The output with SGX and IPFS is like:
70+
71+
```bash
72+
Opening a file..
73+
[Test] File opening passed.
74+
Writing to the file..
75+
[Test] File writing passed.
76+
Moving the cursor to the start of the file..
77+
Reading from the file, up to 1000 characters..
78+
Text read: Hello, world!
79+
[Test] File reading passed.
80+
Determine whether we reach the end of the file..
81+
Is the end of file? 1
82+
[Test] End of file detection passed.
83+
Getting the plaintext size..
84+
The plaintext size is 13.
85+
[Test] Retrieving file offset passed.
86+
Force actual write of all the cached data to the disk..
87+
[Test] Retrieving file offset passed.
88+
Writing 5 characters at offset 7..
89+
File current offset: 13
90+
[Test] Writing at specified offset passed.
91+
Reading 5 characters at offset 7..
92+
Text read: James
93+
File current offset: 13
94+
[Test] Reading at specified offset passed.
95+
Allocate more space to the file..
96+
File current offset: 23
97+
Moving to the end..
98+
File current offset: 23
99+
[Test] Allocation or more space passed.
100+
Extend the file size of 10 bytes using ftruncate..
101+
File current offset: 23
102+
Moving to the end..
103+
File current offset: 33
104+
[Test] Extension of the file size passed.
105+
Closing from the file..
106+
[Test] Closing file passed.
107+
Getting the size of the file on disk..
108+
The file size is 4096.
109+
All the tests passed!
110+
```
111+
112+
For SGX IPFS, refer to [SGX Intel Protected File System](../../doc/linux_sgx.md#sgx-intel-protected-file-system) for more details.

‎samples/file/src/CMakeLists.txt

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Copyright (C) 2022 Intel Corporation. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
cmake_minimum_required (VERSION 3.0)
5+
6+
if (NOT WAMR_BUILD_PLATFORM STREQUAL "windows")
7+
project (iwasm)
8+
else()
9+
project (iwasm C ASM)
10+
enable_language (ASM_MASM)
11+
endif()
12+
13+
################ runtime settings ################
14+
string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM)
15+
if (APPLE)
16+
add_definitions(-DBH_PLATFORM_DARWIN)
17+
endif ()
18+
19+
# Reset default linker flags
20+
set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
21+
set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
22+
23+
# WAMR features switch
24+
25+
# Set WAMR_BUILD_TARGET, currently values supported:
26+
# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]",
27+
# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]"
28+
if (NOT DEFINED WAMR_BUILD_TARGET)
29+
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)")
30+
set (WAMR_BUILD_TARGET "AARCH64")
31+
elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64")
32+
set (WAMR_BUILD_TARGET "RISCV64")
33+
elseif (CMAKE_SIZEOF_VOID_P EQUAL 8)
34+
# Build as X86_64 by default in 64-bit platform
35+
set (WAMR_BUILD_TARGET "X86_64")
36+
elseif (CMAKE_SIZEOF_VOID_P EQUAL 4)
37+
# Build as X86_32 by default in 32-bit platform
38+
set (WAMR_BUILD_TARGET "X86_32")
39+
else ()
40+
message(SEND_ERROR "Unsupported build target platform!")
41+
endif ()
42+
endif ()
43+
44+
if (NOT CMAKE_BUILD_TYPE)
45+
set (CMAKE_BUILD_TYPE Release)
46+
endif ()
47+
48+
set (WAMR_BUILD_INTERP 1)
49+
set (WAMR_BUILD_AOT 1)
50+
set (WAMR_BUILD_JIT 0)
51+
set (WAMR_BUILD_LIBC_BUILTIN 1)
52+
53+
if (NOT MSVC)
54+
set (WAMR_BUILD_LIBC_WASI 1)
55+
endif ()
56+
57+
if (NOT MSVC)
58+
# linker flags
59+
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie -fPIE")
60+
if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang"))
61+
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
62+
endif ()
63+
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security")
64+
if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64")
65+
if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang"))
66+
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register")
67+
endif ()
68+
endif ()
69+
endif ()
70+
71+
# build out vmlib
72+
set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../../..)
73+
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
74+
75+
add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE})
76+
77+
################ application related ################
78+
include_directories(${CMAKE_CURRENT_LIST_DIR})
79+
include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
80+
81+
add_executable (iwasm main.c ${UNCOMMON_SHARED_SOURCE})
82+
83+
if (APPLE)
84+
target_link_libraries (iwasm vmlib -lm -ldl -lpthread)
85+
else ()
86+
target_link_libraries (iwasm vmlib -lm -ldl -lpthread -lrt)
87+
endif ()

‎samples/file/src/main.c

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright (C) 2022 Intel Corporation. All rights reserved.
3+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
*/
5+
6+
#include "wasm_export.h"
7+
#include "bh_read_file.h"
8+
9+
void
10+
print_usage(void)
11+
{
12+
fprintf(stdout, "Required arguments:\r\n");
13+
fprintf(stdout, " -f [path of wasm file] \n");
14+
fprintf(stdout, " -d [path of host directory] \n");
15+
}
16+
17+
int
18+
main(int argc, char *argv_main[])
19+
{
20+
static char global_heap_buf[512 * 1024];
21+
char *buffer, error_buf[128];
22+
const char *wasm_path = NULL, *wasi_dir = NULL;
23+
int opt;
24+
25+
wasm_module_t module = NULL;
26+
wasm_module_inst_t module_inst = NULL;
27+
wasm_exec_env_t exec_env = NULL;
28+
uint32 buf_size, stack_size = 8092, heap_size = 8092;
29+
uint32_t wasm_buffer = 0;
30+
31+
RuntimeInitArgs init_args;
32+
memset(&init_args, 0, sizeof(RuntimeInitArgs));
33+
34+
while ((opt = getopt(argc, argv_main, "hf:d:")) != -1) {
35+
switch (opt) {
36+
case 'f':
37+
wasm_path = optarg;
38+
break;
39+
case 'd':
40+
wasi_dir = optarg;
41+
break;
42+
case 'h':
43+
print_usage();
44+
return 0;
45+
case '?':
46+
print_usage();
47+
return 0;
48+
}
49+
}
50+
if (wasm_path == NULL || wasi_dir == NULL) {
51+
print_usage();
52+
return 0;
53+
}
54+
55+
init_args.mem_alloc_type = Alloc_With_Pool;
56+
init_args.mem_alloc_option.pool.heap_buf = global_heap_buf;
57+
init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf);
58+
59+
if (!wasm_runtime_full_init(&init_args)) {
60+
printf("Init runtime environment failed.\n");
61+
return -1;
62+
}
63+
64+
buffer = bh_read_file_to_buffer(wasm_path, &buf_size);
65+
66+
if (!buffer) {
67+
printf("Open wasm app file [%s] failed.\n", wasm_path);
68+
goto fail;
69+
}
70+
71+
module = wasm_runtime_load(buffer, buf_size, error_buf, sizeof(error_buf));
72+
if (!module) {
73+
printf("Load wasm module failed. error: %s\n", error_buf);
74+
goto fail;
75+
}
76+
77+
wasm_runtime_set_wasi_args_ex(module, &wasi_dir, 1, NULL, 0, NULL, 0, NULL,
78+
0, 0, 1, 2);
79+
80+
module_inst = wasm_runtime_instantiate(module, stack_size, heap_size,
81+
error_buf, sizeof(error_buf));
82+
83+
if (!module_inst) {
84+
printf("Instantiate wasm module failed. error: %s\n", error_buf);
85+
goto fail;
86+
}
87+
88+
exec_env = wasm_runtime_create_exec_env(module_inst, stack_size);
89+
if (!exec_env) {
90+
printf("Create wasm execution environment failed.\n");
91+
goto fail;
92+
}
93+
94+
if (wasm_application_execute_main(module_inst, 0, NULL)) {
95+
printf("Main wasm function successfully finished.\n");
96+
}
97+
else {
98+
printf("call wasm function main failed. error: %s\n",
99+
wasm_runtime_get_exception(module_inst));
100+
goto fail;
101+
}
102+
103+
fail:
104+
if (exec_env)
105+
wasm_runtime_destroy_exec_env(exec_env);
106+
if (module_inst) {
107+
if (wasm_buffer)
108+
wasm_runtime_module_free(module_inst, wasm_buffer);
109+
wasm_runtime_deinstantiate(module_inst);
110+
}
111+
if (module)
112+
wasm_runtime_unload(module);
113+
if (buffer)
114+
BH_FREE(buffer);
115+
wasm_runtime_destroy();
116+
return 0;
117+
}

‎samples/file/wasm-app/CMakeLists.txt

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright (C) 2022 Intel Corporation. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
cmake_minimum_required(VERSION 3.0)
5+
project(wasm-app)
6+
7+
set (WAMR_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../..)
8+
9+
if (APPLE)
10+
set (HAVE_FLAG_SEARCH_PATHS_FIRST 0)
11+
set (CMAKE_C_LINK_FLAGS "")
12+
set (CMAKE_CXX_LINK_FLAGS "")
13+
endif ()
14+
15+
set (CMAKE_SYSTEM_PROCESSOR wasm32)
16+
17+
if (NOT DEFINED WASI_SDK_DIR)
18+
set (WASI_SDK_DIR "/opt/wasi-sdk")
19+
endif ()
20+
21+
set (CMAKE_C_COMPILER_TARGET "wasm32-wasi")
22+
set (CMAKE_C_COMPILER "${WASI_SDK_DIR}/bin/clang")
23+
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Wno-unused-command-line-argument")
24+
25+
add_executable(file.wasm main.c)
26+
target_link_libraries(file.wasm)

‎samples/file/wasm-app/main.c

+132
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* Copyright (C) 2019 Intel Corporation. All rights reserved.
3+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
*/
5+
6+
#include <stdio.h>
7+
#include <stdlib.h>
8+
#include <string.h>
9+
#include <assert.h>
10+
#include <errno.h>
11+
#include <fcntl.h>
12+
#include <sys/stat.h>
13+
#include <unistd.h>
14+
15+
#define PATH_TEST_FILE "test.txt"
16+
#define FILE_TEXT "Hello, world!"
17+
#define WORLD_OFFSET 7
18+
#define NAME_REPLACMENT "James"
19+
#define NAME_REPLACMENT_LEN (sizeof(NAME_REPLACMENT) - 1)
20+
#define ADDITIONAL_SPACE 10
21+
22+
int
23+
main(int argc, char **argv)
24+
{
25+
FILE *file;
26+
const char *text = FILE_TEXT;
27+
char buffer[1000];
28+
int ret;
29+
30+
// Test: File opening (fopen)
31+
printf("Opening a file..\n");
32+
file = fopen(PATH_TEST_FILE, "w+");
33+
if (file == NULL) {
34+
printf("Error! errno: %d\n", errno);
35+
}
36+
assert(file != NULL);
37+
printf("[Test] File opening passed.\n");
38+
39+
// Test: Writing to a file (fprintf)
40+
printf("Writing to the file..\n");
41+
ret = fprintf(file, "%s", text);
42+
assert(ret == strlen(text));
43+
printf("[Test] File writing passed.\n");
44+
45+
// Test: Reading from a file (fseek)
46+
printf("Moving the cursor to the start of the file..\n");
47+
ret = fseek(file, 0, SEEK_SET);
48+
assert(ret == 0);
49+
50+
printf("Reading from the file, up to 1000 characters..\n");
51+
fread(buffer, 1, sizeof(buffer), file);
52+
printf("Text read: %s\n", buffer);
53+
assert(strncmp(text, buffer, strlen(text)) == 0);
54+
printf("[Test] File reading passed.\n");
55+
56+
// Test: end of file detection (feof)
57+
printf("Determine whether we reach the end of the file..\n");
58+
int is_end_of_file = feof(file);
59+
printf("Is the end of file? %d\n", is_end_of_file);
60+
assert(is_end_of_file == 1);
61+
printf("[Test] End of file detection passed.\n");
62+
63+
// Test: retrieving file offset (ftell)
64+
printf("Getting the plaintext size..\n");
65+
long plaintext_size = ftell(file);
66+
printf("The plaintext size is %ld.\n", plaintext_size);
67+
assert(plaintext_size == 13);
68+
printf("[Test] Retrieving file offset passed.\n");
69+
70+
// Test: persist changes on disk (fflush)
71+
printf("Force actual write of all the cached data to the disk..\n");
72+
ret = fflush(file);
73+
assert(ret == 0);
74+
printf("[Test] Retrieving file offset passed.\n");
75+
76+
// Test: writing at specified offset (pwrite)
77+
printf("Writing 5 characters at offset %d..\n", WORLD_OFFSET);
78+
ret = pwrite(fileno(file), NAME_REPLACMENT, NAME_REPLACMENT_LEN,
79+
WORLD_OFFSET);
80+
printf("File current offset: %ld\n", ftell(file));
81+
assert(ret == NAME_REPLACMENT_LEN);
82+
assert(ftell(file) == strlen(FILE_TEXT));
83+
printf("[Test] Writing at specified offset passed.\n");
84+
85+
// Test: reading at specified offset (pread)
86+
printf("Reading %ld characters at offset %d..\n", NAME_REPLACMENT_LEN,
87+
WORLD_OFFSET);
88+
buffer[NAME_REPLACMENT_LEN] = '\0';
89+
pread(fileno(file), buffer, NAME_REPLACMENT_LEN, WORLD_OFFSET);
90+
printf("Text read: %s\n", buffer);
91+
printf("File current offset: %ld\n", ftell(file));
92+
assert(strcmp(NAME_REPLACMENT, buffer) == 0);
93+
assert(ftell(file) == strlen(FILE_TEXT));
94+
printf("[Test] Reading at specified offset passed.\n");
95+
96+
// Test: allocate more space to the file (posix_fallocate)
97+
printf("Allocate more space to the file..\n");
98+
posix_fallocate(fileno(file), ftell(file), ADDITIONAL_SPACE);
99+
printf("File current offset: %ld\n", ftell(file));
100+
printf("Moving to the end..\n");
101+
fseek(file, 0, SEEK_END);
102+
printf("File current offset: %ld\n", ftell(file));
103+
assert(ftell(file) == strlen(text) + ADDITIONAL_SPACE);
104+
printf("[Test] Allocation or more space passed.\n");
105+
106+
// Test: allocate more space to the file (ftruncate)
107+
printf("Extend the file size of 10 bytes using ftruncate..\n");
108+
ftruncate(fileno(file), ftell(file) + 10);
109+
assert(ftell(file) == strlen(text) + ADDITIONAL_SPACE);
110+
printf("File current offset: %ld\n", ftell(file));
111+
printf("Moving to the end..\n");
112+
fseek(file, 0, SEEK_END);
113+
printf("File current offset: %ld\n", ftell(file));
114+
assert(ftell(file) == strlen(text) + 2 * ADDITIONAL_SPACE);
115+
printf("[Test] Extension of the file size passed.\n");
116+
117+
// Test: closing the file (fclose)
118+
printf("Closing from the file..\n");
119+
ret = fclose(file);
120+
assert(ret == 0);
121+
printf("[Test] Closing file passed.\n");
122+
123+
// Display some debug information
124+
printf("Getting the size of the file on disk..\n");
125+
struct stat st;
126+
stat(PATH_TEST_FILE, &st);
127+
printf("The file size is %lld.\n", st.st_size);
128+
129+
printf("All the tests passed!\n");
130+
131+
return 0;
132+
}

0 commit comments

Comments
 (0)
Please sign in to comment.