diff --git a/ChangeLog.d/unistd.txt b/ChangeLog.d/unistd.txt new file mode 100644 index 0000000000..84afdc315f --- /dev/null +++ b/ChangeLog.d/unistd.txt @@ -0,0 +1,6 @@ +Changes + * Tweak the detection of Unix-like platforms, which makes more system + interfaces (timing, threading) available on Haiku, QNX and Midipix. + +Bugfix + * Fix a build failure with dietlibc. diff --git a/framework b/framework index 8ed11c99fe..bd6dfd6d8a 160000 --- a/framework +++ b/framework @@ -1 +1 @@ -Subproject commit 8ed11c99fe9e6d4d96289ebc1e134949421be917 +Subproject commit bd6dfd6d8af59ccd6ea24fcc37565809bd2c8cc7 diff --git a/library/common.h b/library/common.h index c5cd241e7a..1f59b32426 100644 --- a/library/common.h +++ b/library/common.h @@ -27,6 +27,24 @@ #define MBEDTLS_HAVE_NEON_INTRINSICS #endif +/* Decide whether we're built for a Unix-like platform. + */ +#if defined(MBEDTLS_TEST_PLATFORM_IS_NOT_UNIXLIKE) //no-check-names +/* We may be building on a Unix-like platform, but for test purposes, + * do not try to use Unix features. */ +#elif defined(_WIN32) +/* If Windows platform interfaces are available, we use them, even if + * a Unix-like might also to be available. */ +/* defined(_WIN32) ==> we can include */ +#elif defined(unix) || defined(__unix) || defined(__unix__) || \ + (defined(__APPLE__) && defined(__MACH__)) || \ + defined(__HAIKU__) || \ + defined(__midipix__) || \ + /* Add other Unix-like platform indicators here ^^^^ */ 0 +/* defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) ==> we can include */ +#define MBEDTLS_PLATFORM_IS_UNIXLIKE +#endif + /** Helper to define a function as static except when building invasive tests. * * If a function is only used inside its own source file and should be diff --git a/library/debug.c b/library/debug.c index c36ed3c5c2..24c6253c40 100644 --- a/library/debug.c +++ b/library/debug.c @@ -21,6 +21,16 @@ /* DEBUG_BUF_SIZE must be at least 2 */ #define DEBUG_BUF_SIZE 512 +int mbedtls_debug_snprintf(char *dest, size_t maxlen, + const char *format, ...) +{ + va_list argp; + va_start(argp, format); + int ret = mbedtls_vsnprintf(dest, maxlen, format, argp); + va_end(argp); + return ret; +} + static int debug_threshold = 0; void mbedtls_debug_set_threshold(int threshold) diff --git a/library/debug_internal.h b/library/debug_internal.h index 4523b4633a..2dd2599c1c 100644 --- a/library/debug_internal.h +++ b/library/debug_internal.h @@ -12,6 +12,19 @@ #include "mbedtls/debug.h" +/* This should be equivalent to mbedtls_snprintf(). But it might not be due + * to platform shenanigans. For example, Mbed TLS and TF-PSA-Crypto could + * have inconsistent platform definitions. On Mingw, some code might + * be built with a different setting of __USE_MINGW_ANSI_STDIO, resulting + * in an old non-C99 printf being used somewhere. + * + * Our library assumes that mbedtls_snprintf() and other printf functions + * are consistent throughout. This function is not an official API and + * is not meant to be used inside the library. It is provided to help + * debugging printf inconsistencies issues. If you need it, good luck! + */ +int mbedtls_debug_snprintf(char *dest, size_t maxlen, + const char *format, ...) MBEDTLS_PRINTF_ATTRIBUTE(3, 4); /** * \brief Print a message to the debug output. This function is always used * through the MBEDTLS_SSL_DEBUG_MSG() macro, which supplies the ssl diff --git a/library/net_sockets.c b/library/net_sockets.c index 1419c787b9..c919f6f574 100644 --- a/library/net_sockets.c +++ b/library/net_sockets.c @@ -19,9 +19,7 @@ #if defined(MBEDTLS_NET_C) -#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ - !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ - !defined(__HAIKU__) && !defined(__midipix__) +#if !defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) && !defined(_WIN32) #error "This module only works on Unix and Windows, see MBEDTLS_NET_C in mbedtls_config.h" #endif diff --git a/library/platform_util.c b/library/platform_util.c index 19ef07aead..1cab42ffc0 100644 --- a/library/platform_util.c +++ b/library/platform_util.c @@ -147,12 +147,9 @@ void mbedtls_zeroize_and_free(void *buf, size_t len) #if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT) #include -#if !defined(_WIN32) && (defined(unix) || \ - defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \ - defined(__MACH__)) || defined(__midipix__)) +#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) #include -#endif /* !_WIN32 && (unix || __unix || __unix__ || - * (__APPLE__ && __MACH__) || __midipix__) */ +#endif #if !((defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L) || \ (defined(_POSIX_THREAD_SAFE_FUNCTIONS) && \ @@ -218,12 +215,10 @@ void (*mbedtls_test_hook_test_fail)(const char *, int, const char *); #if defined(MBEDTLS_HAVE_TIME) && !defined(MBEDTLS_PLATFORM_MS_TIME_ALT) #include -#if !defined(_WIN32) && \ - (defined(unix) || defined(__unix) || defined(__unix__) || \ - (defined(__APPLE__) && defined(__MACH__)) || defined(__HAIKU__) || defined(__midipix__)) +#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) #include -#endif \ - /* !_WIN32 && (unix || __unix || __unix__ || (__APPLE__ && __MACH__) || __HAIKU__ || __midipix__) */ +#endif + #if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 199309L) || defined(__HAIKU__) mbedtls_ms_time_t mbedtls_ms_time(void) { diff --git a/library/threading.c b/library/threading.c index ff8183ed15..8764b3edce 100644 --- a/library/threading.c +++ b/library/threading.c @@ -21,9 +21,7 @@ #if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT) -#if !defined(_WIN32) && (defined(unix) || \ - defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \ - defined(__MACH__))) +#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) #include #endif /* !_WIN32 && (unix || __unix || __unix__ || * (__APPLE__ && __MACH__)) */ diff --git a/library/timing.c b/library/timing.c index 58f1c1ec2e..e3e9da52ef 100644 --- a/library/timing.c +++ b/library/timing.c @@ -13,9 +13,7 @@ #if !defined(MBEDTLS_TIMING_ALT) -#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ - !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ - !defined(__HAIKU__) && !defined(__midipix__) +#if !defined(_WIN32) && !defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) #error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in mbedtls_config.h" #endif diff --git a/tests/scripts/components-configuration-crypto.sh b/tests/scripts/components-configuration-crypto.sh index bb4608acca..47dd20450e 100644 --- a/tests/scripts/components-configuration-crypto.sh +++ b/tests/scripts/components-configuration-crypto.sh @@ -882,7 +882,7 @@ component_test_crypto_for_psa_service () { component_build_crypto_baremetal () { msg "build: make, crypto only, baremetal config" scripts/config.py crypto_baremetal - make CFLAGS="-O1 -Werror -I$PWD/framework/tests/include/baremetal-override/" + make CFLAGS="-O1 -Werror -I$PWD/framework/tests/include/baremetal-override/ -DMBEDTLS_TEST_PLATFORM_IS_NOT_UNIXLIKE" are_empty_libraries library/libmbedx509.* library/libmbedtls.* } diff --git a/tests/scripts/components-configuration.sh b/tests/scripts/components-configuration.sh index 72e7a86e3d..db9b5740e4 100644 --- a/tests/scripts/components-configuration.sh +++ b/tests/scripts/components-configuration.sh @@ -222,7 +222,7 @@ component_test_full_deprecated_warning () { component_build_baremetal () { msg "build: make, baremetal config" scripts/config.py baremetal - make CFLAGS="-O1 -Werror -I$PWD/framework/tests/include/baremetal-override/" + make CFLAGS="-O1 -Werror -I$PWD/framework/tests/include/baremetal-override/ -DMBEDTLS_TEST_PLATFORM_IS_NOT_UNIXLIKE" } support_build_baremetal () { diff --git a/tests/suites/host_test.function b/tests/suites/host_test.function index d28a75e077..90b050e129 100644 --- a/tests/suites/host_test.function +++ b/tests/suites/host_test.function @@ -275,7 +275,12 @@ static int convert_params(size_t cnt, char **params, * \return 0 for success else 1 */ #if defined(__GNUC__) +# if defined(__dietlibc__) +/* __noinline__ is a macro in dietlibc... */ +__attribute__((noinline)) +# else __attribute__((__noinline__)) +# endif #endif static int test_snprintf(size_t n, const char *ref_buf, int ref_ret) { diff --git a/tests/suites/main_test.function b/tests/suites/main_test.function index c0cc2ac50b..0121f826c7 100644 --- a/tests/suites/main_test.function +++ b/tests/suites/main_test.function @@ -23,6 +23,17 @@ #endif #endif +#if defined(__FreeBSD__) +/* On FreeBSD as of 14.3, no value of _POSIX_C_SOURCE is enough for + * gettimeofday(), you need _XOPEN_SOURCE (any value). + * Furthermore, setting _XOPEN_SOURCE to 500 removes support for long long + * in libc, so you need at least 600 for e.g. strtoull(). + */ +#if !defined(_XOPEN_SOURCE) +#define _XOPEN_SOURCE 600 +#endif +#endif + #include "mbedtls/build_info.h" /* Test code may use deprecated identifiers only if the preprocessor symbol diff --git a/tests/suites/test_suite_debug.function b/tests/suites/test_suite_debug.function index 9e53107626..df0ce4c987 100644 --- a/tests/suites/test_suite_debug.function +++ b/tests/suites/test_suite_debug.function @@ -113,11 +113,11 @@ void printf_int_expr(int format_indicator, intmax_t sizeof_x, intmax_t x, char * /* Nominal case: buffer just large enough */ TEST_CALLOC(output, n + 1); if ((size_t) sizeof_x <= sizeof(int)) { // Any smaller integers would be promoted to an int due to calling a vararg function - TEST_EQUAL(n, mbedtls_snprintf(output, n + 1, format, (int) x)); + TEST_EQUAL(n, mbedtls_debug_snprintf(output, n + 1, format, (int) x)); } else if (sizeof_x == sizeof(long)) { - TEST_EQUAL(n, mbedtls_snprintf(output, n + 1, format, (long) x)); + TEST_EQUAL(n, mbedtls_debug_snprintf(output, n + 1, format, (long) x)); } else if (sizeof_x == sizeof(long long)) { - TEST_EQUAL(n, mbedtls_snprintf(output, n + 1, format, (long long) x)); + TEST_EQUAL(n, mbedtls_debug_snprintf(output, n + 1, format, (long long) x)); } else { TEST_FAIL( "sizeof_x <= sizeof(int) || sizeof_x == sizeof(long) || sizeof_x == sizeof(long long)"); diff --git a/tests/suites/test_suite_platform.function b/tests/suites/test_suite_platform.function index 5d49e52e45..6c967fa8dc 100644 --- a/tests/suites/test_suite_platform.function +++ b/tests/suites/test_suite_platform.function @@ -127,7 +127,7 @@ void check_mbedtls_calloc_overallocation(intmax_t num, intmax_t size) unsigned char *buf; buf = mbedtls_calloc((size_t) num, (size_t) size); /* Dummy usage of the pointer to prevent optimizing it */ - mbedtls_printf("calloc pointer : %p\n", buf); + mbedtls_printf("calloc pointer : %p\n", (void *) buf); TEST_ASSERT(buf == NULL); exit: diff --git a/tests/suites/test_suite_platform_printf.data b/tests/suites/test_suite_platform_printf.data index 891771b919..a359e8c581 100644 --- a/tests/suites/test_suite_platform_printf.data +++ b/tests/suites/test_suite_platform_printf.data @@ -3,58 +3,86 @@ # and strings through the test framework. printf "%d", 0 -printf_int:"%d":0:"0" +printf_integer:"%d":PRINTF_CAST_INT:0:"0" printf "%d", -0 -printf_int:"%d":-0:"0" +printf_integer:"%d":PRINTF_CAST_INT:-0:"0" printf "%d", 0x0 -printf_int:"%d":0x0:"0" +printf_integer:"%d":PRINTF_CAST_INT:0x0:"0" printf "%d", 0x00 -printf_int:"%d":0x00:"0" +printf_integer:"%d":PRINTF_CAST_INT:0x00:"0" printf "%d", 0x000000000000000000000000000000000000000000 -printf_int:"%d":0x000000000000000000000000000000000000000000:"0" +printf_integer:"%d":PRINTF_CAST_INT:0x000000000000000000000000000000000000000000:"0" printf "%d", -0x0 -printf_int:"%d":-0x0:"0" +printf_integer:"%d":PRINTF_CAST_INT:-0x0:"0" printf "%d", 1 -printf_int:"%d":1:"1" +printf_integer:"%d":PRINTF_CAST_INT:1:"1" printf "%d", 0x1 -printf_int:"%d":0x1:"1" +printf_integer:"%d":PRINTF_CAST_INT:0x1:"1" printf "%d", 0x0000000000000000000000000000000000000000001 -printf_int:"%d":0x0000000000000000000000000000000000000000001:"1" +printf_integer:"%d":PRINTF_CAST_INT:0x0000000000000000000000000000000000000000001:"1" printf "%d", -1 -printf_int:"%d":-1:"-1" +printf_integer:"%d":PRINTF_CAST_INT:-1:"-1" printf "%d", -0x1 -printf_int:"%d":-0x1:"-1" +printf_integer:"%d":PRINTF_CAST_INT:-0x1:"-1" printf "%d", -0x0000000000000000000000000000000000000000001 -printf_int:"%d":-0x0000000000000000000000000000000000000000001:"-1" +printf_integer:"%d":PRINTF_CAST_INT:-0x0000000000000000000000000000000000000000001:"-1" printf "%d", 2147483647 -printf_int:"%d":2147483647:"2147483647" +printf_integer:"%d":PRINTF_CAST_INT:2147483647:"2147483647" printf "%d", 0x7fffffff -printf_int:"%d":0x7fffffff:"2147483647" +printf_integer:"%d":PRINTF_CAST_INT:0x7fffffff:"2147483647" printf "%d", -2147483647 -printf_int:"%d":-2147483647:"-2147483647" +printf_integer:"%d":PRINTF_CAST_INT:-2147483647:"-2147483647" printf "%d", -0x7fffffff -printf_int:"%d":-0x7fffffff:"-2147483647" +printf_integer:"%d":PRINTF_CAST_INT:-0x7fffffff:"-2147483647" printf "%d", -2147483648 -printf_int:"%d":-2147483648:"-2147483648" +printf_integer:"%d":PRINTF_CAST_INT:-2147483648:"-2147483648" printf "%d", -0x80000000 -printf_int:"%d":-0x80000000:"-2147483648" +printf_integer:"%d":PRINTF_CAST_INT:-0x80000000:"-2147483648" + +printf "%u", 0x80000000 +printf_integer:"%u":PRINTF_CAST_INT:-0x80000000:"2147483648" + +printf "%zx", 0x12345678 +depends_on:HAVE_C99_PRINTF +printf_integer:"%zx":PRINTF_CAST_SIZE_T:0x12345678:"12345678" + +printf "%zu", 0x80000000 +depends_on:HAVE_C99_PRINTF +printf_integer:"%zu":PRINTF_CAST_SIZE_T:0x80000000:"2147483648" + +printf "%zx", 0xffffffff +depends_on:HAVE_C99_PRINTF +printf_integer:"%zx":PRINTF_CAST_SIZE_T:0xffffffff:"ffffffff" + +printf "%zx", 0xffffffffffffffff +depends_on:HAVE_C99_PRINTF:SIZE_T_AT_LEAST_64_BIT +printf_integer:"%zx":PRINTF_CAST_SIZE_T:0xffffffffffffffff:"ffffffffffffffff" + +printf "%lld", 0x7fffffffffffffff +printf_integer:"%lld":PRINTF_CAST_LONG_LONG:0x7fffffffffffffff:"9223372036854775807" + +printf "%lld", -0x8000000000000000 +printf_integer:"%lld":PRINTF_CAST_LONG_LONG:-0x8000000000000000:"-9223372036854775808" + +printf "%llx", 0x102030405060708 +printf_integer:"%llx":PRINTF_CAST_UNSIGNED_LONG_LONG:0x0102030405060708:"102030405060708" # Test that LONG_MAX is coming out untruncated through the test framework. printf "%lx", LONG_MAX diff --git a/tests/suites/test_suite_platform_printf.function b/tests/suites/test_suite_platform_printf.function index 643accf1f7..5a132b7954 100644 --- a/tests/suites/test_suite_platform_printf.function +++ b/tests/suites/test_suite_platform_printf.function @@ -15,6 +15,34 @@ #include #include +#if SIZE_MAX >= 0xffffffffffffffff +#define SIZE_T_AT_LEAST_64_BIT +#endif + +/* Older Windows runtimes have a non-compliant printf family, e.g. + * it doesn't understand `%zu` to print a `size_t`. MSVC provides a + * C99-compliant printf family (at least enough for our purposes), + * since Visual Studio 2015. With MinGW, you get the non-compliant legacy + * printf by default, but can select the standard-compliant version + * at compile time. In the Mbed TLS 3.6 LTS, we use the default, so + * we can't rely on %z being understood. The debug module defines + * `MBEDTLS_PRINTF_SIZET` for that, and this is tested in test_suite_debug. + * Here we just skip the test cases that break the legacy Windows printf. + */ +#if !(defined(__MINGW32__)) +#define HAVE_C99_PRINTF +#endif + +typedef enum { + PRINTF_CAST_INT, + PRINTF_CAST_UNSIGNED, + PRINTF_CAST_SIZE_T, + PRINTF_CAST_LONG, + PRINTF_CAST_UNSIGNED_LONG, + PRINTF_CAST_LONG_LONG, + PRINTF_CAST_UNSIGNED_LONG_LONG, +} printf_cast_type_t; + #define NEWLINE_CHAR '\n' #define SPACE_CHAR ' ' #define DOUBLE_QUOTE_CHAR '"' @@ -22,18 +50,41 @@ #define QUESTION_CHAR '?' #define BACKSLASH_CHAR '\\' #define LOWERCASE_N_CHAR 'n' + /* END_HEADER */ /* BEGIN_CASE */ -void printf_int(char *format, /* any format expecting one int argument, e.g. "%d" */ - int x, char *result) +void printf_integer(char *format, /* format expecting one foo_t argument */ + int type, /* enum value from printf_cast_type_t */ + intmax_t value, + char *result) { char *output = NULL; const size_t n = strlen(result); + int ret = 0; /* Nominal case: buffer just large enough */ TEST_CALLOC(output, n + 1); - TEST_EQUAL(n, mbedtls_snprintf(output, n + 1, format, x)); + switch (type) { + case PRINTF_CAST_INT: + ret = mbedtls_snprintf(output, n + 1, format, (int) value); + break; + case PRINTF_CAST_UNSIGNED: + ret = mbedtls_snprintf(output, n + 1, format, (unsigned) value); + break; + case PRINTF_CAST_SIZE_T: + ret = mbedtls_snprintf(output, n + 1, format, (size_t) value); + break; + case PRINTF_CAST_LONG_LONG: + ret = mbedtls_snprintf(output, n + 1, format, (long long) value); + break; + case PRINTF_CAST_UNSIGNED_LONG_LONG: + ret = mbedtls_snprintf(output, n + 1, format, (unsigned long long) value); + break; + default: + TEST_FAIL("Unsupported type"); + } + TEST_EQUAL(n, ret); TEST_MEMORY_COMPARE(result, n + 1, output, n + 1); mbedtls_free(output); output = NULL; diff --git a/tests/suites/test_suite_platform_unix.data b/tests/suites/test_suite_platform_unix.data new file mode 100644 index 0000000000..adb90fe80c --- /dev/null +++ b/tests/suites/test_suite_platform_unix.data @@ -0,0 +1,16 @@ + smoke test +unistd_available: + +# At the time of writing, we don't actually use CLOCK_REALTIME. +# But it's the only clock that's guaranteed by POSIX. +clock_gettime(CLOCK_REALTIME) smoke test +clock_gettime_available:CLOCK_REALTIME + +# Used for mbedtls_ms_time() on platforms where we don't think +# CLOCK_BOOTTIME is available. +clock_gettime(CLOCK_MONOTONIC) smoke test +clock_gettime_available:CLOCK_MONOTONIC + +# Used in library/timing.c and programs/test/benchmark.c +gettimeofday() smoke test +gettimeofday_available: diff --git a/tests/suites/test_suite_platform_unix.function b/tests/suites/test_suite_platform_unix.function new file mode 100644 index 0000000000..6646815962 --- /dev/null +++ b/tests/suites/test_suite_platform_unix.function @@ -0,0 +1,68 @@ +/* BEGIN_HEADER */ +/* Test access to the Unix primitives used in platform_util.c and elsewhere. + * We aren't testing that they work, just getting an easy-to-understand + * diagnostic if they aren't available. + * (There is a separate test suite for the platform_util.h interfacces.) + */ + +#include +#include +#include "common.h" + +#if defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) + +#include +#include +#include + +#else /* defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) */ + +/* Constants used in the test data need to be defined even if no test + * functions that use them are enabled. + * Undefine the macros first in case a system header does define them + * even though we haven't recognized the platform as Unix-like. */ +#undef CLOCK_REALTIME +#define CLOCK_REALTIME 0 +#undef CLOCK_MONOTONIC +#define CLOCK_MONOTONIC 0 + +#endif /* defined(MBEDTLS_PLATFORM_IS_UNIXLIKE) */ + +/* END_HEADER */ + +/* Note: we can't make the whole test suite depend on + * MBEDTLS_PLATFORM_IS_UNIXLIKE, because file-level dependencies can only + * come from build_info.h, platform.h or some test helper headers, not + * from internal macros. */ +/* BEGIN_DEPENDENCIES + * END_DEPENDENCIES */ + +/* BEGIN_CASE depends_on:MBEDTLS_PLATFORM_IS_UNIXLIKE */ +void unistd_available() +{ + pid_t pid = getpid(); + TEST_LE_S(1, pid); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_PLATFORM_IS_UNIXLIKE */ +void clock_gettime_available(int clockid) +{ + struct timespec ts = { 0, 0 }; + memset(&ts, 0, sizeof(ts)); + int ret = clock_gettime(clockid, &ts); + TEST_ASSERT_ERRNO(ret == 0); + TEST_ASSERT(ts.tv_sec != 0 || ts.tv_nsec != 0); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_PLATFORM_IS_UNIXLIKE */ +void gettimeofday_available() +{ + struct timeval tv = { 0, 0 }; + memset(&tv, 0, sizeof(tv)); + int ret = gettimeofday(&tv, NULL); + TEST_ASSERT_ERRNO(ret == 0); + TEST_LE_S(1, tv.tv_sec); +} +/* END_CASE */