occlum/tools/occlum
Zheng, Qi 7db9d9b955 Add SGX KSS support
Signed-off-by: Zheng, Qi <huaiqing.zq@antgroup.com>
2021-12-06 15:46:34 +08:00

627 lines
20 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
}
get_enclave_enable_kss_flag() {
jq '.metadata.enable_kss' $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>] [--image-key <key_path>] [--buildin-image-key] [-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.
In default only HW release mode package is supported. Debug or simulation mode package
could be supported by adding "--debug" flag.
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>] [--image-key <key_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.
occlum gen-image-key <key_path>
Generate a file consists of a randomly generated 128-bit key for encryption of the FS image.
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() {
# Ignore AESM service status for simulation mode
if [ "$(cat $instance_dir/.sgx_mode 2>/dev/null)" != "HW" ]; then
return
fi
AESM_SOCKET_FILE=/var/run/aesmd/aesm.socket
for i in $(seq 1 3); do
if [ -S "$AESM_SOCKET_FILE" ]; then
return
else
sleep 5
fi
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
mkdir -p image/dev
mkdir -p image/proc
mkdir -p image/etc
local occlum_glibc_lib=/opt/occlum/glibc/lib
local occlum_glibc_etc=/opt/occlum/glibc/etc
if [ -d "$occlum_glibc_lib" ]; then
mkdir -p "image/$occlum_glibc_lib"
mkdir -p "image/$occlum_glibc_etc"
fi
# add default /etc/hosts
echo "127.0.0.1 localhost" > image/etc/hosts
# add default timezone file
cp /etc/localtime image/etc/
# 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/$occlum_glibc_etc" \
/etc/localtime
fi
mkdir -p initfs
mkdir -p initfs/bin
mkdir -p initfs/lib
mkdir -p initfs/dev
mkdir -p initfs/proc
mkdir -p initfs/etc
# add default /etc/hosts
echo "127.0.0.1 localhost" > initfs/etc/hosts
# add default timezone file
cp /etc/localtime initfs/etc/
# add musl
local occlum_musl_lib=/usr/local/occlum/x86_64-linux-musl/lib
cp -t initfs/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"
cp "$occlum_dir"/build/bin/init initfs/bin/
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
BUILDIN_IMAGE_KEY=false
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";;
--image-key) [ -n "$2" ] && SECURE_IMAGE_KEY=$2 ; shift 2 || exit_error "empty secure image key path" ;;
--buildin-image-key) BUILDIN_IMAGE_KEY=true ; shift ;;
--force | -f) MAKE_OPTION="clean" ; 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"
if [ -n "$SECURE_IMAGE_KEY" ]; then
[ -e "$SECURE_IMAGE_KEY" ] || exit_error "invalid secure image key path: $SECURE_IMAGE_KEY"
fi
echo "Enclave sign-tool: $ENCLAVE_SIGN_TOOL"
echo "Enclave sign-key: $ENCLAVE_SIGN_KEY"
[ -n "$SECURE_IMAGE_KEY" ] && echo "Image encryption key: $SECURE_IMAGE_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="clean"
fi
else
#HW mode
if [ "$(cat $instance_dir/.sgx_mode 2>/dev/null)" != "HW" ]; then
MAKE_OPTION="clean"
fi
fi
rm -rf "$instance_dir/run"
if [[ -n $MAKE_OPTION ]]; then
occlum_dir=$occlum_dir instance_dir=$instance_dir \
make -f $build_makefile $MAKE_OPTION
fi
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 \
SECURE_IMAGE_KEY=$SECURE_IMAGE_KEY BUILDIN_IMAGE_KEY=$BUILDIN_IMAGE_KEY \
make -f $build_makefile --no-builtin-rules
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/initfs/__ROOT"
echo "Built the Occlum image and enclave successfully"
}
cmd_run() {
check_has_built
check_has_run
check_aesm_service
loop=true
while [ -n "$1" ] && [ "$loop" = "true" ]; do
case "$1" in
--config-id) [ -n "$2" ] && export OCCLUM_CONF_ID_BASE64=$2 ; shift 2 || exit_error "Empty Base64 Encoded Occlum Config ID provided" ;;
--config-svn) [ -n "$2" ] && export OCCLUM_CONF_SVN=$2 ; shift 2 || exit_error "Empty Occlum Config SVN provided" ;;
*) loop=false ;;
esac
done
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
if [ "`get_enclave_enable_kss_flag`" == "true" ]; then
export OCCLUM_ENABLE_KSS=1
fi
RUST_BACKTRACE=1 "$instance_dir/build/bin/occlum-run" "$@"
echo "built" > $status_file
}
cmd_start() {
check_has_built
check_aesm_service
loop=true
while [ -n "$1" ] && [ "$loop" = "true" ]; do
case "$1" in
--config-id) [ -n "$2" ] && export OCCLUM_CONF_ID_BASE64=$2 ; shift 2 || exit_error "Empty Base64 Encoded Occlum Config ID provided" ;;
--config-svn) [ -n "$2" ] && export OCCLUM_CONF_SVN=$2 ; shift 2 || exit_error "Empty Occlum Config SVN provided" ;;
*) loop=false ;;
esac
done
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
if [ "`get_enclave_enable_kss_flag`" == "true" ]; then
export OCCLUM_ENABLE_KSS=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
debug="false"
instance_base_name=$(basename $instance_dir)
package_name="$instance_base_name.tar.gz"
while [ -n "$1" ]; do
case "$1" in
--debug) debug="true" ; shift ;;
*) package_name=$1 ; shift ;;
esac
done
if [[ "$package_name" != *.tar.gz ]]; then
package_name="$package_name.tar.gz"
fi
if [[ "`get_enclave_debuggable_flag`" == "true" && "$debug" != "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")'
echo 'Or, use "occlum package --debug" to support debug mode package'
exit 1
fi
SGX_MODE=$(cat $instance_dir/.sgx_mode)
if [[ -n $SGX_MODE && "$SGX_MODE" != "HW" && "$debug" != "true" ]]; 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"'
echo 'Or, use "occlum package --debug" to support similation mode package'
exit 1
fi
rm -f $package_name
pkg_files="\
$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/build/initfs $instance_base_name/build/.Occlum_sys.json.protected \
$instance_base_name/initfs $instance_base_name/run \
$instance_base_name/.__occlum_status $instance_base_name/.sgx_mode \
"
if [[ "$debug" == "true" && "$SGX_MODE" != "HW" ]]; then
sim_files="\
$instance_base_name/build/lib/libocclum-libos_sim.so* \
$instance_base_name/build/lib/libocclum-pal_sim.so* \
"
fi
cd .. && tar -cvzf $instance_dir/$package_name \
--transform s/$instance_base_name/$(basename $package_name .tar.gz)/ \
$pkg_files $sim_files
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" ;;
--image-key) [ -n "$2" ] && SECURE_IMAGE_KEY=$2 ; shift 2 || exit_error "empty secure image key 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"
if [ -n "$SECURE_IMAGE_KEY" ]; then
[ -e "$SECURE_IMAGE_KEY" ] || exit_error "invalid secure image key path: $SECURE_IMAGE_KEY"
fi
[ -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"
[ -n "$SECURE_IMAGE_KEY" ] && echo "Image decryption key: $SECURE_IMAGE_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
[ -n "$SECURE_IMAGE_KEY" ] && SECURE_IMAGE_KEY_OPTION="--key $SECURE_IMAGE_KEY"
echo "Start to mount the FS..."
LD_LIBRARY_PATH="$SGX_SDK/sdk_libs" "$sefs_cli" \
--enclave "$signed_sefs_cli_lib" \
mount \
$SECURE_IMAGE_KEY_OPTION \
"$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"
}
cmd_gen_image_key() {
if [ -z $@ ]; then
echo "Error: target file is not set"
exit 1
fi
key_path="$@"
if [[ "$key_path" != "/"* ]]; then
key_path="$instance_dir/$@"
fi
cat /dev/urandom | tr -dc 'a-f0-9' | fold -w 32 | head -n 1 | sed -r 's/.{2}/&-/g; s/.$//' > $key_path
}
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 "${@:2}"
;;
exec)
cmd_exec "${@:2}"
;;
stop)
cmd_stop
;;
package)
cmd_package "${@:2}"
;;
gdb)
cmd_gdb "${@:2}"
;;
mount)
cmd_mount "${@:2}"
;;
status)
cmd_status
;;
gen-image-key)
cmd_gen_image_key "${@:2:1}"
;;
*)
report_arg_error "Error: unknown sub-command $cmd"
exit 1
esac