diff --git a/demos/README.md b/demos/README.md index c5635f95..1e4ba82a 100644 --- a/demos/README.md +++ b/demos/README.md @@ -15,14 +15,20 @@ This set of demos shows how the Occlum toolchain can be used with different buil This set of demos shows how real-world apps can be easily run inside SGX enclaves with Occlum. * [https_server](https_server/): A HTTPS file server based on [Mongoose Embedded Web Server Library](https://github.com/cesanta/mongoose). -* [golang](golang/): A [Golang](https://golang.org) web server demo app. -* [grpc](grpc/): A client and server communicating through [gRPC](https://grpc.io/). +* [grpc](grpc/): A client and server communicating through [gRPC](https://grpc.io). * [openvino](openvino/) A benchmark of [OpenVINO Inference Engine](https://docs.openvinotoolkit.org/2019_R3/_docs_IE_DG_inference_engine_intro.html). -* [python](python/) A demo of [Python](https://www.python.org). -* [rust](rust/) A demo of [Rust](https://www.rust-lang.org/). * [sqlite](sqlite/) A demo of [SQLite](https://www.sqlite.org) SQL database engine. * [tensorflow_lite](tensorflow_lite/): A demo and benchmark of [Tensorflow Lite](https://www.tensorflow.org/lite) inference engine. -* [xgboost](xgboost/): A demo of [XGBoost](https://xgboost.readthedocs.io/en/latest/). +* [xgboost](xgboost/): A demo of [XGBoost](https://xgboost.readthedocs.io/en/latest). + +## Programming language demos + +This set of demos shows how apps written with popular programming languages can be run inside SGX enclaves with Occlum. + +* [golang](golang/): A [Golang](https://golang.org) web server demo app. +* [java](java/): A demo of [Java](https://openjdk.java.net) program. +* [python](python/) A demo of [Python](https://www.python.org) program. +* [rust](rust/) A demo of [Rust](https://www.rust-lang.org) program. ## Other demos diff --git a/demos/golang/run_golang_on_occlum.sh b/demos/golang/run_golang_on_occlum.sh index 77edae00..a5295cf5 100755 --- a/demos/golang/run_golang_on_occlum.sh +++ b/demos/golang/run_golang_on_occlum.sh @@ -16,7 +16,8 @@ fi rm -rf occlum_context && mkdir occlum_context cd occlum_context occlum init -new_json="$(jq '.resource_limits.user_space_size = "380MB" | .process.default_mmap_size = "300MB"' Occlum.json)" && \ +new_json="$(jq '.resource_limits.user_space_size = "380MB" | + .process.default_mmap_size = "300MB"' Occlum.json)" && \ echo "${new_json}" > Occlum.json # 2. Copy program into Occlum Workspace and build diff --git a/demos/java/.gitignore b/demos/java/.gitignore new file mode 100644 index 00000000..7db3632b --- /dev/null +++ b/demos/java/.gitignore @@ -0,0 +1,3 @@ +occlum_context/ +gs-messaging-stomp-websocket/ +*/*.class diff --git a/demos/java/README.md b/demos/java/README.md new file mode 100644 index 00000000..a5bf4d1e --- /dev/null +++ b/demos/java/README.md @@ -0,0 +1,50 @@ +# Use Java with Occlum + +This project demonstrates how Occlum enables _unmodified_ Java programs running in SGX enclaves. + +# About JDK + +JDK 11 is supported currently. The source code of JDK 11 can be found [here](https://hg.openjdk.java.net/portola/jdk11). In order for it to cooperate with Occlum, a [minor modification](../../tools/toolchains/java/) has been made to it. The modified JDK is compiled in Alpine Linux with `bash configure && make images` commands. We have installed it at `/opt/occlum/toolchains/jvm/java-11-openjdk/jre` while making the Docker image. + +## Demo: Hello World + +We provide a "Hello World" demo to show how to run a simple Java program inside SGX enclaves. The demo code can be found [here](hello_world/). + +### How to Run + +Step 1: Compile the source code with `occlum-javac` +``` +occlum-javac ./hello_world/Main.java +``` +When completed, the resulting file can be found at `./hello_world/Main.class`. + +Step 2: Start JVM to run the hello world program +``` +./run_java_on_occlum.sh hello +``` + +## Demo: Web application with Spring Boot + +We also choose a Java web application that using WebSocket with [Spring Boot](https://spring.io/projects/spring-boot). The demo code can be found [here](https://github.com/spring-guides/gs-messaging-stomp-websocket). + +### How to Run + +Step 1: Download the demo code and build a Fat JAR file with Maven +``` +./download_and_build_web_app.sh +``` +When completed, the resulting Fat JAR file can be found at `./gs-messaging-stomp-websocket/complete/target/gs-messaging-stomp-websocket-0.1.0.jar`. + +Step 2: Start JVM to run the JAR file on Occlum +``` +./run_java_on_occlum.sh web_app +``` +The web application should now start to listen on port 8080 and serve requests. + +Step 3: To check whether it works, run +``` +curl http://localhost:8080 +``` +in another terminal. + +It is recommended to access the web application in a Web browser. You have to manually map port 8080 of the Docker container to a port on the host OS. Check out how to use [the `-p` argument of `docker run` command](https://docs.docker.com/engine/reference/commandline/run/). diff --git a/demos/java/download_and_build_web_app.sh b/demos/java/download_and_build_web_app.sh new file mode 100755 index 00000000..8cbf9225 --- /dev/null +++ b/demos/java/download_and_build_web_app.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -e + +# 1. Download the demo +rm -rf gs-messaging-stomp-websocket && mkdir gs-messaging-stomp-websocket +cd gs-messaging-stomp-websocket +git clone https://github.com/spring-guides/gs-messaging-stomp-websocket.git . +git checkout -b 2.1.6.RELEASE tags/2.1.6.RELEASE + +# 2. Build the Fat JAR file with Maven +cd complete +export LD_LIBRARY_PATH=/opt/occlum/toolchains/gcc/x86_64-linux-musl/lib +export JAVA_HOME=/opt/occlum/toolchains/jvm/java-11-openjdk/jre +./mvnw clean package diff --git a/demos/java/hello_world/Main.java b/demos/java/hello_world/Main.java new file mode 100644 index 00000000..5a5f303d --- /dev/null +++ b/demos/java/hello_world/Main.java @@ -0,0 +1,5 @@ +public class Main { + public static void main(String[] args) { + System.out.println("Hello, World!"); + } +} diff --git a/demos/java/run_java_on_occlum.sh b/demos/java/run_java_on_occlum.sh new file mode 100755 index 00000000..31960ace --- /dev/null +++ b/demos/java/run_java_on_occlum.sh @@ -0,0 +1,85 @@ +#!/bin/bash +set -e + +BLUE='\033[1;34m' +NC='\033[0m' + +show_usage() { + echo "Error: invalid arguments" + echo "Usage: $0 web_app/hello" + exit 1 +} + +check_file_exist() { + file=$1 + if [ ! -f ${file} ];then + echo "Error: cannot stat file '${file}'" + echo "Please see README and build it" + exit 1 + fi +} + +init_workspace() { + # Init Occlum Workspace + rm -rf occlum_context && mkdir occlum_context + cd occlum_context + occlum init + new_json="$(jq '.resource_limits.user_space_size = "1400MB" | + .resource_limits.kernel_space_heap_size="64MB" | + .resource_limits.max_num_of_threads = 64 | + .process.default_heap_size = "256MB" | + .process.default_mmap_size = "1120MB" | + .entry_points = [ "/usr/lib/jvm/java-11-openjdk/jre/bin" ] | + .env.default = [ "LD_LIBRARY_PATH=/usr/lib/jvm/java-11-openjdk/jre/lib/server:/usr/lib/jvm/java-11-openjdk/jre/lib:/usr/lib/jvm/java-11-openjdk/jre/../lib" ]' Occlum.json)" && \ + echo "${new_json}" > Occlum.json +} + +build_web() { + # Copy JVM and JAR file into Occlum Workspace and build + mkdir -p image/usr/lib + cp -r /opt/occlum/toolchains/jvm image/usr/lib/ + cp /usr/local/occlum/x86_64-linux-musl/lib/libz.so.1 image/lib + mkdir -p image/usr/lib/spring + cp ../${jar_path} image/usr/lib/spring/ + occlum build +} + +run_web() { + jar_path=./gs-messaging-stomp-websocket/complete/target/gs-messaging-stomp-websocket-0.1.0.jar + check_file_exist ${jar_path} + jar_file=`basename "${jar_path}"` + init_workspace + build_web + echo -e "${BLUE}occlum run JVM web app${NC}" + occlum run /usr/lib/jvm/java-11-openjdk/jre/bin/java -Xmx512m -XX:MaxMetaspaceSize=64m -Dos.name=Linux -jar /usr/lib/spring/${jar_file} +} + +build_hello() { + # Copy JVM and class file into Occlum Workspace and build + mkdir -p image/usr/lib + cp -r /opt/occlum/toolchains/jvm image/usr/lib/ + cp /usr/local/occlum/x86_64-linux-musl/lib/libz.so.1 image/lib + cp ../${hello} image + occlum build +} + +run_hello() { + hello=./hello_world/Main.class + check_file_exist ${hello} + init_workspace + build_hello + echo -e "${BLUE}occlum run JVM hello${NC}" + occlum run /usr/lib/jvm/java-11-openjdk/jre/bin/java -Xmx512m -XX:MaxMetaspaceSize=64m -Dos.name=Linux Main +} + +arg=$1 +case "$arg" in + web_app) + run_web + ;; + hello) + run_hello + ;; + *) + show_usage +esac diff --git a/demos/openvino/run_benchmark_on_occlum.sh b/demos/openvino/run_benchmark_on_occlum.sh index eb1a65f0..bb9b0a9a 100755 --- a/demos/openvino/run_benchmark_on_occlum.sh +++ b/demos/openvino/run_benchmark_on_occlum.sh @@ -9,7 +9,8 @@ rm -rf occlum_context mkdir occlum_context cd occlum_context occlum init -new_json="$(jq '.resource_limits.user_space_size = "320MB" | .process.default_mmap_size = "256MB"' Occlum.json)" && \ +new_json="$(jq '.resource_limits.user_space_size = "320MB" | + .process.default_mmap_size = "256MB"' Occlum.json)" && \ echo "${new_json}" > Occlum.json # 2. Copy files into Occlum Workspace and Build diff --git a/demos/python/run_python_on_occlum.sh b/demos/python/run_python_on_occlum.sh index 1211b728..50cabd62 100755 --- a/demos/python/run_python_on_occlum.sh +++ b/demos/python/run_python_on_occlum.sh @@ -34,7 +34,10 @@ if [ ! -d "image/lib/python3.7" ];then cp -f $alpine_fs/lib/libz.so.1 image/lib cp -rf ../dataset image cp -f ../demo.py image - new_json="$(jq '.resource_limits.user_space_size = "320MB" | .resource_limits.kernel_space_heap_size = "144MB" | .process.default_mmap_size = "256MB"' Occlum.json)" && echo "${new_json}" > Occlum.json + new_json="$(jq '.resource_limits.user_space_size = "320MB" | + .resource_limits.kernel_space_heap_size = "144MB" | + .process.default_mmap_size = "256MB"' Occlum.json)" && \ + echo "${new_json}" > Occlum.json occlum build fi diff --git a/tools/docker/Dockerfile.centos7.5 b/tools/docker/Dockerfile.centos7.5 index 22ea54d9..ff56b9ba 100644 --- a/tools/docker/Dockerfile.centos7.5 +++ b/tools/docker/Dockerfile.centos7.5 @@ -107,6 +107,12 @@ RUN cd rust && ./build.sh && rm -rf /tmp/rust ENV PATH="/opt/occlum/toolchains/rust/bin:$PATH" ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/opt/intel/sgxsdk/sdk_libs" +# Install Occlum Java toolchain (JDK 11) +COPY toolchains/java /tmp/java +WORKDIR /tmp +RUN cd java && ./install.sh && rm -rf /tmp/java +ENV PATH="/opt/occlum/toolchains/jvm/bin:$PATH" + # Install the latest version of Occlum WORKDIR /root RUN git clone https://github.com/occlum/occlum && \ diff --git a/tools/docker/Dockerfile.ubuntu18.04 b/tools/docker/Dockerfile.ubuntu18.04 index 4c5e952e..d32d35e4 100644 --- a/tools/docker/Dockerfile.ubuntu18.04 +++ b/tools/docker/Dockerfile.ubuntu18.04 @@ -94,6 +94,12 @@ RUN cd rust && ./build.sh && rm -rf /tmp/rust ENV PATH="/opt/occlum/toolchains/rust/bin:$PATH" ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/opt/intel/sgxsdk/sdk_libs" +# Install Occlum Java toolchain (JDK 11) +COPY toolchains/java /tmp/java +WORKDIR /tmp +RUN cd java && ./install.sh && rm -rf /tmp/java +ENV PATH="/opt/occlum/toolchains/jvm/bin:$PATH" + # Install the latest version of Occlum WORKDIR /root RUN git clone https://github.com/occlum/occlum && \ diff --git a/tools/toolchains/java/0001-openjdk11-Xhook-SYS_getcpu-vdso-call.patch b/tools/toolchains/java/0001-openjdk11-Xhook-SYS_getcpu-vdso-call.patch new file mode 100644 index 00000000..5404a508 --- /dev/null +++ b/tools/toolchains/java/0001-openjdk11-Xhook-SYS_getcpu-vdso-call.patch @@ -0,0 +1,39 @@ +From f195a65829b168efddad9cbe41b6154c4483005f Mon Sep 17 00:00:00 2001 +From: "jeffery.wsj" +Date: Fri, 10 Jul 2020 08:31:42 +0000 +Subject: [PATCH] Xhook SYS_getcpu vdso call + +--- + src/hotspot/os/linux/os_linux.cpp | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp +index dbf18b7b5f..59a2ef3ab6 100644 +--- a/src/hotspot/os/linux/os_linux.cpp ++++ b/src/hotspot/os/linux/os_linux.cpp +@@ -2876,13 +2876,15 @@ int os::Linux::sched_getcpu_syscall(void) { + #elif defined(AMD64) + // Unfortunately we have to bring all these macros here from vsyscall.h + // to be able to compile on old linuxes. +- #define __NR_vgetcpu 2 +- #define VSYSCALL_START (-10UL << 20) +- #define VSYSCALL_SIZE 1024 +- #define VSYSCALL_ADDR(vsyscall_nr) (VSYSCALL_START+VSYSCALL_SIZE*(vsyscall_nr)) +- typedef long (*vgetcpu_t)(unsigned int *cpu, unsigned int *node, unsigned long *tcache); +- vgetcpu_t vgetcpu = (vgetcpu_t)VSYSCALL_ADDR(__NR_vgetcpu); +- retval = vgetcpu(&cpu, NULL, NULL); ++// #define __NR_vgetcpu 2 ++// #define VSYSCALL_START (-10UL << 20) ++// #define VSYSCALL_SIZE 1024 ++// #define VSYSCALL_ADDR(vsyscall_nr) (VSYSCALL_START+VSYSCALL_SIZE*(vsyscall_nr)) ++// typedef long (*vgetcpu_t)(unsigned int *cpu, unsigned int *node, unsigned long *tcache); ++// vgetcpu_t vgetcpu = (vgetcpu_t)VSYSCALL_ADDR(__NR_vgetcpu); ++// retval = vgetcpu(&cpu, NULL, NULL); ++ cpu = get_nprocs(); ++ retval = 0; + #endif + + return (retval == -1) ? retval : cpu; +-- +2.17.1 + diff --git a/tools/toolchains/java/install.sh b/tools/toolchains/java/install.sh new file mode 100755 index 00000000..1b71cb0c --- /dev/null +++ b/tools/toolchains/java/install.sh @@ -0,0 +1,40 @@ +#!/bin/bash +THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +DOWNLOAD_DIR=/tmp/occlum_java_toolchain +INSTALL_DIR=/opt/occlum/toolchains/jvm + +# Exit if any command fails +set -e + +# Clean previous download and installation if any +rm -rf ${DOWNLOAD_DIR} +rm -rf ${INSTALL_DIR} + +# Create the download directory +mkdir -p ${DOWNLOAD_DIR} +cd ${DOWNLOAD_DIR} + +# Download and install JDK 11 +JDK=openjdk-11-for-occlum-0.14.0 +wget https://github.com/occlum/occlum/releases/download/0.14.0/${JDK}.tar.gz +tar -xf ${JDK}.tar.gz +mkdir -p ${INSTALL_DIR}/java-11-openjdk +mv ${DOWNLOAD_DIR}/${JDK} ${INSTALL_DIR}/java-11-openjdk/jre + +# Clean the download directory +rm -rf ${DOWNLOAD_DIR} + +# Generate the wrappers for executables +mkdir -p ${INSTALL_DIR}/bin +cat > ${INSTALL_DIR}/bin/occlum-java < ${INSTALL_DIR}/bin/occlum-javac <