Fix Msan failure with explicit_bzero

On some platforms, including modern Linux, Clang with Msan does not
recognize that explicit_bzero() writes well-defined content to its output
buffer. For us, this causes CMAC operations to fail in Msan builds when
mbedtls_platform_zeroize() is implemented over explicit_bzero(). Fix this.

Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
diff --git a/library/platform_util.c b/library/platform_util.c
index 6d4759c..f891cd4 100644
--- a/library/platform_util.c
+++ b/library/platform_util.c
@@ -57,6 +57,15 @@
 #endif
 
 #if !defined(MBEDTLS_PLATFORM_ZEROIZE_ALT)
+
+#undef HAVE_MEMORY_SANITIZER
+#if defined(__has_feature)
+#if __has_feature(memory_sanitizer)
+#include <sanitizer/msan_interface.h>
+#define HAVE_MEMORY_SANITIZER
+#endif
+#endif
+
 /*
  * Where possible, we try to detect the presence of a platform-provided
  * secure memset, such as explicit_bzero(), that is safe against being optimized
@@ -100,6 +109,15 @@
     if (len > 0) {
 #if defined(MBEDTLS_PLATFORM_HAS_EXPLICIT_BZERO)
         explicit_bzero(buf, len);
+#if defined(HAVE_MEMORY_SANITIZER)
+        /* You'd think that Msan would recognize explicit_bzero() as
+         * equivalent to bzero(), but it actually doesn't on several
+         * platforms, including Linux (Ubuntu 20.04).
+         * https://github.com/google/sanitizers/issues/1507
+         * https://github.com/openssh/openssh-portable/commit/74433a19bb6f4cef607680fa4d1d7d81ca3826aa
+         */
+        __msan_unpoison(buf, len);
+#endif
 #elif defined(__STDC_LIB_EXT1__)
         memset_s(buf, len, 0, len);
 #elif defined(_WIN32)