From 6240defd17f23c636db24caf36a4ebf975585ecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Fri, 10 Jul 2020 09:35:54 +0200 Subject: [PATCH] Add MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This option allows to test the constant-flow nature of selected code, using MemSan and the fundamental observation behind ctgrind that the set of operations allowed on undefined memory by dynamic analysers is the same as the set of operations allowed on secret data to avoid leaking it to a local attacker via side channels, namely, any operation except branching and dereferencing. (This isn't the full story, as on some CPUs some instructions have variable execution depending on the inputs, most notably division and on some cores multiplication. However, testing that no branch or memory access depends on secret data is already a good start.) Signed-off-by: Manuel Pégourié-Gonnard --- include/mbedtls/check_config.h | 10 ++++++ include/mbedtls/config.h | 13 ++++++++ library/version_features.c | 3 ++ programs/test/query_config.c | 8 +++++ scripts/config.py | 1 + tests/include/test/constant_flow.h | 51 ++++++++++++++++++++++++++++++ tests/scripts/all.sh | 12 +++++++ visualc/VS2010/mbedTLS.vcxproj | 1 + 8 files changed, 99 insertions(+) create mode 100644 tests/include/test/constant_flow.h diff --git a/include/mbedtls/check_config.h b/include/mbedtls/check_config.h index f2148a8b5..15cc21b64 100644 --- a/include/mbedtls/check_config.h +++ b/include/mbedtls/check_config.h @@ -186,6 +186,16 @@ #error "MBEDTLS_ENTROPY_FORCE_SHA256 defined, but not all prerequisites" #endif +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) +#define MBEDTLS_HAS_MEMSAN +#endif +#endif +#if defined(MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN) && !defined(MBEDTLS_HAS_MEMSAN) +#error "MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN requires building with MemorySanitizer" +#endif +#undef MBEDTLS_HAS_MEMSAN + #if defined(MBEDTLS_TEST_NULL_ENTROPY) && \ ( !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) ) #error "MBEDTLS_TEST_NULL_ENTROPY defined, but not all prerequisites" diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h index e00c546e5..124c597b6 100644 --- a/include/mbedtls/config.h +++ b/include/mbedtls/config.h @@ -1906,6 +1906,19 @@ */ //#define MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH +/** + * \def MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN + * + * Enable testing of the constant-flow nature of some sensitive functions with + * clang's MemorySanitizer. This causes some existing tests to also test + * non-functional properties of the code under test. + * + * This setting requires compiling with clang -fsanitize=memory. + * + * Uncomment to enable testing of the constant-flow nature of seletected code. + */ +//#define MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN + /** * \def MBEDTLS_TEST_HOOKS * diff --git a/library/version_features.c b/library/version_features.c index 64e9e86db..2470d8d1d 100644 --- a/library/version_features.c +++ b/library/version_features.c @@ -557,6 +557,9 @@ static const char * const features[] = { #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH) "MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH", #endif /* MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH */ +#if defined(MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN) + "MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN", +#endif /* MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN */ #if defined(MBEDTLS_TEST_HOOKS) "MBEDTLS_TEST_HOOKS", #endif /* MBEDTLS_TEST_HOOKS */ diff --git a/programs/test/query_config.c b/programs/test/query_config.c index 98b065bfe..23dc51512 100644 --- a/programs/test/query_config.c +++ b/programs/test/query_config.c @@ -1538,6 +1538,14 @@ int query_config( const char *config ) } #endif /* MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH */ +#if defined(MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN) + if( strcmp( "MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN", config ) == 0 ) + { + MACRO_EXPANSION_TO_STR( MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN ); + return( 0 ); + } +#endif /* MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN */ + #if defined(MBEDTLS_TEST_HOOKS) if( strcmp( "MBEDTLS_TEST_HOOKS", config ) == 0 ) { diff --git a/scripts/config.py b/scripts/config.py index 3d297dc3d..793e9dfa7 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -194,6 +194,7 @@ EXCLUDE_FROM_FULL = frozenset([ 'MBEDTLS_RSA_NO_CRT', # influences the use of RSA in X.509 and TLS 'MBEDTLS_SHA512_NO_SHA384', # removes a feature 'MBEDTLS_SSL_HW_RECORD_ACCEL', # build dependency (hook functions) + 'MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN', # build dependency (clang+memsan) 'MBEDTLS_TEST_NULL_ENTROPY', # removes a feature 'MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION', # influences the use of X.509 in TLS 'MBEDTLS_ZLIB_SUPPORT', # build dependency (libz) diff --git a/tests/include/test/constant_flow.h b/tests/include/test/constant_flow.h new file mode 100644 index 000000000..98bee7e48 --- /dev/null +++ b/tests/include/test/constant_flow.h @@ -0,0 +1,51 @@ +/** + * \file constant_flow.h + * + * \brief This file contains tools to ensure tested code has constant flow. + */ + +/* + * Copyright (C) 2020, ARM Limited, All Rights Reserved + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef TEST_CONSTANT_FLOW_H +#define TEST_CONSTANT_FLOW_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN) +#include + +/* Use macros to avoid messing up with origin tracking */ +#define TEST_CF_SECRET __msan_allocated_memory +// void __msan_allocated_memory(const volatile void* data, size_t size); +#define TEST_CF_PUBLIC __msan_unpoison +// void __msan_unpoison(const volatile void *a, size_t size); + +#else /* MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN */ + +#define TEST_CF_SECRET(ptr, size) +#define TEST_CF_PUBLIC(ptr, size) + +#endif /* MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN */ + +#endif /* TEST_CONSTANT_FLOW_H */ diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh index ec61d1962..9c9247f8f 100755 --- a/tests/scripts/all.sh +++ b/tests/scripts/all.sh @@ -1074,6 +1074,18 @@ component_test_full_cmake_clang () { if_build_succeeded env OPENSSL_CMD="$OPENSSL_NEXT" tests/compat.sh -e '^$' -f 'ARIA\|CHACHA' } +component_test_memsan_constant_flow () { + msg "build: cmake memsan, full config with constant flow testing" + scripts/config.py full + scripts/config.py set MBEDTLS_TEST_CONSTANT_FLOW_MEMSAN + scripts/config.py unset MBEDTLS_AESNI_C # memsan doesn't grok asm + CC=clang cmake -D CMAKE_BUILD_TYPE:String=MemSan . + make + + msg "test: main suites (memsan constant flow)" + make test +} + component_test_default_no_deprecated () { # Test that removing the deprecated features from the default # configuration leaves something consistent. diff --git a/visualc/VS2010/mbedTLS.vcxproj b/visualc/VS2010/mbedTLS.vcxproj index 15eb6b583..578289f17 100644 --- a/visualc/VS2010/mbedTLS.vcxproj +++ b/visualc/VS2010/mbedTLS.vcxproj @@ -232,6 +232,7 @@ +