From 4e11bb9f6dd8ebb3405d60894250c9294ecc6362 Mon Sep 17 00:00:00 2001 From: Kailun Qin Date: Wed, 20 Jul 2022 05:45:13 -0400 Subject: [PATCH] [tools/sgx,curl] Minimize and build libcurl statically Previously, we built `libsgx_util` as a shared library which was linked into RA-TLS, Secret Provisioning libraries and some other tools. This library relied on libcurl taken from the host platform. However, libcurl has a high number of dependencies itself, most of which are not required by Gramine, only consume space and are hard to track and reason about. This is especially pronounced for the RA-TLS/SecretProv libs because they typically run inside SGX enclaves and therefore should be minimal and reproducible. This patch: - builds `libsgx_util` into a static library, - builds and minimizes `libcurl` into a static library (leveraging `mbedtls` as the TLS backend), - links all dependencies of `tools/sgx` statically to avoid pulling in a lot of dependencies. Co-authored-by: Wojtek Porczyk Signed-off-by: Kailun Qin Signed-off-by: Wojtek Porczyk --- .ci/lib/stage-build-nosgx.jenkinsfile | 2 +- .ci/lib/stage-build-sgx.jenkinsfile | 2 +- .ci/ubuntu18.04.dockerfile | 1 - .ci/ubuntu20.04.dockerfile | 1 - CI-Examples/ra-tls-secret-prov/Makefile | 4 +- Documentation/devel/building.rst | 5 +- meson.build | 3 +- subprojects/.gitignore | 1 + subprojects/curl-7.84.0.wrap | 7 ++ .../packagefiles/curl-7.84.0/compile.sh | 89 +++++++++++++++++++ .../packagefiles/curl-7.84.0/meson.build | 23 +++++ .../packagefiles/mbedtls/compile-curl.sh | 24 +++++ subprojects/packagefiles/mbedtls/compile.sh | 3 +- subprojects/packagefiles/mbedtls/meson.build | 29 ++++++ tools/sgx/common/meson.build | 15 +--- 15 files changed, 183 insertions(+), 26 deletions(-) create mode 100644 subprojects/curl-7.84.0.wrap create mode 100644 subprojects/packagefiles/curl-7.84.0/compile.sh create mode 100644 subprojects/packagefiles/curl-7.84.0/meson.build create mode 100644 subprojects/packagefiles/mbedtls/compile-curl.sh diff --git a/.ci/lib/stage-build-nosgx.jenkinsfile b/.ci/lib/stage-build-nosgx.jenkinsfile index a6f99f6855..df00c99464 100644 --- a/.ci/lib/stage-build-nosgx.jenkinsfile +++ b/.ci/lib/stage-build-nosgx.jenkinsfile @@ -45,7 +45,7 @@ stage('build') { env.GRAMINE_PKGLIBDIR = libdir + '/gramine' // In CI we install to non-standard --prefix (see above). This makes sure the libraries are - // available anyway (e.g. gramine-sgx-pf-crypt needs libsgx_util.so). + // available anyway. env.PKG_CONFIG_PATH = libdir + '/pkgconfig' // prevent cheating and testing from repo diff --git a/.ci/lib/stage-build-sgx.jenkinsfile b/.ci/lib/stage-build-sgx.jenkinsfile index 01fb8ab159..ad16dd85cb 100644 --- a/.ci/lib/stage-build-sgx.jenkinsfile +++ b/.ci/lib/stage-build-sgx.jenkinsfile @@ -57,7 +57,7 @@ stage('build') { env.GRAMINE_PKGLIBDIR = libdir + '/gramine' // In CI we install to non-standard --prefix (see above). This makes sure the libraries are - // available anyway (e.g. gramine-sgx-pf-crypt needs libsgx_util.so). + // available anyway. env.PKG_CONFIG_PATH = libdir + '/pkgconfig' // prevent cheating and testing from repo diff --git a/.ci/ubuntu18.04.dockerfile b/.ci/ubuntu18.04.dockerfile index 4228edc3cd..ec287b831b 100644 --- a/.ci/ubuntu18.04.dockerfile +++ b/.ci/ubuntu18.04.dockerfile @@ -17,7 +17,6 @@ RUN apt-get update && env DEBIAN_FRONTEND=noninteractive apt-get install -y \ jq \ libapr1-dev \ libaprutil1-dev \ - libcurl4-openssl-dev \ libelf-dev \ libevent-dev \ libexpat1 \ diff --git a/.ci/ubuntu20.04.dockerfile b/.ci/ubuntu20.04.dockerfile index f1c99dd40c..fef644df87 100644 --- a/.ci/ubuntu20.04.dockerfile +++ b/.ci/ubuntu20.04.dockerfile @@ -18,7 +18,6 @@ RUN apt-get update && env DEBIAN_FRONTEND=noninteractive apt-get install -y \ libapr1-dev \ libaprutil1-dev \ libcjson-dev \ - libcurl4-openssl-dev \ libelf-dev \ libevent-dev \ libexpat1 \ diff --git a/CI-Examples/ra-tls-secret-prov/Makefile b/CI-Examples/ra-tls-secret-prov/Makefile index 8bd8a3f318..20176b6d22 100644 --- a/CI-Examples/ra-tls-secret-prov/Makefile +++ b/CI-Examples/ra-tls-secret-prov/Makefile @@ -49,12 +49,12 @@ ssl/server.crt: ssl/ca_config.conf ######################### CLIENT/SERVER EXECUTABLES ########################### # Use hard-coded GRAMINEDIR because we currently fail to provide secret prov headers in Gramine -# installation. We also use `sgx_util` pkg-config because we don't have a secret prov one. +# installation. We also use `mbedtls_gramine` pkg-config because we don't have a secret prov one. # TODO: Create a pkg-config file for secretprov_gramine libs, and use it in below # CFLAGS/LDFLAGS lines (via `pkg-config {--cflags|--libs} secretprov_gramine`). GRAMINEDIR ?= ../.. CFLAGS += -Wall -std=c11 -I$(GRAMINEDIR)/tools/sgx/ra-tls -LDFLAGS += -Wl,--enable-new-dtags $(shell pkg-config --libs sgx_util) +LDFLAGS += -Wl,--enable-new-dtags $(shell pkg-config --libs mbedtls_gramine) %/server_epid: %/server.c $(CC) $< $(CFLAGS) $(LDFLAGS) -lsecret_prov_verify_epid -pthread -o $@ diff --git a/Documentation/devel/building.rst b/Documentation/devel/building.rst index e89b5612ab..74dc07a2af 100644 --- a/Documentation/devel/building.rst +++ b/Documentation/devel/building.rst @@ -71,9 +71,8 @@ running, and Intel SGX SDK/PSW/DCAP must be installed. """""""""""""""""""" Run the following commands on Ubuntu to install SGX-related dependencies:: - sudo apt-get install -y libcurl4-openssl-dev \ - libprotobuf-c-dev protobuf-c-compiler protobuf-compiler \ - python3-cryptography python3-pip python3-protobuf + sudo apt-get install -y libprotobuf-c-dev protobuf-c-compiler \ + protobuf-compiler python3-cryptography python3-pip python3-protobuf 2. Install Linux kernel with patched FSGSBASE """"""""""""""""""""""""""""""""""""""""""""" diff --git a/meson.build b/meson.build index 6c2cbc5f28..7d6e93b75f 100644 --- a/meson.build +++ b/meson.build @@ -247,7 +247,8 @@ if sgx threads_dep = dependency('threads') - libcurl_dep = dependency('libcurl', version: '>=7.58.0') + curl_proj = subproject('curl-7.84.0') + libcurl_dep = curl_proj.get_variable('curl_minimal_dep') cjson_dep = dependency('cjson', required: false) if not cjson_dep.found() diff --git a/subprojects/.gitignore b/subprojects/.gitignore index aa91c2a96c..a2c9535aaa 100644 --- a/subprojects/.gitignore +++ b/subprojects/.gitignore @@ -1,6 +1,7 @@ /packagecache /cJSON-*/ +/curl-*/ /gcc-*/ /glibc-*/ /mbedtls-*/ diff --git a/subprojects/curl-7.84.0.wrap b/subprojects/curl-7.84.0.wrap new file mode 100644 index 0000000000..c7fcfe835f --- /dev/null +++ b/subprojects/curl-7.84.0.wrap @@ -0,0 +1,7 @@ +[wrap-file] +directory = curl-7.84.0 +source_url = https://github.com/curl/curl/releases/download/curl-7_84_0/curl-7.84.0.tar.gz +source_fallback_url = https://packages.gramineproject.io/distfiles/curl-7.84.0.tar.gz +source_filename = curl-7.84.0.tar.gz +source_hash = 3c6893d38d054d4e378267166858698899e9d87258e8ff1419d020c395384535 +patch_directory = curl-7.84.0 diff --git a/subprojects/packagefiles/curl-7.84.0/compile.sh b/subprojects/packagefiles/curl-7.84.0/compile.sh new file mode 100644 index 0000000000..23ed82fc24 --- /dev/null +++ b/subprojects/packagefiles/curl-7.84.0/compile.sh @@ -0,0 +1,89 @@ +#!/bin/sh + +set -e + +log() { + echo "curl: $*" +} + +CURRENT_SOURCE_DIR="$1" +CURRENT_BUILD_DIR="$2" +PRIVATE_DIR="$3" +SUBPROJ_ROOT="$4" +shift 4 + +BUILD_LOG=$(realpath "$CURRENT_BUILD_DIR/curl-build.log") +rm -f "$BUILD_LOG" + +log "see $BUILD_LOG for full build log" + +log "preparing sources..." + +rm -rf "$PRIVATE_DIR" +cp -ar "$CURRENT_SOURCE_DIR" "$PRIVATE_DIR" + +( + cd "$PRIVATE_DIR" + + log "running configure..." + # The list of configure options is selected based on: + # https://github.com/curl/curl/blob/curl-7_84_0/docs/INSTALL.md#reducing-size + ./configure \ + --disable-alt-svc \ + --disable-ares \ + --disable-cookies \ + --disable-crypto-auth \ + --disable-dateparse \ + --disable-dict \ + --disable-dnsshuffle \ + --disable-doh \ + --disable-file \ + --disable-ftp \ + --disable-get-easy-options \ + --disable-gopher \ + --disable-hsts \ + --disable-http-auth \ + --disable-imap \ + --disable-ldap \ + --disable-ldaps \ + --disable-libcurl-option \ + --disable-manual \ + --disable-mqtt \ + --disable-netrc \ + --disable-ntlm-wb \ + --disable-pop3 \ + --disable-progress-meter \ + --disable-proxy \ + --disable-pthreads \ + --disable-rtsp \ + --disable-shared \ + --disable-smb \ + --disable-smtp \ + --disable-socketpair \ + --disable-telnet \ + --disable-tftp \ + --disable-threaded-resolver \ + --disable-tls-srp \ + --disable-unix-sockets \ + --disable-verbose \ + --disable-versioned-symbols \ + --with-mbedtls="$SUBPROJ_ROOT"/mbedtls-curl \ + --without-brotli \ + --without-libidn2 \ + --without-libpsl \ + --without-librtmp \ + --without-nghttp2 \ + --without-ngtcp2 \ + --without-zlib \ + --without-zstd \ + >>"$BUILD_LOG" 2>&1 + + log "running make..." + + # The curl executable is not needed so we only build libcurl here. + cd lib; make -j"$(nproc)" >>"$BUILD_LOG" 2>&1 +) + +cp -r "$PRIVATE_DIR"/lib/.libs/* "$CURRENT_BUILD_DIR"/ + +log "done" diff --git a/subprojects/packagefiles/curl-7.84.0/meson.build b/subprojects/packagefiles/curl-7.84.0/meson.build new file mode 100644 index 0000000000..2435a406cb --- /dev/null +++ b/subprojects/packagefiles/curl-7.84.0/meson.build @@ -0,0 +1,23 @@ +project('curl', 'c', version: '7.84.0') + +curl_libs_output = [ + 'libcurl.a', +] + +curl = custom_target('curl', + command: [ + find_program('compile.sh'), + '@CURRENT_SOURCE_DIR@', + meson.current_build_dir(), + '@PRIVATE_DIR@', + join_paths(meson.build_root(), 'subprojects'), + ], + + depends: subproject('mbedtls-mbedtls-3.2.1').get_variable('mbedtls_curl_libs'), + output: curl_libs_output, +) + +curl_minimal_dep = declare_dependency( + link_with: curl, + include_directories: 'include', +) diff --git a/subprojects/packagefiles/mbedtls/compile-curl.sh b/subprojects/packagefiles/mbedtls/compile-curl.sh new file mode 100644 index 0000000000..0d7c080357 --- /dev/null +++ b/subprojects/packagefiles/mbedtls/compile-curl.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +set -ex + +CURRENT_SOURCE_DIR="$1" +VENDOR_SOURCE_DIR="$2" +CURRENT_BUILD_DIR="$3" +PRIVATE_DIR="$4" +SUBPROJ_ROOT="$5" +shift 5 + +rm -rf "$PRIVATE_DIR" + +cp -ar "$VENDOR_SOURCE_DIR" "$PRIVATE_DIR" +cp "$CURRENT_SOURCE_DIR"/include/mbedtls/*.h "$PRIVATE_DIR"/include/mbedtls/ +patch -p1 --directory "$PRIVATE_DIR" <"$CURRENT_SOURCE_DIR"/gramine.patch +patch -p1 --directory "$PRIVATE_DIR" <"$CURRENT_SOURCE_DIR"/fcntl.patch + +make -C "$PRIVATE_DIR" lib SUFFIX="''" install DESTDIR="$SUBPROJ_ROOT"/mbedtls-curl + +for output in $@ +do + cp -a "$PRIVATE_DIR"/library/"$(basename "$output")" "$output" +done diff --git a/subprojects/packagefiles/mbedtls/compile.sh b/subprojects/packagefiles/mbedtls/compile.sh index 152d088100..72fa845f2c 100755 --- a/subprojects/packagefiles/mbedtls/compile.sh +++ b/subprojects/packagefiles/mbedtls/compile.sh @@ -1,7 +1,6 @@ #!/bin/sh -set -x -set -e +set -ex CURRENT_SOURCE_DIR="$1" VENDOR_SOURCE_DIR="$2" diff --git a/subprojects/packagefiles/mbedtls/meson.build b/subprojects/packagefiles/mbedtls/meson.build index 8948a2a35e..f8e3f1661f 100644 --- a/subprojects/packagefiles/mbedtls/meson.build +++ b/subprojects/packagefiles/mbedtls/meson.build @@ -84,6 +84,28 @@ mbedtls_pal_libs = custom_target('mbedtls_pal', build_by_default: true, ) +mbedtls_curl_libs = custom_target('mbedtls_curl', + command: [ + find_program('compile-curl.sh'), + '@CURRENT_SOURCE_DIR@', + '@CURRENT_SOURCE_DIR@/mbedtls-mbedtls-3.2.1', + meson.current_build_dir(), + '@PRIVATE_DIR@', + join_paths(meson.build_root(), 'subprojects'), + '@OUTPUT@', + ], + + input: ['mbedtls-mbedtls-3.2.1/Makefile', 'gramine.patch'], + + output: [ + 'libmbedcrypto.a', + 'libmbedtls.a', + 'libmbedx509.a', + ], + + build_by_default: true, +) + mbedtls_inc = include_directories('include', 'mbedtls-mbedtls-3.2.1/include') mbedtls_static_dep = declare_dependency( @@ -98,3 +120,10 @@ mbedtls_pal_dep = declare_dependency( include_directories: mbedtls_inc, compile_args: '-DMBEDTLS_CONFIG_FILE="mbedtls/config-pal.h"', ) +mbedtls_curl_dep = declare_dependency( + # HACK: Apparently Meson considers the `mbedtls_curl_libs` to be "not linkable", because it has + # multiple outputs; however, it allows picking the outputs one by one. + link_with: [mbedtls_curl_libs[0], mbedtls_curl_libs[1], mbedtls_curl_libs[2]], + include_directories: mbedtls_inc, + compile_args: '-DMBEDTLS_CONFIG_FILE="mbedtls/config-pal.h"', +) diff --git a/tools/sgx/common/meson.build b/tools/sgx/common/meson.build index 0526b71616..8a49910c3e 100644 --- a/tools/sgx/common/meson.build +++ b/tools/sgx/common/meson.build @@ -1,4 +1,4 @@ -sgx_util = shared_library('sgx_util', +sgx_util = static_library('sgx_util', 'ias.c', 'ias.h', 'pf_util.c', @@ -36,16 +36,3 @@ sgx_util_dep = declare_dependency( protected_files_inc, ], ) - -pkgconfig.generate( - sgx_util, - libraries: [ - '-Wl,-rpath,${libdir}', - sgx_util, - ], -) - -meson.add_install_script('/bin/sh', '-c', - 'ln -sf ../../../libsgx_util.so ' + - '"$MESON_INSTALL_DESTDIR_PREFIX"/@0@/gramine/runtime/glibc/'.format( - get_option('libdir')))