blob: eb3bb76aff5a355e0730be0120b7825e66c81cc9 [file] [log] [blame]
Gilles Peskine33406b62023-11-02 18:48:39 +01001/** \file metatest.c
2 *
3 * \brief Test features of the test framework.
4 */
5
6/*
7 * Copyright The Mbed TLS Contributors
8 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
9 */
10
11#define MBEDTLS_ALLOW_PRIVATE_ACCESS
12
13#include <mbedtls/platform.h>
Gilles Peskine69e8db02023-11-02 19:52:32 +010014#include <mbedtls/platform_util.h>
Gilles Peskine33406b62023-11-02 18:48:39 +010015#include "test/helpers.h"
16
17#include <stdio.h>
18#include <string.h>
19
20
Gilles Peskine69e8db02023-11-02 19:52:32 +010021/* This is an external variable, so the compiler doesn't know that we're never
22 * changing its value.
23 *
24 * TODO: LTO (link-time-optimization) would defeat this.
25 */
26int false_but_the_compiler_does_not_know = 0;
27
28
Gilles Peskine33406b62023-11-02 18:48:39 +010029/****************************************************************/
Gilles Peskinef309fbf2023-11-02 18:49:52 +010030/* Test framework features */
31/****************************************************************/
32
33void meta_test_fail(const char *name)
34{
35 (void) name;
36 mbedtls_test_fail("Forced test failure", __LINE__, __FILE__);
37}
38
39
40/****************************************************************/
Gilles Peskine80ba8322023-11-02 19:23:26 +010041/* Platform features */
42/****************************************************************/
43
44void null_pointer_dereference(const char *name)
45{
46 (void) name;
Gilles Peskine69e8db02023-11-02 19:52:32 +010047 volatile char *p;
48 mbedtls_platform_zeroize(&p, sizeof(p));
49 mbedtls_printf("%p -> %u\n", p, (unsigned) *p);
Gilles Peskine80ba8322023-11-02 19:23:26 +010050}
51
52void null_pointer_call(const char *name)
53{
54 (void) name;
Gilles Peskine69e8db02023-11-02 19:52:32 +010055 unsigned (*p)(void);
56 mbedtls_platform_zeroize(&p, sizeof(p));
57 mbedtls_printf("%p() -> %u\n", p, p());
Gilles Peskine80ba8322023-11-02 19:23:26 +010058}
59
60
61/****************************************************************/
Gilles Peskineb0f0a642023-11-02 19:42:13 +010062/* Sanitizers */
63/****************************************************************/
64
65void read_after_free(const char *name)
66{
67 (void) name;
68 volatile char *p = mbedtls_calloc(1, 1);
69 *p = 'a';
70 mbedtls_free((void *) p);
71 mbedtls_printf("%u\n", (unsigned) *p);
72}
73
74void double_free(const char *name)
75{
76 (void) name;
77 volatile char *p = mbedtls_calloc(1, 1);
78 *p = 'a';
79 mbedtls_free((void *) p);
80 mbedtls_free((void *) p);
81}
82
83void read_uninitialized_stack(const char *name)
84{
85 (void) name;
86 volatile char buf[1];
Gilles Peskineb0f0a642023-11-02 19:42:13 +010087 if (false_but_the_compiler_does_not_know) {
88 buf[0] = '!';
89 }
90 if (*buf != 0) {
91 mbedtls_printf("%u\n", (unsigned) *buf);
92 }
93}
94
95void memory_leak(const char *name)
96{
97 (void) name;
98 volatile char *p = mbedtls_calloc(1, 1);
99 /* Hint to the compiler that calloc must not be optimized away. */
100 (void) *p;
101}
102
103
104/****************************************************************/
Gilles Peskine33406b62023-11-02 18:48:39 +0100105/* Command line entry point */
106/****************************************************************/
107
108typedef struct {
109 const char *name;
110 const char *platform;
111 void (*entry_point)(const char *name);
112} metatest_t;
113
114metatest_t metatests[] = {
Gilles Peskinef309fbf2023-11-02 18:49:52 +0100115 { "test_fail", "any", meta_test_fail },
Gilles Peskine80ba8322023-11-02 19:23:26 +0100116 { "null_dereference", "any", null_pointer_dereference },
117 { "null_call", "any", null_pointer_call },
Gilles Peskineb0f0a642023-11-02 19:42:13 +0100118 { "read_after_free", "asan", read_after_free },
119 { "double_free", "asan", double_free },
120 { "read_uninitialized_stack", "msan", read_uninitialized_stack },
121 { "memory_leak", "asan", memory_leak },
Gilles Peskine33406b62023-11-02 18:48:39 +0100122 { NULL, NULL, NULL }
123};
124
125static void help(FILE *out, const char *argv0)
126{
127 mbedtls_fprintf(out, "Usage: %s list|TEST\n", argv0);
128 mbedtls_fprintf(out, "Run a meta-test that should cause a test failure.\n");
129 mbedtls_fprintf(out, "With 'list', list the available tests and their platform requirement.\n");
130}
131
132int main(int argc, char *argv[])
133{
134 const char *argv0 = argc > 0 ? argv[0] : "metatest";
135 if (argc != 2) {
136 help(stderr, argv0);
137 mbedtls_exit(MBEDTLS_EXIT_FAILURE);
138 }
139
140 /* Support "-help", "--help", "--list", etc. */
141 const char *command = argv[1];
142 while (*command == '-') {
143 ++command;
144 }
145
146 if (strcmp(argv[1], "help") == 0) {
147 help(stdout, argv0);
148 mbedtls_exit(MBEDTLS_EXIT_SUCCESS);
149 }
150 if (strcmp(argv[1], "list") == 0) {
151 for (const metatest_t *p = metatests; p->name != NULL; p++) {
152 mbedtls_printf("%s %s\n", p->name, p->platform);
153 }
154 mbedtls_exit(MBEDTLS_EXIT_SUCCESS);
155 }
156
157 for (const metatest_t *p = metatests; p->name != NULL; p++) {
158 if (strcmp(argv[1], p->name) == 0) {
159 mbedtls_printf("Running metatest %s...\n", argv[1]);
160 p->entry_point(argv[1]);
161 mbedtls_printf("Running metatest %s... done, result=%d\n",
162 argv[1], (int) mbedtls_test_info.result);
163 mbedtls_exit(mbedtls_test_info.result == MBEDTLS_TEST_RESULT_SUCCESS ?
164 MBEDTLS_EXIT_SUCCESS :
165 MBEDTLS_EXIT_FAILURE);
166 }
167 }
168
169 mbedtls_fprintf(stderr, "%s: FATAL: No such metatest: %s\n",
170 argv0, command);
171 mbedtls_exit(MBEDTLS_EXIT_FAILURE);
172}