blob: d3173f3d4093b9841308030676715c8163bbd29d [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;
Gilles Peskine6aa9f322023-11-02 21:31:07 +010048 mbedtls_platform_zeroize((void *) &p, sizeof(p));
Gilles Peskine69e8db02023-11-02 19:52:32 +010049 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));
Gilles Peskinef0d5cf92023-11-03 10:58:57 +010057 /* The pointer representation may be truncated, but we don't care:
58 * the only point of printing it is to have some use of the pointer
59 * to dissuade the compiler from optimizing it away. */
60 mbedtls_printf("%lx() -> %u\n", (unsigned long) (uintptr_t) p, p());
Gilles Peskine80ba8322023-11-02 19:23:26 +010061}
62
63
64/****************************************************************/
Gilles Peskineb0f0a642023-11-02 19:42:13 +010065/* Sanitizers */
66/****************************************************************/
67
68void read_after_free(const char *name)
69{
70 (void) name;
71 volatile char *p = mbedtls_calloc(1, 1);
72 *p = 'a';
73 mbedtls_free((void *) p);
74 mbedtls_printf("%u\n", (unsigned) *p);
75}
76
77void double_free(const char *name)
78{
79 (void) name;
80 volatile char *p = mbedtls_calloc(1, 1);
81 *p = 'a';
82 mbedtls_free((void *) p);
83 mbedtls_free((void *) p);
84}
85
86void read_uninitialized_stack(const char *name)
87{
88 (void) name;
89 volatile char buf[1];
Gilles Peskineb0f0a642023-11-02 19:42:13 +010090 if (false_but_the_compiler_does_not_know) {
91 buf[0] = '!';
92 }
93 if (*buf != 0) {
94 mbedtls_printf("%u\n", (unsigned) *buf);
95 }
96}
97
98void memory_leak(const char *name)
99{
100 (void) name;
101 volatile char *p = mbedtls_calloc(1, 1);
102 /* Hint to the compiler that calloc must not be optimized away. */
103 (void) *p;
104}
105
106
107/****************************************************************/
Gilles Peskine33406b62023-11-02 18:48:39 +0100108/* Command line entry point */
109/****************************************************************/
110
111typedef struct {
112 const char *name;
113 const char *platform;
114 void (*entry_point)(const char *name);
115} metatest_t;
116
117metatest_t metatests[] = {
Gilles Peskinef309fbf2023-11-02 18:49:52 +0100118 { "test_fail", "any", meta_test_fail },
Gilles Peskine80ba8322023-11-02 19:23:26 +0100119 { "null_dereference", "any", null_pointer_dereference },
120 { "null_call", "any", null_pointer_call },
Gilles Peskineb0f0a642023-11-02 19:42:13 +0100121 { "read_after_free", "asan", read_after_free },
122 { "double_free", "asan", double_free },
123 { "read_uninitialized_stack", "msan", read_uninitialized_stack },
124 { "memory_leak", "asan", memory_leak },
Gilles Peskine33406b62023-11-02 18:48:39 +0100125 { NULL, NULL, NULL }
126};
127
128static void help(FILE *out, const char *argv0)
129{
130 mbedtls_fprintf(out, "Usage: %s list|TEST\n", argv0);
131 mbedtls_fprintf(out, "Run a meta-test that should cause a test failure.\n");
132 mbedtls_fprintf(out, "With 'list', list the available tests and their platform requirement.\n");
133}
134
135int main(int argc, char *argv[])
136{
137 const char *argv0 = argc > 0 ? argv[0] : "metatest";
138 if (argc != 2) {
139 help(stderr, argv0);
140 mbedtls_exit(MBEDTLS_EXIT_FAILURE);
141 }
142
143 /* Support "-help", "--help", "--list", etc. */
144 const char *command = argv[1];
145 while (*command == '-') {
146 ++command;
147 }
148
149 if (strcmp(argv[1], "help") == 0) {
150 help(stdout, argv0);
151 mbedtls_exit(MBEDTLS_EXIT_SUCCESS);
152 }
153 if (strcmp(argv[1], "list") == 0) {
154 for (const metatest_t *p = metatests; p->name != NULL; p++) {
155 mbedtls_printf("%s %s\n", p->name, p->platform);
156 }
157 mbedtls_exit(MBEDTLS_EXIT_SUCCESS);
158 }
159
160 for (const metatest_t *p = metatests; p->name != NULL; p++) {
161 if (strcmp(argv[1], p->name) == 0) {
162 mbedtls_printf("Running metatest %s...\n", argv[1]);
163 p->entry_point(argv[1]);
164 mbedtls_printf("Running metatest %s... done, result=%d\n",
165 argv[1], (int) mbedtls_test_info.result);
166 mbedtls_exit(mbedtls_test_info.result == MBEDTLS_TEST_RESULT_SUCCESS ?
167 MBEDTLS_EXIT_SUCCESS :
168 MBEDTLS_EXIT_FAILURE);
169 }
170 }
171
172 mbedtls_fprintf(stderr, "%s: FATAL: No such metatest: %s\n",
173 argv0, command);
174 mbedtls_exit(MBEDTLS_EXIT_FAILURE);
175}