1/** \file metatest.c 2 * 3 * \brief Test features of the test framework. 4 * 5 * When you run this program, it runs a single "meta-test". A meta-test 6 * performs an operation which should be caught as a failure by our 7 * test framework. The meta-test passes if this program calls `exit` with 8 * a nonzero status, or aborts, or is terminated by a signal, or if the 9 * framework running the program considers the run an error (this happens 10 * with Valgrind for a memory leak). The non-success of the meta-test 11 * program means that the test failure has been caught correctly. 12 * 13 * Some failures are purely functional: the logic of the code causes the 14 * test result to be set to FAIL. Other failures come from extra 15 * instrumentation which is not present in a normal build; for example, 16 * Asan or Valgrind to detect memory leaks. This is reflected by the 17 * "platform" associated with each meta-test. 18 * 19 * Use the companion script `tests/scripts/run-metatests.sh` to run all 20 * the meta-tests for a given platform and validate that they trigger a 21 * detected failure as expected. 22 */ 23 24/* 25 * Copyright The Mbed TLS Contributors 26 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 27 */ 28 29 30#include <mbedtls/debug.h> 31#include <mbedtls/platform.h> 32#include <mbedtls/platform_util.h> 33#include "test/helpers.h" 34#include "test/threading_helpers.h" 35#include "test/macros.h" 36#include "test/memory.h" 37#include "common.h" 38 39#include <stdio.h> 40#include <string.h> 41 42#if defined(MBEDTLS_THREADING_C) 43#include <mbedtls/threading.h> 44#endif 45 46 47/* This is an external variable, so the compiler doesn't know that we're never 48 * changing its value. 49 */ 50volatile int false_but_the_compiler_does_not_know = 0; 51 52/* Hide calls to calloc/free from static checkers such as 53 * `gcc-12 -Wuse-after-free`, to avoid compile-time complaints about 54 * code where we do mean to cause a runtime error. */ 55void * (* volatile calloc_but_the_compiler_does_not_know)(size_t, size_t) = mbedtls_calloc; 56void(*volatile free_but_the_compiler_does_not_know)(void *) = mbedtls_free; 57 58/* Set n bytes at the address p to all-bits-zero, in such a way that 59 * the compiler should not know that p is all-bits-zero. */ 60static void set_to_zero_but_the_compiler_does_not_know(volatile void *p, size_t n) 61{ 62 memset((void *) p, false_but_the_compiler_does_not_know, n); 63} 64 65/* Simulate an access to the given object, to avoid compiler optimizations 66 * in code that prepares or consumes the object. */ 67static void do_nothing_with_object(void *p) 68{ 69 (void) p; 70} 71void(*volatile do_nothing_with_object_but_the_compiler_does_not_know)(void *) = 72 do_nothing_with_object; 73 74 75/****************************************************************/ 76/* Test framework features */ 77/****************************************************************/ 78 79void meta_test_fail(const char *name) 80{ 81 (void) name; 82 mbedtls_test_fail("Forced test failure", __LINE__, __FILE__); 83} 84 85void meta_test_not_equal(const char *name) 86{ 87 int left = 20; 88 int right = 10; 89 90 (void) name; 91 92 TEST_EQUAL(left, right); 93exit: 94 ; 95} 96 97void meta_test_not_le_s(const char *name) 98{ 99 int left = 20; 100 int right = 10; 101 102 (void) name; 103 104 TEST_LE_S(left, right); 105exit: 106 ; 107} 108 109void meta_test_not_le_u(const char *name) 110{ 111 size_t left = 20; 112 size_t right = 10; 113 114 (void) name; 115 116 TEST_LE_U(left, right); 117exit: 118 ; 119} 120 121/****************************************************************/ 122/* Platform features */ 123/****************************************************************/ 124 125void null_pointer_dereference(const char *name) 126{ 127 (void) name; 128 volatile char *volatile p; 129 set_to_zero_but_the_compiler_does_not_know(&p, sizeof(p)); 130 /* Undefined behavior (read from null data pointer) */ 131 mbedtls_printf("%p -> %u\n", p, (unsigned) *p); 132} 133 134void null_pointer_call(const char *name) 135{ 136 (void) name; 137 unsigned(*volatile p)(void); 138 set_to_zero_but_the_compiler_does_not_know(&p, sizeof(p)); 139 /* Undefined behavior (execute null function pointer) */ 140 /* The pointer representation may be truncated, but we don't care: 141 * the only point of printing it is to have some use of the pointer 142 * to dissuade the compiler from optimizing it away. */ 143 mbedtls_printf("%lx() -> %u\n", (unsigned long) (uintptr_t) p, p()); 144} 145 146 147/****************************************************************/ 148/* Memory */ 149/****************************************************************/ 150 151void read_after_free(const char *name) 152{ 153 (void) name; 154 volatile char *p = calloc_but_the_compiler_does_not_know(1, 1); 155 *p = 'a'; 156 free_but_the_compiler_does_not_know((void *) p); 157 /* Undefined behavior (read after free) */ 158 mbedtls_printf("%u\n", (unsigned) *p); 159} 160 161void double_free(const char *name) 162{ 163 (void) name; 164 volatile char *p = calloc_but_the_compiler_does_not_know(1, 1); 165 *p = 'a'; 166 free_but_the_compiler_does_not_know((void *) p); 167 /* Undefined behavior (double free) */ 168 free_but_the_compiler_does_not_know((void *) p); 169} 170 171void read_uninitialized_stack(const char *name) 172{ 173 (void) name; 174 char buf[1]; 175 if (false_but_the_compiler_does_not_know) { 176 buf[0] = '!'; 177 } 178 char *volatile p = buf; 179 if (*p != 0) { 180 /* Unspecified result (read from uninitialized memory) */ 181 mbedtls_printf("%u\n", (unsigned) *p); 182 } 183} 184 185void memory_leak(const char *name) 186{ 187 (void) name; 188 volatile char *p = calloc_but_the_compiler_does_not_know(1, 1); 189 mbedtls_printf("%u\n", (unsigned) *p); 190 /* Leak of a heap object */ 191} 192 193/* name = "test_memory_poison_%(start)_%(offset)_%(count)_%(direction)" 194 * Poison a region starting at start from an 8-byte aligned origin, 195 * encompassing count bytes. Access the region at offset from the start. 196 * %(start), %(offset) and %(count) are decimal integers. 197 * %(direction) is either the character 'r' for read or 'w' for write. 198 */ 199void test_memory_poison(const char *name) 200{ 201 size_t start = 0, offset = 0, count = 0; 202 char direction = 'r'; 203 if (sscanf(name, 204 "%*[^0-9]%" MBEDTLS_PRINTF_SIZET 205 "%*[^0-9]%" MBEDTLS_PRINTF_SIZET 206 "%*[^0-9]%" MBEDTLS_PRINTF_SIZET 207 "_%c", 208 &start, &offset, &count, &direction) != 4) { 209 mbedtls_fprintf(stderr, "%s: Bad name format: %s\n", __func__, name); 210 return; 211 } 212 213 union { 214 long long ll; 215 unsigned char buf[32]; 216 } aligned; 217 memset(aligned.buf, 'a', sizeof(aligned.buf)); 218 219 if (start > sizeof(aligned.buf)) { 220 mbedtls_fprintf(stderr, 221 "%s: start=%" MBEDTLS_PRINTF_SIZET 222 " > size=%" MBEDTLS_PRINTF_SIZET, 223 __func__, start, sizeof(aligned.buf)); 224 return; 225 } 226 if (start + count > sizeof(aligned.buf)) { 227 mbedtls_fprintf(stderr, 228 "%s: start+count=%" MBEDTLS_PRINTF_SIZET 229 " > size=%" MBEDTLS_PRINTF_SIZET, 230 __func__, start + count, sizeof(aligned.buf)); 231 return; 232 } 233 if (offset >= count) { 234 mbedtls_fprintf(stderr, 235 "%s: offset=%" MBEDTLS_PRINTF_SIZET 236 " >= count=%" MBEDTLS_PRINTF_SIZET, 237 __func__, offset, count); 238 return; 239 } 240 241 MBEDTLS_TEST_MEMORY_POISON(aligned.buf + start, count); 242 243 if (direction == 'w') { 244 aligned.buf[start + offset] = 'b'; 245 do_nothing_with_object_but_the_compiler_does_not_know(aligned.buf); 246 } else { 247 do_nothing_with_object_but_the_compiler_does_not_know(aligned.buf); 248 mbedtls_printf("%u\n", (unsigned) aligned.buf[start + offset]); 249 } 250} 251 252 253/****************************************************************/ 254/* Threading */ 255/****************************************************************/ 256 257void mutex_lock_not_initialized(const char *name) 258{ 259 (void) name; 260#if defined(MBEDTLS_THREADING_C) 261 mbedtls_threading_mutex_t mutex; 262 memset(&mutex, 0, sizeof(mutex)); 263 /* This mutex usage error is detected by our test framework's mutex usage 264 * verification framework. See tests/src/threading_helpers.c. Other 265 * threading implementations (e.g. pthread without our instrumentation) 266 * might consider this normal usage. */ 267 TEST_ASSERT(mbedtls_mutex_lock(&mutex) == 0); 268exit: 269 ; 270#endif 271} 272 273void mutex_unlock_not_initialized(const char *name) 274{ 275 (void) name; 276#if defined(MBEDTLS_THREADING_C) 277 mbedtls_threading_mutex_t mutex; 278 memset(&mutex, 0, sizeof(mutex)); 279 /* This mutex usage error is detected by our test framework's mutex usage 280 * verification framework. See tests/src/threading_helpers.c. Other 281 * threading implementations (e.g. pthread without our instrumentation) 282 * might consider this normal usage. */ 283 TEST_ASSERT(mbedtls_mutex_unlock(&mutex) == 0); 284exit: 285 ; 286#endif 287} 288 289void mutex_free_not_initialized(const char *name) 290{ 291 (void) name; 292#if defined(MBEDTLS_THREADING_C) 293 mbedtls_threading_mutex_t mutex; 294 memset(&mutex, 0, sizeof(mutex)); 295 /* This mutex usage error is detected by our test framework's mutex usage 296 * verification framework. See tests/src/threading_helpers.c. Other 297 * threading implementations (e.g. pthread without our instrumentation) 298 * might consider this normal usage. */ 299 mbedtls_mutex_free(&mutex); 300#endif 301} 302 303void mutex_double_init(const char *name) 304{ 305 (void) name; 306#if defined(MBEDTLS_THREADING_C) 307 mbedtls_threading_mutex_t mutex; 308 mbedtls_mutex_init(&mutex); 309 /* This mutex usage error is detected by our test framework's mutex usage 310 * verification framework. See tests/src/threading_helpers.c. Other 311 * threading implementations (e.g. pthread without our instrumentation) 312 * might consider this normal usage. */ 313 mbedtls_mutex_init(&mutex); 314 mbedtls_mutex_free(&mutex); 315#endif 316} 317 318void mutex_double_free(const char *name) 319{ 320 (void) name; 321#if defined(MBEDTLS_THREADING_C) 322 mbedtls_threading_mutex_t mutex; 323 mbedtls_mutex_init(&mutex); 324 mbedtls_mutex_free(&mutex); 325 /* This mutex usage error is detected by our test framework's mutex usage 326 * verification framework. See tests/src/threading_helpers.c. Other 327 * threading implementations (e.g. pthread without our instrumentation) 328 * might consider this normal usage. */ 329 mbedtls_mutex_free(&mutex); 330#endif 331} 332 333void mutex_leak(const char *name) 334{ 335 (void) name; 336#if defined(MBEDTLS_THREADING_C) 337 mbedtls_threading_mutex_t mutex; 338 mbedtls_mutex_init(&mutex); 339#endif 340 /* This mutex usage error is detected by our test framework's mutex usage 341 * verification framework. See tests/src/threading_helpers.c. Other 342 * threading implementations (e.g. pthread without our instrumentation) 343 * might consider this normal usage. */ 344} 345 346 347/****************************************************************/ 348/* Command line entry point */ 349/****************************************************************/ 350 351typedef struct { 352 /** Command line argument that will trigger that metatest. 353 * 354 * Conventionally matches "[a-z0-9_]+". */ 355 const char *name; 356 357 /** Platform under which that metatest is valid. 358 * 359 * - "any": should work anywhere. 360 * - "asan": triggers ASan (Address Sanitizer). 361 * - "msan": triggers MSan (Memory Sanitizer). 362 * - "pthread": requires MBEDTLS_THREADING_PTHREAD and MBEDTLS_TEST_HOOKS, 363 * which enables MBEDTLS_TEST_MUTEX_USAGE internally in the test 364 * framework (see tests/src/threading_helpers.c). 365 */ 366 const char *platform; 367 368 /** Function that performs the metatest. 369 * 370 * The function receives the name as an argument. This allows using the 371 * same function to perform multiple variants of a test based on the name. 372 * 373 * When executed on a conforming platform, the function is expected to 374 * either cause a test failure (mbedtls_test_fail()), or cause the 375 * program to abort in some way (e.g. by causing a segfault or by 376 * triggering a sanitizer). 377 * 378 * When executed on a non-conforming platform, the function may return 379 * normally or may have unpredictable behavior. 380 */ 381 void (*entry_point)(const char *name); 382} metatest_t; 383 384/* The list of availble meta-tests. Remember to register new functions here! 385 * 386 * Note that we always compile all the functions, so that `metatest --list` 387 * will always list all the available meta-tests. 388 * 389 * See the documentation of metatest_t::platform for the meaning of 390 * platform values. 391 */ 392metatest_t metatests[] = { 393 { "test_fail", "any", meta_test_fail }, 394 { "test_not_equal", "any", meta_test_not_equal }, 395 { "test_not_le_s", "any", meta_test_not_le_s }, 396 { "test_not_le_u", "any", meta_test_not_le_u }, 397 { "null_dereference", "any", null_pointer_dereference }, 398 { "null_call", "any", null_pointer_call }, 399 { "read_after_free", "asan", read_after_free }, 400 { "double_free", "asan", double_free }, 401 { "read_uninitialized_stack", "msan", read_uninitialized_stack }, 402 { "memory_leak", "asan", memory_leak }, 403 { "test_memory_poison_0_0_8_r", "poison", test_memory_poison }, 404 { "test_memory_poison_0_0_8_w", "poison", test_memory_poison }, 405 { "test_memory_poison_0_7_8_r", "poison", test_memory_poison }, 406 { "test_memory_poison_0_7_8_w", "poison", test_memory_poison }, 407 { "test_memory_poison_0_0_1_r", "poison", test_memory_poison }, 408 { "test_memory_poison_0_0_1_w", "poison", test_memory_poison }, 409 { "test_memory_poison_0_1_2_r", "poison", test_memory_poison }, 410 { "test_memory_poison_0_1_2_w", "poison", test_memory_poison }, 411 { "test_memory_poison_7_0_8_r", "poison", test_memory_poison }, 412 { "test_memory_poison_7_0_8_w", "poison", test_memory_poison }, 413 { "test_memory_poison_7_7_8_r", "poison", test_memory_poison }, 414 { "test_memory_poison_7_7_8_w", "poison", test_memory_poison }, 415 { "test_memory_poison_7_0_1_r", "poison", test_memory_poison }, 416 { "test_memory_poison_7_0_1_w", "poison", test_memory_poison }, 417 { "test_memory_poison_7_1_2_r", "poison", test_memory_poison }, 418 { "test_memory_poison_7_1_2_w", "poison", test_memory_poison }, 419 { "mutex_lock_not_initialized", "pthread", mutex_lock_not_initialized }, 420 { "mutex_unlock_not_initialized", "pthread", mutex_unlock_not_initialized }, 421 { "mutex_free_not_initialized", "pthread", mutex_free_not_initialized }, 422 { "mutex_double_init", "pthread", mutex_double_init }, 423 { "mutex_double_free", "pthread", mutex_double_free }, 424 { "mutex_leak", "pthread", mutex_leak }, 425 { NULL, NULL, NULL } 426}; 427 428static void help(FILE *out, const char *argv0) 429{ 430 mbedtls_fprintf(out, "Usage: %s list|TEST\n", argv0); 431 mbedtls_fprintf(out, "Run a meta-test that should cause a test failure.\n"); 432 mbedtls_fprintf(out, "With 'list', list the available tests and their platform requirement.\n"); 433} 434 435int main(int argc, char *argv[]) 436{ 437 const char *argv0 = argc > 0 ? argv[0] : "metatest"; 438 if (argc != 2) { 439 help(stderr, argv0); 440 mbedtls_exit(MBEDTLS_EXIT_FAILURE); 441 } 442 443 /* Support "-help", "--help", "--list", etc. */ 444 const char *command = argv[1]; 445 while (*command == '-') { 446 ++command; 447 } 448 449 if (strcmp(argv[1], "help") == 0) { 450 help(stdout, argv0); 451 mbedtls_exit(MBEDTLS_EXIT_SUCCESS); 452 } 453 if (strcmp(argv[1], "list") == 0) { 454 for (const metatest_t *p = metatests; p->name != NULL; p++) { 455 mbedtls_printf("%s %s\n", p->name, p->platform); 456 } 457 mbedtls_exit(MBEDTLS_EXIT_SUCCESS); 458 } 459 460#if defined(MBEDTLS_TEST_MUTEX_USAGE) 461 mbedtls_test_mutex_usage_init(); 462#endif 463 464 for (const metatest_t *p = metatests; p->name != NULL; p++) { 465 if (strcmp(argv[1], p->name) == 0) { 466 mbedtls_printf("Running metatest %s...\n", argv[1]); 467 p->entry_point(argv[1]); 468#if defined(MBEDTLS_TEST_MUTEX_USAGE) 469 mbedtls_test_mutex_usage_check(); 470#endif 471 int result = (int) mbedtls_test_get_result(); 472 473 mbedtls_printf("Running metatest %s... done, result=%d\n", 474 argv[1], result); 475 mbedtls_exit(result == MBEDTLS_TEST_RESULT_SUCCESS ? 476 MBEDTLS_EXIT_SUCCESS : 477 MBEDTLS_EXIT_FAILURE); 478 } 479 } 480 481 mbedtls_fprintf(stderr, "%s: FATAL: No such metatest: %s\n", 482 argv0, command); 483 mbedtls_exit(MBEDTLS_EXIT_FAILURE); 484} 485