diff --git a/demos/README.md b/demos/README.md index 566e1773..24ec7398 100644 --- a/demos/README.md +++ b/demos/README.md @@ -15,6 +15,7 @@ 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/). * [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). diff --git a/demos/golang/.gitignore b/demos/golang/.gitignore new file mode 100644 index 00000000..5cc03124 --- /dev/null +++ b/demos/golang/.gitignore @@ -0,0 +1,2 @@ +occlum_context/ +web_server diff --git a/demos/golang/README.md b/demos/golang/README.md new file mode 100644 index 00000000..934ebd00 --- /dev/null +++ b/demos/golang/README.md @@ -0,0 +1,20 @@ +# Use Golang with Occlum + +This project demonstrates how Occlum enables [Golang](https://golang.org) programs running in SGX enclaves. + +Step 1: Build Golang web server program using the Occlum Golang toolchain(i.e., `occlum-go`) +``` +occlum-go build -o web_server -buildmode=pie ./web_server.go +``` + +Step 2: You can run the web server demo on Occlum via +``` +./run_golang_on_occlum.sh +``` +The HTTP web server should now start to listen on port 8090 and serve HTTP requests. + +Step 3: To check whether the HTTP server works, run +``` +curl http://127.0.0.1:8090/hello1 +``` +in another terminal, and get the response "hello,1". diff --git a/demos/golang/run_golang_on_occlum.sh b/demos/golang/run_golang_on_occlum.sh new file mode 100755 index 00000000..273acf5d --- /dev/null +++ b/demos/golang/run_golang_on_occlum.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -e + +BLUE='\033[1;34m' +NC='\033[0m' + +web_server="./web_server" + +if [ ! -f $web_server ];then + echo "Error: cannot stat file '$web_server'" + echo "Please see README and build it using Occlum Golang toolchain" + exit 1 +fi + +# 1. Init Occlum Workspace +rm -rf occlum_context && mkdir occlum_context +cd occlum_context +occlum init +jq '.vm.user_space_size = "320MB"' Occlum.json > temp_Occlum.json +jq '.process.default_mmap_size = "256MB"' temp_Occlum.json > Occlum.json + +# 2. Copy program into Occlum Workspace and build +cp ../web_server image/bin +occlum build + +# 3. Run the hello world sample +echo -e "${BLUE}occlum run /bin/web_server${NC}" +occlum run /bin/web_server diff --git a/demos/golang/web_server.go b/demos/golang/web_server.go new file mode 100644 index 00000000..f7b2bebd --- /dev/null +++ b/demos/golang/web_server.go @@ -0,0 +1,29 @@ +package main + +import "net/http" +import "log" +import "flag" +import "fmt" + +type Controller struct {} +func (c Controller)ServeHTTP(writer http.ResponseWriter, request *http.Request){ + writer.Write([]byte("hello,1\n")); +} + +func hello(writer http.ResponseWriter, request *http.Request) { + writer.Write([]byte("hello,2\n")); +} + +var port string + +func init() { + flag.StringVar(&port, "port", "8090", "port number, default value is 8090") +} + +func main(){ + flag.Parse() + fmt.Println("Web Server port is:", port) + http.Handle("/hello1",&Controller{}) + http.Handle("/hello2",http.HandlerFunc(hello)) + log.Fatal(http.ListenAndServe(":" + port, nil)) +} diff --git a/tools/docker/Dockerfile.centos7.2 b/tools/docker/Dockerfile.centos7.2 index 64753989..8024fdd1 100644 --- a/tools/docker/Dockerfile.centos7.2 +++ b/tools/docker/Dockerfile.centos7.2 @@ -11,6 +11,7 @@ RUN yum update -y && \ cmake \ curl \ curl-devel \ + epel-release \ expect \ fuse-devel \ fuse-libs \ @@ -41,6 +42,7 @@ RUN yum update -y && \ vim \ wget && \ yum groupinstall 'Development Tools' -y && \ + yum install -y golang && \ yum clean all # Install cpuid tool for tests @@ -87,6 +89,12 @@ WORKDIR /tmp RUN ./build.sh ENV PATH="/opt/occlum/build/bin:/usr/local/occlum/bin:$PATH" +# Install Occlum Golang toolchain +COPY toolchains/golang/* /tmp/ +WORKDIR /tmp +RUN ./build.sh +ENV PATH="/usr/local/occlum/golang/bin:$PATH" + # Install the latest version of Occlum WORKDIR /root RUN git clone https://github.com/occlum/occlum && \ diff --git a/tools/docker/Dockerfile.ubuntu16.04 b/tools/docker/Dockerfile.ubuntu16.04 index 50aea1bc..612ec727 100644 --- a/tools/docker/Dockerfile.ubuntu16.04 +++ b/tools/docker/Dockerfile.ubuntu16.04 @@ -15,6 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ gdb \ git-core \ + golang-go \ jq \ kmod \ libboost-system-dev \ @@ -77,6 +78,12 @@ WORKDIR /tmp RUN ./build.sh ENV PATH="/opt/occlum/build/bin:/usr/local/occlum/bin:$PATH" +# Install Occlum Golang toolchain +COPY toolchains/golang/* /tmp/ +WORKDIR /tmp +RUN ./build.sh +ENV PATH="/usr/local/occlum/golang/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 b6b4f79a..ede544ac 100644 --- a/tools/docker/Dockerfile.ubuntu18.04 +++ b/tools/docker/Dockerfile.ubuntu18.04 @@ -15,6 +15,7 @@ RUN apt-get update && DEBIAN_FRONTEND="noninteractive" apt-get install -y --no-i g++ \ gdb \ git-core \ + golang-go \ jq \ kmod \ libboost-system-dev \ @@ -79,6 +80,12 @@ WORKDIR /tmp RUN ./build.sh ENV PATH="/opt/occlum/build/bin:/usr/local/occlum/bin:$PATH" +# Install Occlum Golang toolchain +COPY toolchains/golang/* /tmp/ +WORKDIR /tmp +RUN ./build.sh +ENV PATH="/usr/local/occlum/golang/bin:$PATH" + # Install the latest version of Occlum WORKDIR /root RUN git clone https://github.com/occlum/occlum && \ diff --git a/tools/toolchains/golang/0001-adapt-golang-to-occlum-libos.patch b/tools/toolchains/golang/0001-adapt-golang-to-occlum-libos.patch new file mode 100644 index 00000000..5566c542 --- /dev/null +++ b/tools/toolchains/golang/0001-adapt-golang-to-occlum-libos.patch @@ -0,0 +1,637 @@ +From 4c7e5586d109eba46c4f067699ae652d722270a0 Mon Sep 17 00:00:00 2001 +From: "jeffery.wsj" +Date: Fri, 8 May 2020 18:06:37 +0800 +Subject: [PATCH] adapt golang to occlum libos: + +1. hook heap malloc +2. hook all syscall based on amd64 linux platform +3. hook vdso call +--- + src/runtime/malloc.go | 76 ++++++++++----------- + src/runtime/os_linux.go | 4 ++ + src/runtime/sys_linux_amd64.go | 3 + + src/runtime/sys_linux_amd64.s | 116 +++++++++++++++++++++------------ + src/runtime/textflag.h | 11 ++++ + src/syscall/asm_linux_amd64.s | 24 +++++-- + 6 files changed, 150 insertions(+), 84 deletions(-) + create mode 100644 src/runtime/sys_linux_amd64.go + +diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go +index d768054198..0d7166397d 100644 +--- a/src/runtime/malloc.go ++++ b/src/runtime/malloc.go +@@ -610,43 +610,45 @@ func (h *mheap) sysAlloc(n uintptr) (v unsafe.Pointer, size uintptr) { + goto mapped + } + +- // Try to grow the heap at a hint address. +- for h.arenaHints != nil { +- hint := h.arenaHints +- p := hint.addr +- if hint.down { +- p -= n +- } +- if p+n < p { +- // We can't use this, so don't ask. +- v = nil +- } else if arenaIndex(p+n-1) >= 1<= 1<procid to Linux tid + MOVL $SYS_gettid, AX +- SYSCALL ++ SYSCALL_ENHANCE + MOVQ AX, m_procid(R8) + + // Set FS to point at m->tls. +@@ -589,14 +624,14 @@ nog: + // It shouldn't return. If it does, exit that thread. + MOVL $111, DI + MOVL $SYS_exit, AX +- SYSCALL ++ SYSCALL_ENHANCE + JMP -3(PC) // keep exiting + + TEXT runtime·sigaltstack(SB),NOSPLIT,$-8 + MOVQ new+0(FP), DI + MOVQ old+8(FP), SI + MOVQ $SYS_sigaltstack, AX +- SYSCALL ++ SYSCALL_ENHANCE + CMPQ AX, $0xfffffffffffff001 + JLS 2(PC) + MOVL $0xf1, 0xf1 // crash +@@ -613,7 +648,7 @@ TEXT runtime·settls(SB),NOSPLIT,$32 + MOVQ DI, SI + MOVQ $0x1002, DI // ARCH_SET_FS + MOVQ $SYS_arch_prctl, AX +- SYSCALL ++ SYSCALL_ENHANCE + CMPQ AX, $0xfffffffffffff001 + JLS 2(PC) + MOVL $0xf1, 0xf1 // crash +@@ -621,7 +656,7 @@ TEXT runtime·settls(SB),NOSPLIT,$32 + + TEXT runtime·osyield(SB),NOSPLIT,$0 + MOVL $SYS_sched_yield, AX +- SYSCALL ++ SYSCALL_ENHANCE + RET + + TEXT runtime·sched_getaffinity(SB),NOSPLIT,$0 +@@ -629,7 +664,7 @@ TEXT runtime·sched_getaffinity(SB),NOSPLIT,$0 + MOVQ len+8(FP), SI + MOVQ buf+16(FP), DX + MOVL $SYS_sched_getaffinity, AX +- SYSCALL ++ SYSCALL_ENHANCE + MOVL AX, ret+24(FP) + RET + +@@ -637,7 +672,7 @@ TEXT runtime·sched_getaffinity(SB),NOSPLIT,$0 + TEXT runtime·epollcreate(SB),NOSPLIT,$0 + MOVL size+0(FP), DI + MOVL $SYS_epoll_create, AX +- SYSCALL ++ SYSCALL_ENHANCE + MOVL AX, ret+8(FP) + RET + +@@ -645,7 +680,7 @@ TEXT runtime·epollcreate(SB),NOSPLIT,$0 + TEXT runtime·epollcreate1(SB),NOSPLIT,$0 + MOVL flags+0(FP), DI + MOVL $SYS_epoll_create1, AX +- SYSCALL ++ SYSCALL_ENHANCE + MOVL AX, ret+8(FP) + RET + +@@ -656,7 +691,7 @@ TEXT runtime·epollctl(SB),NOSPLIT,$0 + MOVL fd+8(FP), DX + MOVQ ev+16(FP), R10 + MOVL $SYS_epoll_ctl, AX +- SYSCALL ++ SYSCALL_ENHANCE + MOVL AX, ret+24(FP) + RET + +@@ -669,7 +704,7 @@ TEXT runtime·epollwait(SB),NOSPLIT,$0 + MOVL timeout+20(FP), R10 + MOVQ $0, R8 + MOVL $SYS_epoll_pwait, AX +- SYSCALL ++ SYSCALL_ENHANCE + MOVL AX, ret+24(FP) + RET + +@@ -679,10 +714,9 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$0 + MOVQ $2, SI // F_SETFD + MOVQ $1, DX // FD_CLOEXEC + MOVL $SYS_fcntl, AX +- SYSCALL ++ SYSCALL_ENHANCE + RET + +- + // int access(const char *name, int mode) + TEXT runtime·access(SB),NOSPLIT,$0 + // This uses faccessat instead of access, because Android O blocks access. +@@ -691,7 +725,7 @@ TEXT runtime·access(SB),NOSPLIT,$0 + MOVL mode+8(FP), DX + MOVL $0, R10 + MOVL $SYS_faccessat, AX +- SYSCALL ++ SYSCALL_ENHANCE + MOVL AX, ret+16(FP) + RET + +@@ -701,7 +735,7 @@ TEXT runtime·connect(SB),NOSPLIT,$0-28 + MOVQ addr+8(FP), SI + MOVL len+16(FP), DX + MOVL $SYS_connect, AX +- SYSCALL ++ SYSCALL_ENHANCE + MOVL AX, ret+24(FP) + RET + +@@ -711,7 +745,7 @@ TEXT runtime·socket(SB),NOSPLIT,$0-20 + MOVL typ+4(FP), SI + MOVL prot+8(FP), DX + MOVL $SYS_socket, AX +- SYSCALL ++ SYSCALL_ENHANCE + MOVL AX, ret+16(FP) + RET + +@@ -720,6 +754,6 @@ TEXT runtime·sbrk0(SB),NOSPLIT,$0-8 + // Implemented as brk(NULL). + MOVQ $0, DI + MOVL $SYS_brk, AX +- SYSCALL ++ SYSCALL_ENHANCE + MOVQ AX, ret+0(FP) + RET +diff --git a/src/runtime/textflag.h b/src/runtime/textflag.h +index daca36d948..824f069076 100644 +--- a/src/runtime/textflag.h ++++ b/src/runtime/textflag.h +@@ -35,3 +35,14 @@ + // Function is the top of the call stack. Call stack unwinders should stop + // at this function. + #define TOPFRAME 2048 ++ ++#define SYSCALL_ENHANCE \ ++ CMPQ runtime·occlumentry(SB), $0x0 \ ++ JBE 4(PC) \ ++ CALL *runtime·occlumentry(SB) \ ++ CMPQ runtime·occlumentry(SB), $0x0 \ ++ JNE 2(PC) \ ++ SYSCALL ++ ++#define OCCLUM_GET_TIME_OF_DAY \ ++ CALL *runtime·occlumentry(SB) +diff --git a/src/syscall/asm_linux_amd64.s b/src/syscall/asm_linux_amd64.s +index 364815df18..4417768e8a 100644 +--- a/src/syscall/asm_linux_amd64.s ++++ b/src/syscall/asm_linux_amd64.s +@@ -5,6 +5,8 @@ + #include "textflag.h" + #include "funcdata.h" + ++#define SYS_gettimeofday 96 ++ + // + // System calls for AMD64, Linux + // +@@ -23,7 +25,7 @@ TEXT ·Syscall(SB),NOSPLIT,$0-56 + MOVQ $0, R8 + MOVQ $0, R9 + MOVQ trap+0(FP), AX // syscall entry +- SYSCALL ++ SYSCALL_ENHANCE + CMPQ AX, $0xfffffffffffff001 + JLS ok + MOVQ $-1, r1+32(FP) +@@ -49,7 +51,7 @@ TEXT ·Syscall6(SB),NOSPLIT,$0-80 + MOVQ a5+40(FP), R8 + MOVQ a6+48(FP), R9 + MOVQ trap+0(FP), AX // syscall entry +- SYSCALL ++ SYSCALL_ENHANCE + CMPQ AX, $0xfffffffffffff001 + JLS ok6 + MOVQ $-1, r1+56(FP) +@@ -74,7 +76,7 @@ TEXT ·RawSyscall(SB),NOSPLIT,$0-56 + MOVQ $0, R8 + MOVQ $0, R9 + MOVQ trap+0(FP), AX // syscall entry +- SYSCALL ++ SYSCALL_ENHANCE + CMPQ AX, $0xfffffffffffff001 + JLS ok1 + MOVQ $-1, r1+32(FP) +@@ -97,7 +99,7 @@ TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 + MOVQ a5+40(FP), R8 + MOVQ a6+48(FP), R9 + MOVQ trap+0(FP), AX // syscall entry +- SYSCALL ++ SYSCALL_ENHANCE + CMPQ AX, $0xfffffffffffff001 + JLS ok2 + MOVQ $-1, r1+56(FP) +@@ -121,7 +123,7 @@ TEXT ·rawVforkSyscall(SB),NOSPLIT,$0-32 + MOVQ $0, R9 + MOVQ trap+0(FP), AX // syscall entry + POPQ R12 // preserve return address +- SYSCALL ++ SYSCALL_ENHANCE + PUSHQ R12 + CMPQ AX, $0xfffffffffffff001 + JLS ok2 +@@ -143,18 +145,28 @@ TEXT ·rawSyscallNoError(SB),NOSPLIT,$0-48 + MOVQ $0, R8 + MOVQ $0, R9 + MOVQ trap+0(FP), AX // syscall entry +- SYSCALL ++ SYSCALL_ENHANCE + MOVQ AX, r1+32(FP) + MOVQ DX, r2+40(FP) + RET + + // func gettimeofday(tv *Timeval) (err uintptr) + TEXT ·gettimeofday(SB),NOSPLIT,$0-16 ++ CMPQ runtime·occlumentry(SB), $0x0 ++ JBE start ++ MOVQ tv+0(FP), DI ++ MOVQ $0, SI ++ MOVQ $SYS_gettimeofday, AX ++ OCCLUM_GET_TIME_OF_DAY ++ JMP result ++ ++start: + MOVQ tv+0(FP), DI + MOVQ $0, SI + MOVQ runtime·vdsoGettimeofdaySym(SB), AX + CALL AX + ++result: + CMPQ AX, $0xfffffffffffff001 + JLS ok7 + NEGQ AX +-- +2.19.1.3.ge56e4f7 + diff --git a/tools/toolchains/golang/build.sh b/tools/toolchains/golang/build.sh new file mode 100755 index 00000000..33807748 --- /dev/null +++ b/tools/toolchains/golang/build.sh @@ -0,0 +1,39 @@ +#!/bin/bash +THIS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" +BUILD_DIR=/tmp/occlum_golang_toolchain +INSTALL_DIR=/opt/occlum/toolchains/golang + +# Exit if any command fails +set -e + +# Clean previous build and installation if any +rm -rf ${BUILD_DIR} +rm -rf ${INSTALL_DIR} + +# Create the build directory +mkdir -p ${BUILD_DIR} +cd ${BUILD_DIR} + +# Download Golang +git clone https://github.com/golang/go . +# Swtich to Golang 1.13.4 +git checkout -b go1.13.4 tags/go1.13.4 +# Apply the patch to adapt Golang to Occlum +git apply ${THIS_DIR}/0001-adapt-golang-to-occlum-libos.patch + +# Build Golang +cd src +./make.bash +mv ${BUILD_DIR} ${INSTALL_DIR} + +# Generate the wrappers for Go +cat > ${INSTALL_DIR}/bin/occlum-go <