From a7c247e87d1b79c6c74b89aaab32864e57f685d5 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 4 Nov 2021 12:45:19 +0100 Subject: [PATCH 1/8] New test app for dynamic loading of libmbed* with dlopen Signed-off-by: Gilles Peskine --- programs/.gitignore | 1 + programs/Makefile | 14 +++++ programs/test/CMakeLists.txt | 6 +++ programs/test/dlopen.c | 102 +++++++++++++++++++++++++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 programs/test/dlopen.c diff --git a/programs/.gitignore b/programs/.gitignore index deb104a401..550239eff6 100644 --- a/programs/.gitignore +++ b/programs/.gitignore @@ -57,6 +57,7 @@ ssl/ssl_server2 test/benchmark test/cpp_dummy_build test/cpp_dummy_build.cpp +test/dlopen test/ecp-bench test/query_compile_time_config test/selftest diff --git a/programs/Makefile b/programs/Makefile index 7f9d11e80d..2c25983c59 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -118,6 +118,10 @@ ifdef PTHREAD APPS += ssl/ssl_pthread_server endif +ifdef SHARED +APPS += test/dlopen +endif + ifdef TEST_CPP APPS += test/cpp_dummy_build endif @@ -344,6 +348,15 @@ test/cpp_dummy_build$(EXEXT): test/cpp_dummy_build.cpp $(DEP) echo " CXX test/cpp_dummy_build.cpp" $(CXX) $(LOCAL_CXXFLAGS) $(CXXFLAGS) test/cpp_dummy_build.cpp $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@ +ifdef SHARED +test/dlopen$(EXEXT): test/dlopen.c $(DEP) + echo " CC test/dlopen.c" +# Do not link any test objects (that would bring in a static dependency on +# libmbedcrypto at least). Do not link with libmbed* (that would defeat the +# purpose of testing dynamic loading). + $(CC) $(LOCAL_CFLAGS) $(CFLAGS) test/dlopen.c $(LDFLAGS) -ldl -o $@ +endif + test/query_config.o: test/query_config.c test/query_config.h $(DEP) echo " CC test/query_config.c" $(CC) $(LOCAL_CFLAGS) $(CFLAGS) -c test/query_config.c -o $@ @@ -405,6 +418,7 @@ ifndef WINDOWS rm -f $(EXES) -rm -f ssl/ssl_pthread_server$(EXEXT) -rm -f test/cpp_dummy_build.cpp test/cpp_dummy_build$(EXEXT) + -rm -f test/dlopen$(EXEXT) else if exist *.o del /Q /F *.o if exist *.exe del /Q /F *.exe diff --git a/programs/test/CMakeLists.txt b/programs/test/CMakeLists.txt index 142a831667..637b870a4e 100644 --- a/programs/test/CMakeLists.txt +++ b/programs/test/CMakeLists.txt @@ -27,6 +27,12 @@ if(TEST_CPP) target_link_libraries(cpp_dummy_build ${mbedcrypto_target}) endif() +if(USE_SHARED_MBEDTLS_LIBRARY) + add_executable(dlopen "dlopen.c") + target_include_directories(dlopen PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include) + target_link_libraries(dlopen "-ldl") +endif() + if(GEN_FILES) find_package(Perl REQUIRED) diff --git a/programs/test/dlopen.c b/programs/test/dlopen.c new file mode 100644 index 0000000000..fe1a6ac157 --- /dev/null +++ b/programs/test/dlopen.c @@ -0,0 +1,102 @@ +/* + * Test dynamic loading of libmbed* + * + * Copyright The Mbed TLS Contributors + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbedtls/build_info.h" + +#include "mbedtls/platform.h" +#if !defined(MBEDTLS_PLATFORM_C) +#include +#include +#define mbedtls_fprintf fprintf +#define mbedtls_printf printf +#define mbedtls_exit exit +#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS +#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#include "mbedtls/x509_crt.h" +#endif + +#define CRYPTO_SO_FILENAME "libmbedcrypto.so" +#define X509_SO_FILENAME "libmbedx509.so" +#define TLS_SO_FILENAME "libmbedtls.so" + +#include + +#define CHECK_DLERROR( function, argument ) \ + do \ + { \ + char *CHECK_DLERROR_error = dlerror ( ); \ + if( CHECK_DLERROR_error != NULL ) \ + { \ + fprintf( stderr, "Dynamic loading error for %s(%s): %s\n", \ + function, argument, CHECK_DLERROR_error ); \ + mbedtls_exit( MBEDTLS_EXIT_FAILURE ); \ + } \ + } \ + while( 0 ) + +int main( void ) +{ + unsigned n; + +#if defined(MBEDTLS_SSL_TLS_C) + void *tls_so = dlopen( TLS_SO_FILENAME, RTLD_NOW ); + CHECK_DLERROR( "dlopen", TLS_SO_FILENAME ); + const int *( *ssl_list_ciphersuites )( void ) = + dlsym( tls_so, "mbedtls_ssl_list_ciphersuites" ); + CHECK_DLERROR( "dlsym", "mbedtls_ssl_list_ciphersuites" ); + const int *ciphersuites = ssl_list_ciphersuites( ); + for( n = 0; ciphersuites[n] != 0; n++ ) + /* nothing to do, we're just counting */; + mbedtls_printf( "%u ciphersuites\n", n ); + dlclose( tls_so ); + CHECK_DLERROR( "dlclose", TLS_SO_FILENAME ); +#endif /* MBEDTLS_SSL_TLS_C */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + void *x509_so = dlopen( X509_SO_FILENAME, RTLD_NOW ); + CHECK_DLERROR( "dlopen", X509_SO_FILENAME ); + const mbedtls_x509_crt_profile *profile = + dlsym( x509_so, "mbedtls_x509_crt_profile_default" ); + CHECK_DLERROR( "dlsym", "mbedtls_x509_crt_profile_default" ); + mbedtls_printf( "Allowed md mask: %08x\n", + (unsigned) profile->allowed_mds ); + dlclose( x509_so ); + CHECK_DLERROR( "dlclose", X509_SO_FILENAME ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_MD_C) + void *crypto_so = dlopen( CRYPTO_SO_FILENAME, RTLD_NOW ); + CHECK_DLERROR( "dlopen", CRYPTO_SO_FILENAME ); + const int *( *md_list )( void ) = + dlsym( crypto_so, "mbedtls_md_list" ); + CHECK_DLERROR( "dlsym", "mbedtls_md_list" ); + const int *mds = md_list( ); + for( n = 0; mds[n] != 0; n++ ) + /* nothing to do, we're just counting */; + mbedtls_printf( "%u hashes\n", n ); + dlclose( crypto_so ); + CHECK_DLERROR( "dlclose", CRYPTO_SO_FILENAME ); +#endif /* MBEDTLS_MD_C */ + + return( 0 ); +} + From ca144597e8db9f300b6d790bb96e2454f99e199a Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 4 Nov 2021 12:52:14 +0100 Subject: [PATCH 2/8] Run the dlopen test in shared library builds Non-regression for the fix in https://github.com/ARMmbed/mbedtls/pull/5126: libmbedtls and libmbedx509 did not declare their dependencies on libmbedx509 and libmbedcrypto when built with make. Signed-off-by: Gilles Peskine --- programs/test/dlopen_demo.sh | 44 ++++++++++++++++++++++++++++++++++++ tests/scripts/all.sh | 2 ++ 2 files changed, 46 insertions(+) create mode 100755 programs/test/dlopen_demo.sh diff --git a/programs/test/dlopen_demo.sh b/programs/test/dlopen_demo.sh new file mode 100755 index 0000000000..f488dfbb30 --- /dev/null +++ b/programs/test/dlopen_demo.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +# Run the shared library dynamic loading demo program. +# This is only expected to work when Mbed TLS is built as a shared library. + +# Copyright The Mbed TLS Contributors +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e -u + +program_dir="${0%/*}" +program="$program_dir/dlopen" +top_dir="$program_dir/../.." +library_dir="$top_dir/library" + +# ELF-based Unix-like (Linux, *BSD, Solaris, ...) +if [ -n "${LD_LIBRARY_PATH-}" ]; then + LD_LIBRARY_PATH="$library_dir:$LD_LIBRARY_PATH" +else + LD_LIBRARY_PATH="$library_dir" +fi +export LD_LIBRARY_PATH + +# OSX/macOS +if [ -n "${DYLD_LIBRARY_PATH-}" ]; then + DYLD_LIBRARY_PATH="$library_dir:$DYLD_LIBRARY_PATH" +else + DYLD_LIBRARY_PATH="$library_dir" +fi +export DYLD_LIBRARY_PATH + +"$program" diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh index c148cf1ef7..df0b762912 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -2277,6 +2277,7 @@ component_test_make_shared () { msg "build/test: make shared" # ~ 40s make SHARED=1 all check ldd programs/util/strerror | grep libmbedcrypto + programs/test/dlopen_demo.sh } component_test_cmake_shared () { @@ -2285,6 +2286,7 @@ component_test_cmake_shared () { make ldd programs/util/strerror | grep libmbedcrypto make test + programs/test/dlopen_demo.sh } test_build_opt () { From 5dbee582a31061ff83dd8485a941d58504fb3936 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 4 Nov 2021 15:07:28 +0100 Subject: [PATCH 3/8] Only link with libdl on Linux Requiring an extra library for dlopen is a Linux non-POSIX-compliance. Signed-off-by: Gilles Peskine --- programs/Makefile | 8 +++++++- programs/test/CMakeLists.txt | 4 +++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/programs/Makefile b/programs/Makefile index 2c25983c59..84399f9be3 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -17,6 +17,12 @@ LOCAL_LDFLAGS = ${MBEDTLS_TEST_OBJS} \ -lmbedx509$(SHARED_SUFFIX) \ -lmbedcrypto$(SHARED_SUFFIX) +ifeq ($(shell uname -s),Linux) +DLOPEN_LDFLAGS ?= -ldl +else +DLOPEN_LDFLAGS ?= +endif + include ../3rdparty/Makefile.inc LOCAL_CFLAGS+=$(THIRDPARTY_INCLUDES) @@ -354,7 +360,7 @@ test/dlopen$(EXEXT): test/dlopen.c $(DEP) # Do not link any test objects (that would bring in a static dependency on # libmbedcrypto at least). Do not link with libmbed* (that would defeat the # purpose of testing dynamic loading). - $(CC) $(LOCAL_CFLAGS) $(CFLAGS) test/dlopen.c $(LDFLAGS) -ldl -o $@ + $(CC) $(LOCAL_CFLAGS) $(CFLAGS) test/dlopen.c $(LDFLAGS) $(DLOPEN_LDFLAGS) -o $@ endif test/query_config.o: test/query_config.c test/query_config.h $(DEP) diff --git a/programs/test/CMakeLists.txt b/programs/test/CMakeLists.txt index 637b870a4e..3a8affbfa9 100644 --- a/programs/test/CMakeLists.txt +++ b/programs/test/CMakeLists.txt @@ -30,7 +30,9 @@ endif() if(USE_SHARED_MBEDTLS_LIBRARY) add_executable(dlopen "dlopen.c") target_include_directories(dlopen PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include) - target_link_libraries(dlopen "-ldl") + if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + target_link_libraries(dlopen "-ldl") + endif() endif() if(GEN_FILES) From f80a029f28213487f92155550bf666e5d43fce7d Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 4 Nov 2021 15:18:00 +0100 Subject: [PATCH 4/8] Don't build dlopen when building for Windows Windows doesn't have dlopen, not even Linux emulation environments such as MinGW. Signed-off-by: Gilles Peskine --- programs/Makefile | 16 ++++++++++++++-- programs/test/CMakeLists.txt | 3 ++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/programs/Makefile b/programs/Makefile index 84399f9be3..1ebf8d241e 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -61,6 +61,18 @@ else PYTHON ?= $(shell if type python3 >/dev/null 2>/dev/null; then echo python3; else echo python; fi) endif +# Only build the dlopen test in shared library builds, and not when building +# for Windows. +ifdef BUILD_DLOPEN +# Don't override the value +else ifdef WINDOWS_BUILD +BUILD_DLOPEN = +else ifdef SHARED +BUILD_DLOPEN = y +else +BUILD_DLOPEN = +endif + ## The following assignment is the list of base names of applications that ## will be built on Windows. Extra Linux/Unix/POSIX-only applications can ## be declared by appending with `APPS += ...` afterwards. @@ -124,7 +136,7 @@ ifdef PTHREAD APPS += ssl/ssl_pthread_server endif -ifdef SHARED +ifdef BUILD_DLOPEN APPS += test/dlopen endif @@ -354,7 +366,7 @@ test/cpp_dummy_build$(EXEXT): test/cpp_dummy_build.cpp $(DEP) echo " CXX test/cpp_dummy_build.cpp" $(CXX) $(LOCAL_CXXFLAGS) $(CXXFLAGS) test/cpp_dummy_build.cpp $(LOCAL_LDFLAGS) $(LDFLAGS) -o $@ -ifdef SHARED +ifdef BUILD_DLOPEN test/dlopen$(EXEXT): test/dlopen.c $(DEP) echo " CC test/dlopen.c" # Do not link any test objects (that would bring in a static dependency on diff --git a/programs/test/CMakeLists.txt b/programs/test/CMakeLists.txt index 3a8affbfa9..1a79e974e6 100644 --- a/programs/test/CMakeLists.txt +++ b/programs/test/CMakeLists.txt @@ -27,7 +27,8 @@ if(TEST_CPP) target_link_libraries(cpp_dummy_build ${mbedcrypto_target}) endif() -if(USE_SHARED_MBEDTLS_LIBRARY) +if(USE_SHARED_MBEDTLS_LIBRARY AND + NOT ${CMAKE_SYSTEM_NAME} MATCHES "[Ww][Ii][Nn]") add_executable(dlopen "dlopen.c") target_include_directories(dlopen PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include) if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") From 88e3e70df589ee9fd4c5275bcbcc08ab8ac465c1 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 10 Nov 2021 19:10:27 +0100 Subject: [PATCH 5/8] Use CMake's knowledge of what system library has dlopen() Signed-off-by: Gilles Peskine --- programs/test/CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/programs/test/CMakeLists.txt b/programs/test/CMakeLists.txt index 1a79e974e6..c3e7d2e98e 100644 --- a/programs/test/CMakeLists.txt +++ b/programs/test/CMakeLists.txt @@ -31,9 +31,7 @@ if(USE_SHARED_MBEDTLS_LIBRARY AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "[Ww][Ii][Nn]") add_executable(dlopen "dlopen.c") target_include_directories(dlopen PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include) - if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - target_link_libraries(dlopen "-ldl") - endif() + target_link_libraries(dlopen ${CMAKE_DL_LIBS}) endif() if(GEN_FILES) From b6a02997080b43f2e9caba81062e97d4bc5773ac Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 10 Nov 2021 19:11:32 +0100 Subject: [PATCH 6/8] Avoid undefined variable warning without MBEDTLS_MD_C Signed-off-by: Gilles Peskine --- programs/test/dlopen.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/programs/test/dlopen.c b/programs/test/dlopen.c index fe1a6ac157..ecd7f0fbc3 100644 --- a/programs/test/dlopen.c +++ b/programs/test/dlopen.c @@ -55,7 +55,9 @@ int main( void ) { +#if defined(MBEDTLS_MD_C) || defined(MBEDTLS_SSL_TLS_C) unsigned n; +#endif #if defined(MBEDTLS_SSL_TLS_C) void *tls_so = dlopen( TLS_SO_FILENAME, RTLD_NOW ); From 7fb54c567456f3501ed711bbb72d1d2de2d130da Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 10 Nov 2021 21:04:24 +0100 Subject: [PATCH 7/8] More explicit output for the test program Without that, the logs were a bit hard to understand if you didn't know what to expect. Signed-off-by: Gilles Peskine --- programs/test/dlopen.c | 10 ++++++---- programs/test/dlopen_demo.sh | 2 ++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/programs/test/dlopen.c b/programs/test/dlopen.c index ecd7f0fbc3..ee3a9d255e 100644 --- a/programs/test/dlopen.c +++ b/programs/test/dlopen.c @@ -68,7 +68,8 @@ int main( void ) const int *ciphersuites = ssl_list_ciphersuites( ); for( n = 0; ciphersuites[n] != 0; n++ ) /* nothing to do, we're just counting */; - mbedtls_printf( "%u ciphersuites\n", n ); + mbedtls_printf( "dlopen(%s): %u ciphersuites\n", + TLS_SO_FILENAME, n ); dlclose( tls_so ); CHECK_DLERROR( "dlclose", TLS_SO_FILENAME ); #endif /* MBEDTLS_SSL_TLS_C */ @@ -79,8 +80,8 @@ int main( void ) const mbedtls_x509_crt_profile *profile = dlsym( x509_so, "mbedtls_x509_crt_profile_default" ); CHECK_DLERROR( "dlsym", "mbedtls_x509_crt_profile_default" ); - mbedtls_printf( "Allowed md mask: %08x\n", - (unsigned) profile->allowed_mds ); + mbedtls_printf( "dlopen(%s): Allowed md mask: %08x\n", + X509_SO_FILENAME, (unsigned) profile->allowed_mds ); dlclose( x509_so ); CHECK_DLERROR( "dlclose", X509_SO_FILENAME ); #endif /* MBEDTLS_X509_CRT_PARSE_C */ @@ -94,7 +95,8 @@ int main( void ) const int *mds = md_list( ); for( n = 0; mds[n] != 0; n++ ) /* nothing to do, we're just counting */; - mbedtls_printf( "%u hashes\n", n ); + mbedtls_printf( "dlopen(%s): %u hashes\n", + CRYPTO_SO_FILENAME, n ); dlclose( crypto_so ); CHECK_DLERROR( "dlclose", CRYPTO_SO_FILENAME ); #endif /* MBEDTLS_MD_C */ diff --git a/programs/test/dlopen_demo.sh b/programs/test/dlopen_demo.sh index f488dfbb30..2dde3ebeda 100755 --- a/programs/test/dlopen_demo.sh +++ b/programs/test/dlopen_demo.sh @@ -41,4 +41,6 @@ else fi export DYLD_LIBRARY_PATH +echo "Running dynamic loading test program: $program" +echo "Loading libraries from: $library_dir" "$program" From 834d229117a3e92483008fc2729231fc0c38b816 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 12 Nov 2021 14:30:22 +0100 Subject: [PATCH 8/8] Fix dynamic library extension on macOS Signed-off-by: Gilles Peskine --- programs/test/dlopen.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/programs/test/dlopen.c b/programs/test/dlopen.c index ee3a9d255e..3b88df4cf3 100644 --- a/programs/test/dlopen.c +++ b/programs/test/dlopen.c @@ -34,9 +34,15 @@ #include "mbedtls/x509_crt.h" #endif -#define CRYPTO_SO_FILENAME "libmbedcrypto.so" -#define X509_SO_FILENAME "libmbedx509.so" -#define TLS_SO_FILENAME "libmbedtls.so" +#if defined(__APPLE__) +#define SO_SUFFIX ".dylib" +#else +#define SO_SUFFIX ".so" +#endif + +#define CRYPTO_SO_FILENAME "libmbedcrypto" SO_SUFFIX +#define X509_SO_FILENAME "libmbedx509" SO_SUFFIX +#define TLS_SO_FILENAME "libmbedtls" SO_SUFFIX #include