occlum/tools/occlum
2021-01-08 13:23:36 +08:00

497 lines
15 KiB
Bash
Executable File

#!/bin/bash
this_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
occlum_dir="$( cd "$( dirname "$this_dir/../../../" )" >/dev/null 2>&1 && pwd )"
build_makefile=$occlum_dir/build/bin/occlum_build.mk
if [[ "$occlum_dir" == "/opt/occlum" ]]; then
version_header=$occlum_dir/include/occlum_version.h
occlum_sgx_env=$occlum_dir/sgxsdk-tools/environment
else
version_header=$occlum_dir/src/pal/include/occlum_version.h
occlum_sgx_env=$occlum_dir/etc/environment
fi
# For deployment environment, version header file may not exist
if [ -f "$version_header" ]; then
major_ver=`grep '\#define OCCLUM_MAJOR_VERSION' $version_header | awk '{print $3}'`
minor_ver=`grep '\#define OCCLUM_MINOR_VERSION' $version_header | awk '{print $3}'`
patch_ver=`grep '\#define OCCLUM_PATCH_VERSION' $version_header | awk '{print $3}'`
occlum_version="$major_ver.$minor_ver.$patch_ver"
fi
instance_dir=`pwd`
status_file=$instance_dir/.__occlum_status
# For deployment environment, env for sgx-sdk may not exist
if [ -f "$occlum_sgx_env" ]; then
source $occlum_sgx_env
SGX_GDB="$SGX_SDK/bin/sgx-gdb"
ENCLAVE_SIGN_TOOL="$SGX_SDK/bin/x64/sgx_sign"
ENCLAVE_SIGN_KEY="$occlum_dir/etc/template/Enclave.pem"
fi
get_enclave_debuggable_flag() {
jq '.metadata.debuggable' $instance_dir/Occlum.json
}
exit_error() {
echo "Error: $@" >&2
exit 1
}
report_arg_error() {
echo $1 >&2
echo ""
cat <<EOF
Usage:
occlum new <path>
Create a new directory at <path> and initialize as the Occlum instance.
occlum init
Initialize a directory as the Occlum instance.
occlum build [--sign-key <key_path>] [--sign-tool <tool_path>] [-f/--force]
Build and sign an Occlum SGX enclave (.so) and generate its associated secure
FS image according to the user-provided image directory and Occlum.json config file.
The whole building process is incremental: the building artifacts are built only
when needed.
To force rebuilding all artifacts, give the [-f/--force] flag.
occlum run <program_name> <program_args>
Run the user program inside an SGX enclave.
occlum package [<package_name>.tar.gz]
Generate a minimal, self-contained package (.tar.gz) for the Occlum instance.
The resulting package can then be copied to a deployment environment and unpacked
as a runnable Occlum instance.
All runtime dependencies required by the Occlum instance---except Intel SGX driver,
enable_rdfsbase kernel module, and Intel SGX PSW---are included in the package.
If package_name is not specified, the directory name of Occlum instance will be used.
occlum gdb <program_name> <program_args>
Debug the program running inside an SGX enclave with GDB.
occlum mount [--sign-key <key_path>] [--sign-tool <tool_path>] <path>
Mount the secure FS image of the Occlum instance as a Linux FS at an existing <path>.
This makes it easy to access and manipulate Occlum's secure FS for debug purpose.
EOF
}
check_has_init() {
if [ ! -f "$status_file" ]; then
echo "Error: the current working directory is not initialized as an Occlum instance. Need to run \"occlum init\" first."
exit 1
fi
}
check_has_built() {
check_has_init
if [ ! -d "$instance_dir/run/mount/__ROOT" ]; then
echo "Error: the Occlum image and enclave are not built yet. Need to run \"occlum build\" first."
exit 1
fi
}
check_has_run() {
if pgrep --full "$instance_dir/build/bin/occlum-run" > /dev/null ; then
echo "Error: the process of current Occlum instance is running. Need to wait for the process to finish or kill it first."
exit 1
fi
}
check_aesm_service() {
for i in $(seq 1 3); do
pgrep "aesm_service" > /dev/null && return || sleep 5
done
echo "Error: AESM service is not started yet. Need to start it first"
exit 1
}
cmd_new() {
if [ -z $@ ]; then
echo "Error: target directory is not set"
exit 1
fi
dir_path="$@"
if [[ "$dir_path" != "/"* ]]; then
dir_path="$instance_dir/$@"
fi
if [[ -e "$dir_path" ]]; then
echo "Error: destination \"$dir_path\" already exists"
exit 1
fi
mkdir -p $dir_path
instance_dir=$dir_path
status_file=$instance_dir/.__occlum_status
cd $dir_path && cmd_init
}
cmd_init() {
if [ -f "$status_file" ]; then
echo "Error: the current working directory has been initialized as an Occlum instance"
exit 1
fi
echo "initialized" > $status_file
cd "$instance_dir"
mkdir -p image
mkdir -p image/bin
mkdir -p image/lib
mkdir -p image/lib64
mkdir -p image/root
mkdir -p image/host
mkdir -p image/tmp
local occlum_glibc_lib=/opt/occlum/glibc/lib
local cpu_lib=/sys/devices/system/cpu
if [ -d "$occlum_glibc_lib" ]; then
mkdir -p "image/$occlum_glibc_lib"
mkdir -p "image/$cpu_lib"
fi
# add default /etc/hosts
mkdir -p image/etc
echo "127.0.0.1 localhost" > image/etc/hosts
# add musl
local occlum_musl_lib=/usr/local/occlum/x86_64-linux-musl/lib
cp -t image/lib \
/lib/ld-musl-x86_64.so.1 \
"$occlum_musl_lib/libc.so" \
"$occlum_musl_lib/libstdc++.so.6" \
"$occlum_musl_lib/libgcc_s.so.1" \
"$occlum_musl_lib/libgomp.so.1"
# add glibc
if [ -d "$occlum_glibc_lib" ]; then
cp -t image/lib64 \
"$occlum_glibc_lib/ld-linux-x86-64.so.2"
ln -sf /lib64/ld-linux-x86-64.so.2 "image/$occlum_glibc_lib/ld-linux-x86-64.so.2"
cp -t "image/$occlum_glibc_lib" \
"$occlum_glibc_lib/libc.so.6" \
"$occlum_glibc_lib/libpthread.so.0" \
"$occlum_glibc_lib/libm.so.6"
local os_release=`awk -F= '/^NAME/{print $2}' /etc/os-release`
if [ "$os_release" == "\"Ubuntu\"" ]; then
cp -t "image/$occlum_glibc_lib" \
"/usr/lib/x86_64-linux-gnu/libstdc++.so.6" \
"/lib/x86_64-linux-gnu/libgcc_s.so.1"
else
cp -t "image/$occlum_glibc_lib" \
"/usr/lib64/libstdc++.so.6" \
"/usr/lib64/libgcc_s.so.1"
fi
cp -t "image/$cpu_lib" \
"$cpu_lib/online"
fi
cp "$occlum_dir"/etc/template/Occlum.json "$instance_dir"/
chmod 644 "$instance_dir"/Occlum.json
echo "$instance_dir initialized as an Occlum instance"
}
cmd_build() {
check_has_init
pal_lib=libocclum-pal.so
libos_lib=libocclum-libos.so
while [ -n "$1" ]; do
case "$1" in
--sign-key) [ -n "$2" ] && ENCLAVE_SIGN_KEY=$2 ; shift 2 || exit_error "empty signing key path" ;;
--sign-tool) [ -n "$2" ] && ENCLAVE_SIGN_TOOL=$2 ; shift 2 || exit_error "empty signing tool path" ;;
--sgx-mode) [[ -n "$2" && "$2" != "HW" ]] && export SGX_MODE=SIM ; shift 2 || exit_error "empty sgx mode";;
--force | -f) MAKE_OPTION="--always-make" ; shift ;;
*) exit_error "Unknown option: $1" ;;
esac
done
[ -e "$ENCLAVE_SIGN_KEY" ] || exit_error "invalid signing key path: $ENCLAVE_SIGN_KEY"
[ -e "$ENCLAVE_SIGN_TOOL" ] || exit_error "invalid signing tool path: $ENCLAVE_SIGN_TOOL"
echo "Enclave sign-tool: $ENCLAVE_SIGN_TOOL"
echo "Enclave sign-key: $ENCLAVE_SIGN_KEY"
if [[ -n $SGX_MODE && "$SGX_MODE" != "HW" ]]; then
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$SGX_SDK/sdk_libs
pal_lib=libocclum-pal_sim.so
libos_lib=libocclum-libos_sim.so
echo "SGX mode: $SGX_MODE"
else
echo "SGX mode: HW"
fi
# If sgx mode is changed, build thoroughly again
if [[ -n $SGX_MODE && "$SGX_MODE" != "HW" ]]; then
if [ "$(cat $instance_dir/.sgx_mode 2>/dev/null)" != "SIM" ]; then
MAKE_OPTION="--always-make"
fi
else
#HW mode
if [ "$(cat $instance_dir/.sgx_mode 2>/dev/null)" != "HW" ]; then
MAKE_OPTION="--always-make"
fi
fi
rm -rf "$instance_dir/run"
occlum_dir=$occlum_dir instance_dir=$instance_dir pal_lib=$pal_lib major_ver=$major_ver \
occlum_version=$occlum_version libos_lib=$libos_lib \
ENCLAVE_SIGN_KEY=$ENCLAVE_SIGN_KEY ENCLAVE_SIGN_TOOL=$ENCLAVE_SIGN_TOOL \
make -f $build_makefile $MAKE_OPTION
cd "$instance_dir"
echo "built" > $status_file
if [[ -n $SGX_MODE && "$SGX_MODE" != "HW" ]]; then
echo "SIM" > .sgx_mode
else
echo "HW" > .sgx_mode
fi
mkdir -p "$instance_dir/run/mount/__ROOT"
mkdir -p "$instance_dir/run/mount/tmp"
echo "Built the Occlum image and enclave successfully"
}
cmd_run() {
check_has_built
check_has_run
check_aesm_service
SGX_MODE=$(cat $instance_dir/.sgx_mode)
if [[ -n $SGX_MODE && "$SGX_MODE" != "HW" ]]; then
export LD_LIBRARY_PATH="$instance_dir/build/lib:$SGX_SDK/sdk_libs/"
else
export LD_LIBRARY_PATH="$instance_dir/build/lib"
fi
echo "running" > $status_file
if [ "`get_enclave_debuggable_flag`" == "false" ]; then
export OCCLUM_RELEASE_ENCLAVE=1
fi
RUST_BACKTRACE=1 "$instance_dir/build/bin/occlum-run" "$@"
echo "built" > $status_file
}
cmd_start() {
check_has_built
check_aesm_service
SGX_MODE=$(cat $instance_dir/.sgx_mode)
if [[ -n $SGX_MODE && "$SGX_MODE" != "HW" ]]; then
export LD_LIBRARY_PATH="$instance_dir/build/lib:$SGX_SDK/sdk_libs/"
else
export LD_LIBRARY_PATH="$instance_dir/build/lib"
fi
echo "running" > $status_file
if [ "`get_enclave_debuggable_flag`" == "false" ]; then
export OCCLUM_RELEASE_ENCLAVE=1
fi
RUST_BACKTRACE=1 "$instance_dir/build/bin/occlum_exec_client" start
echo "built" > $status_file
}
cmd_exec() {
check_has_built
SGX_MODE=$(cat $instance_dir/.sgx_mode)
if [[ -n $SGX_MODE && "$SGX_MODE" != "HW" ]]; then
export LD_LIBRARY_PATH="$instance_dir/build/lib:$SGX_SDK/sdk_libs/"
else
export LD_LIBRARY_PATH="$instance_dir/build/lib"
fi
echo "running" > "$status_file"
RUST_BACKTRACE=1 "$instance_dir/build/bin/occlum_exec_client" exec -- "$@"
echo "built" > "$status_file"
}
cmd_stop() {
check_has_built
SGX_MODE=$(cat $instance_dir/.sgx_mode)
if [[ -n $SGX_MODE && "$SGX_MODE" != "HW" ]]; then
export LD_LIBRARY_PATH="$instance_dir/build/lib:$SGX_SDK/sdk_libs/"
else
export LD_LIBRARY_PATH="$instance_dir/build/lib"
fi
echo "running" > "$status_file"
RUST_BACKTRACE=1 "$instance_dir/build/bin/occlum_exec_client" stop -t 0
echo "built" > "$status_file"
}
cmd_package() {
check_has_built
SGX_MODE=$(cat $instance_dir/.sgx_mode)
if [[ -n $SGX_MODE && "$SGX_MODE" != "HW" ]]; then
echo '"occlum package" command should only be used for an Occlum instance of SGX hardware mode, not the simulation mode.'
echo 'Please run "occlum build --sgx-mode HW" and then use "occlum package"'
exit 1
fi
instance_base_name=$(basename $instance_dir)
if [[ -z "$@" ]]; then
package_name="$instance_base_name.tar.gz"
else
if [[ "$@" == *.tar.gz ]];then
package_name="$@"
else
package_name="$@.tar.gz"
fi
fi
rm -f $package_name
cd .. && tar -cvzf $instance_dir/$package_name $instance_base_name/Occlum.json $instance_base_name/build/bin \
$instance_base_name/build/lib/libocclum-libos.signed.so $instance_base_name/build/lib/libocclum-pal.so* \
$instance_base_name/build/mount $instance_base_name/build/Occlum.json.protected $instance_base_name/run \
$instance_base_name/.__occlum_status $instance_base_name/.sgx_mode
if [ "`get_enclave_debuggable_flag`" == "true" ]; then
echo 'Warning: current Occlum instance is configured as "debuggable".'
echo '(If it is not expected, you can modify the Occlum.json "metadata" - "debuggable" field to "false" and build again. And then use "occlum package")'
fi
echo "The package $package_name is generated successfully"
}
cmd_gdb() {
check_has_built
SGX_MODE=$(cat $instance_dir/.sgx_mode)
if [[ -n $SGX_MODE && "$SGX_MODE" != "HW" ]]; then
export LD_LIBRARY_PATH="$instance_dir/build/lib:$SGX_SDK/sdk_libs/"
else
export LD_LIBRARY_PATH="$instance_dir/build/lib"
fi
echo "debugging" > "$status_file"
OCCLUM_GDB=1 $SGX_GDB --args "$instance_dir/build/bin/occlum-run" "$@"
echo "built" > "$status_file"
}
cmd_mount() {
check_has_built
while [ -n "$1" ]; do
case "$1" in
--sign-key) [ -n "$2" ] && ENCLAVE_SIGN_KEY=$2 ; shift 2 || exit_error "empty signing key path" ;;
--sign-tool) [ -n "$2" ] && ENCLAVE_SIGN_TOOL=$2 ; shift 2 || exit_error "empty signing tool path" ;;
*) MNT_POINT=$1 ; shift ;;
esac
done
[ -e "$ENCLAVE_SIGN_KEY" ] || exit_error "invalid signing key path: $ENCLAVE_SIGN_KEY"
[ -e "$ENCLAVE_SIGN_TOOL" ] || exit_error "invalid signing tool path: $ENCLAVE_SIGN_TOOL"
[ -d "$MNT_POINT" ] || exit_error "invalid mount point: $MNT_POINT"
echo "Mount tool sign-tool: $ENCLAVE_SIGN_TOOL"
echo "Mount tool sign-key: $ENCLAVE_SIGN_KEY"
echo "Mount point: $MNT_POINT"
SGX_MODE=$(cat $instance_dir/.sgx_mode)
if [[ -n $SGX_MODE && "$SGX_MODE" != "HW" ]]; then
sefs_cli="$occlum_dir/build/bin/sefs-cli_sim"
sefs_cli_lib="$occlum_dir/build/lib/libsefs-cli_sim.so"
echo "SGX mode: $SGX_MODE"
else
sefs_cli="$occlum_dir/build/bin/sefs-cli"
sefs_cli_lib="$occlum_dir/build/lib/libsefs-cli.so"
echo "SGX mode: HW"
fi
signed_sefs_cli_lib="$instance_dir/build/lib/libsefs-cli.signed.so"
echo "Signing the mount tool..."
"$ENCLAVE_SIGN_TOOL" sign \
-key "$ENCLAVE_SIGN_KEY" \
-config "$occlum_dir/build/sefs-cli.Enclave.xml" \
-enclave "$sefs_cli_lib" \
-out "$signed_sefs_cli_lib"
image_fs="$instance_dir/build/mount/__ROOT"
if [ -e "$instance_dir/run/mount/__ROOT/metadata" ]; then
container_fs="$instance_dir/run/mount/__ROOT"
else
container_fs=""
fi
echo "Start to mount the FS..."
LD_LIBRARY_PATH="$SGX_SDK/sdk_libs" "$sefs_cli" \
--enclave "$signed_sefs_cli_lib" \
mount \
"$image_fs" \
"$container_fs" \
"$MNT_POINT"
# After mounting the FS, remove the signed mount tool
rm -f "$signed_sefs_cli_lib"
}
cmd_status() {
cat "$status_file"
}
set -e
if [[ ( "$#" < 1 ) ]] ; then
report_arg_error "Error: no sub-command is given"
exit 1
fi
cmd=$1
case "$cmd" in
new)
cmd_new "${@:2:1}"
;;
init)
cmd_init
;;
build)
cmd_build "${@:2}"
;;
run)
cmd_run "${@:2}"
;;
start)
cmd_start
;;
exec)
cmd_exec "${@:2}"
;;
stop)
cmd_stop
;;
package)
cmd_package "${@:2}"
;;
gdb)
cmd_gdb "${@:2}"
;;
mount)
cmd_mount "${@:2}"
;;
status)
cmd_status
;;
*)
report_arg_error "Error: unknown sub-command $cmd"
exit 1
esac