Merge pull request #1162 from gabor-mezei-arm/buffer_sharing_copy_output_buffer

Add allocate and copy style output buffer protection
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 36baa3b..0cb208e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -297,6 +297,8 @@
         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 0778731..5a26821 100644
--- a/programs/test/CMakeLists.txt
+++ b/programs/test/CMakeLists.txt
@@ -78,6 +78,9 @@
         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 392b638..79c57d1 100644
--- a/programs/test/metatest.c
+++ b/programs/test/metatest.c
@@ -362,22 +362,22 @@
     { "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 0869aaa..188d5d5 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -251,6 +251,8 @@
     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 c22ef53..20fd8d3 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_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 4465d05..0daab09 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -1125,7 +1125,7 @@
     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 @@
     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 c277be8..ac9dde6 100644
--- a/tests/src/test_memory.c
+++ b/tests/src/test_memory.c
@@ -13,12 +13,15 @@
 #include <test/macros.h>
 #include <test/memory.h>
 
-#if defined(MBEDTLS_TEST_HAVE_ASAN)
+#if defined(MBEDTLS_TEST_MEMORY_CAN_POISON)
 #include <sanitizer/asan_interface.h>
 #include <stdint.h>
 #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 @@
 
 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 @@
     align_for_asan(&ptr, &size);
     __asan_unpoison_memory_region(ptr, size);
 }
-#endif /* Asan */
+#endif /* Memory poisoning */