From e94335399f2043c695dc89e7cf82ee82f0360c38 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 4 Nov 2021 12:45:19 +0100 Subject: [PATCH 1/9] 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 5d3c5bdc1..d4026071a 100644 --- a/programs/.gitignore +++ b/programs/.gitignore @@ -54,6 +54,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 550887a12..2a3fd6f25 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -114,6 +114,10 @@ ifdef PTHREAD APPS += ssl/ssl_pthread_server$(EXEXT) endif +ifdef SHARED +APPS += test/dlopen +endif + ifdef TEST_CPP APPS += test/cpp_dummy_build$(EXEXT) endif @@ -318,6 +322,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 $@ @@ -379,6 +392,7 @@ ifndef WINDOWS rm -f $(APPS) -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 04ec7fcac..6233de423 100644 --- a/programs/test/CMakeLists.txt +++ b/programs/test/CMakeLists.txt @@ -35,6 +35,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() + foreach(exe IN LISTS executables_libs executables_mbedcrypto) set(extra_sources "") if(exe STREQUAL "query_compile_time_config") diff --git a/programs/test/dlopen.c b/programs/test/dlopen.c new file mode 100644 index 000000000..e770c3911 --- /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/config.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 27482f17f1d13319bd1740010369576d04dd4e5c Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 4 Nov 2021 12:52:14 +0100 Subject: [PATCH 2/9] 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 000000000..f488dfbb3 --- /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 bbc2d9c4f..b10dc6eef 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -2423,6 +2423,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 () { @@ -2431,6 +2432,7 @@ component_test_cmake_shared () { make ldd programs/util/strerror | grep libmbedcrypto make test + programs/test/dlopen_demo.sh } test_build_opt () { From 71fcb3c9942c0e4b811af46c5205643e5a8b1a52 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 4 Nov 2021 15:07:28 +0100 Subject: [PATCH 3/9] 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 2a3fd6f25..7b9c5dd0a 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -18,6 +18,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) @@ -328,7 +334,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 6233de423..a30c89c58 100644 --- a/programs/test/CMakeLists.txt +++ b/programs/test/CMakeLists.txt @@ -38,7 +38,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() foreach(exe IN LISTS executables_libs executables_mbedcrypto) From 507c787b444632568a915a3e06878be5e798c270 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 4 Nov 2021 15:18:00 +0100 Subject: [PATCH 4/9] 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 7b9c5dd0a..2d0f70582 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -61,6 +61,18 @@ ifdef ZLIB LOCAL_LDFLAGS += -lz 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 + APPS = \ aes/crypt_and_hash$(EXEXT) \ hash/generic_sum$(EXEXT) \ @@ -120,7 +132,7 @@ ifdef PTHREAD APPS += ssl/ssl_pthread_server$(EXEXT) endif -ifdef SHARED +ifdef BUILD_DLOPEN APPS += test/dlopen endif @@ -328,7 +340,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 a30c89c58..8ecab4bf0 100644 --- a/programs/test/CMakeLists.txt +++ b/programs/test/CMakeLists.txt @@ -35,7 +35,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 99d8486f8ef3504cb0af749dfd64c47a67130177 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 10 Nov 2021 19:10:27 +0100 Subject: [PATCH 5/9] 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 8ecab4bf0..403797cef 100644 --- a/programs/test/CMakeLists.txt +++ b/programs/test/CMakeLists.txt @@ -39,9 +39,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() foreach(exe IN LISTS executables_libs executables_mbedcrypto) From 3dbb3e7e0771018bbf1d95bf74440c5d7ae78508 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 10 Nov 2021 19:11:32 +0100 Subject: [PATCH 6/9] 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 e770c3911..ab992fda1 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 eea9c74d81228356961f04e26aadaa2535a2a5d6 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 10 Nov 2021 21:04:24 +0100 Subject: [PATCH 7/9] 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 ab992fda1..8413197ee 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 f488dfbb3..2dde3ebed 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 8e8e96500a49e0bb0aabe7909410d2a97b182b9b Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 12 Nov 2021 14:30:22 +0100 Subject: [PATCH 8/9] 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 8413197ee..e31cae1ed 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 From 6fa5c1d20c93d998b64c668e0e7d91771545d237 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 25 Nov 2021 18:12:44 +0100 Subject: [PATCH 9/9] Use the normal idiom to support MBEDTLS_CONFIG_FILE Signed-off-by: Gilles Peskine --- programs/test/dlopen.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/programs/test/dlopen.c b/programs/test/dlopen.c index e31cae1ed..2ee531645 100644 --- a/programs/test/dlopen.c +++ b/programs/test/dlopen.c @@ -17,7 +17,11 @@ * limitations under the License. */ +#if !defined(MBEDTLS_CONFIG_FILE) #include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif #include "mbedtls/platform.h" #if !defined(MBEDTLS_PLATFORM_C)