diff --git a/CMakeLists.txt b/CMakeLists.txt index 36baa3b402..0cb208e988 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -297,6 +297,8 @@ if(ENABLE_TESTING OR ENABLE_PROGRAMS) PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/tests/include PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/library) + # Request C11, needed for memory poisoning tests + set_target_properties(mbedtls_test PROPERTIES C_STANDARD 11) file(GLOB MBEDTLS_TEST_HELPER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/tests/src/test_helpers/*.c) diff --git a/programs/test/CMakeLists.txt b/programs/test/CMakeLists.txt index 0778731125..5a26821b51 100644 --- a/programs/test/CMakeLists.txt +++ b/programs/test/CMakeLists.txt @@ -78,6 +78,9 @@ foreach(exe IN LISTS executables_libs executables_mbedcrypto) target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) endif() + # Request C11, required for memory poisoning + set_target_properties(${exe} PROPERTIES C_STANDARD 11) + # This emulates "if ( ... IN_LIST ... )" which becomes available in CMake 3.3 list(FIND executables_libs ${exe} exe_index) if (${exe_index} GREATER -1) diff --git a/programs/test/metatest.c b/programs/test/metatest.c index 392b638420..79c57d1746 100644 --- a/programs/test/metatest.c +++ b/programs/test/metatest.c @@ -362,22 +362,22 @@ metatest_t metatests[] = { { "double_free", "asan", double_free }, { "read_uninitialized_stack", "msan", read_uninitialized_stack }, { "memory_leak", "asan", memory_leak }, - { "test_memory_poison_0_0_8_r", "asan", test_memory_poison }, - { "test_memory_poison_0_0_8_w", "asan", test_memory_poison }, - { "test_memory_poison_0_7_8_r", "asan", test_memory_poison }, - { "test_memory_poison_0_7_8_w", "asan", test_memory_poison }, - { "test_memory_poison_0_0_1_r", "asan", test_memory_poison }, - { "test_memory_poison_0_0_1_w", "asan", test_memory_poison }, - { "test_memory_poison_0_1_2_r", "asan", test_memory_poison }, - { "test_memory_poison_0_1_2_w", "asan", test_memory_poison }, - { "test_memory_poison_7_0_8_r", "asan", test_memory_poison }, - { "test_memory_poison_7_0_8_w", "asan", test_memory_poison }, - { "test_memory_poison_7_7_8_r", "asan", test_memory_poison }, - { "test_memory_poison_7_7_8_w", "asan", test_memory_poison }, - { "test_memory_poison_7_0_1_r", "asan", test_memory_poison }, - { "test_memory_poison_7_0_1_w", "asan", test_memory_poison }, - { "test_memory_poison_7_1_2_r", "asan", test_memory_poison }, - { "test_memory_poison_7_1_2_w", "asan", test_memory_poison }, + { "test_memory_poison_0_0_8_r", "poison", test_memory_poison }, + { "test_memory_poison_0_0_8_w", "poison", test_memory_poison }, + { "test_memory_poison_0_7_8_r", "poison", test_memory_poison }, + { "test_memory_poison_0_7_8_w", "poison", test_memory_poison }, + { "test_memory_poison_0_0_1_r", "poison", test_memory_poison }, + { "test_memory_poison_0_0_1_w", "poison", test_memory_poison }, + { "test_memory_poison_0_1_2_r", "poison", test_memory_poison }, + { "test_memory_poison_0_1_2_w", "poison", test_memory_poison }, + { "test_memory_poison_7_0_8_r", "poison", test_memory_poison }, + { "test_memory_poison_7_0_8_w", "poison", test_memory_poison }, + { "test_memory_poison_7_7_8_r", "poison", test_memory_poison }, + { "test_memory_poison_7_7_8_w", "poison", test_memory_poison }, + { "test_memory_poison_7_0_1_r", "poison", test_memory_poison }, + { "test_memory_poison_7_0_1_w", "poison", test_memory_poison }, + { "test_memory_poison_7_1_2_r", "poison", test_memory_poison }, + { "test_memory_poison_7_1_2_w", "poison", test_memory_poison }, { "mutex_lock_not_initialized", "pthread", mutex_lock_not_initialized }, { "mutex_unlock_not_initialized", "pthread", mutex_unlock_not_initialized }, { "mutex_free_not_initialized", "pthread", mutex_free_not_initialized }, diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0869aaa018..188d5d595f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -251,6 +251,8 @@ function(add_test_suite suite_name) target_include_directories(test_suite_${data_name} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../library) + # Request C11, which is needed for memory poisoning tests + set_target_properties(test_suite_${data_name} PROPERTIES C_STANDARD 11) if(${data_name} MATCHES ${SKIP_TEST_SUITES_REGEX}) message(STATUS "The test suite ${data_name} will not be executed.") diff --git a/tests/include/test/memory.h b/tests/include/test/memory.h index c22ef53f7c..20fd8d30a5 100644 --- a/tests/include/test/memory.h +++ b/tests/include/test/memory.h @@ -22,9 +22,12 @@ * memory as poisoned, which can be used to enforce some memory access * policies. * + * Support for the C11 thread_local keyword is also required. + * * Currently, only Asan (Address Sanitizer) is supported. */ -#if defined(MBEDTLS_TEST_HAVE_ASAN) +#if defined(MBEDTLS_TEST_HAVE_ASAN) && \ + (__STDC_VERSION__ >= 201112L) # define MBEDTLS_TEST_MEMORY_CAN_POISON #endif @@ -62,6 +65,12 @@ #if defined(MBEDTLS_TEST_MEMORY_CAN_POISON) +/** Thread-local variable used to enable memory poisoning. This is set and + * unset in the test wrappers so that calls to PSA functions from the library + * do not poison memory. + */ +extern _Thread_local unsigned int mbedtls_test_memory_poisoning_count; + /** Poison a memory area so that any attempt to read or write from it will * cause a runtime failure. * @@ -69,7 +78,10 @@ */ void mbedtls_test_memory_poison(const unsigned char *ptr, size_t size); #define MBEDTLS_TEST_MEMORY_POISON(ptr, size) \ - mbedtls_test_memory_poison(ptr, size) + do { \ + mbedtls_test_memory_poisoning_count++; \ + mbedtls_test_memory_poison(ptr, size); \ + } while (0) /** Undo the effect of mbedtls_test_memory_poison(). * @@ -80,7 +92,12 @@ void mbedtls_test_memory_poison(const unsigned char *ptr, size_t size); */ void mbedtls_test_memory_unpoison(const unsigned char *ptr, size_t size); #define MBEDTLS_TEST_MEMORY_UNPOISON(ptr, size) \ - mbedtls_test_memory_unpoison(ptr, size) + do { \ + mbedtls_test_memory_unpoison(ptr, size); \ + if (mbedtls_test_memory_poisoning_count != 0) { \ + mbedtls_test_memory_poisoning_count--; \ + } \ + } while (0) #else /* MBEDTLS_TEST_MEMORY_CAN_POISON */ #define MBEDTLS_TEST_MEMORY_POISON(ptr, size) ((void) (ptr), (void) (size)) diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh index 4465d05068..0daab0918d 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -1125,7 +1125,7 @@ component_test_default_cmake_gcc_asan () { programs/test/selftest msg "test: metatests (GCC, ASan build)" - tests/scripts/run-metatests.sh any asan + tests/scripts/run-metatests.sh any asan poison msg "test: ssl-opt.sh (ASan build)" # ~ 1 min tests/ssl-opt.sh @@ -1944,7 +1944,7 @@ component_test_everest () { make test msg "test: metatests (clang, ASan)" - tests/scripts/run-metatests.sh any asan + tests/scripts/run-metatests.sh any asan poison msg "test: Everest ECDH context - ECDH-related part of ssl-opt.sh (ASan build)" # ~ 5s tests/ssl-opt.sh -f ECDH diff --git a/tests/src/test_memory.c b/tests/src/test_memory.c index c277be85ab..ac9dde6163 100644 --- a/tests/src/test_memory.c +++ b/tests/src/test_memory.c @@ -13,12 +13,15 @@ #include #include -#if defined(MBEDTLS_TEST_HAVE_ASAN) +#if defined(MBEDTLS_TEST_MEMORY_CAN_POISON) #include #include #endif -#if defined(MBEDTLS_TEST_HAVE_ASAN) +#if defined(MBEDTLS_TEST_MEMORY_CAN_POISON) + +_Thread_local unsigned int mbedtls_test_memory_poisoning_count = 0; + static void align_for_asan(const unsigned char **p_ptr, size_t *p_size) { uintptr_t start = (uintptr_t) *p_ptr; @@ -36,6 +39,9 @@ static void align_for_asan(const unsigned char **p_ptr, size_t *p_size) void mbedtls_test_memory_poison(const unsigned char *ptr, size_t size) { + if (mbedtls_test_memory_poisoning_count == 0) { + return; + } if (size == 0) { return; } @@ -51,4 +57,4 @@ void mbedtls_test_memory_unpoison(const unsigned char *ptr, size_t size) align_for_asan(&ptr, &size); __asan_unpoison_memory_region(ptr, size); } -#endif /* Asan */ +#endif /* Memory poisoning */