1 /* Copyright (c) 2015-2021, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
5 #include "lib/crypt_ops/crypto_util.h"
7 #include "lib/intmath/cmp.h"
8 #include "lib/malloc/malloc.h"
12 #include <sys/types.h>
15 #ifdef HAVE_SYS_PARAM_H
16 #include <sys/param.h>
19 static unsigned fill_a_buffer_memset(void) __attribute__((noinline
));
20 static unsigned fill_a_buffer_memwipe(void) __attribute__((noinline
));
21 static unsigned fill_a_buffer_nothing(void) __attribute__((noinline
));
22 static unsigned fill_heap_buffer_memset(void) __attribute__((noinline
));
23 static unsigned fill_heap_buffer_memwipe(void) __attribute__((noinline
));
24 static unsigned fill_heap_buffer_nothing(void) __attribute__((noinline
));
25 static unsigned check_a_buffer(void) __attribute__((noinline
));
27 extern const char *s
; /* Make the linkage global */
32 #define FILL_BUFFER_IMPL() \
36 /* Fill up a 1k buffer with a recognizable pattern. */ \
37 for (i = 0; i < BUF_LEN; i += strlen(s)) { \
38 memcpy(buf+i, s, MIN(strlen(s), BUF_LEN-i)); \
41 /* Use the buffer as input to a computation so the above can't get */ \
42 /* optimized away. */ \
43 for (i = 0; i < BUF_LEN; ++i) { \
44 sum += (unsigned char)buf[i]; \
49 /* Disable some of OpenBSD's malloc protections for this test. This helps
50 * us do bad things, such as access freed buffers, without crashing. */
51 extern const char *malloc_options
;
52 const char *malloc_options
= "sufjj";
53 #endif /* defined(OpenBSD) */
56 fill_a_buffer_memset(void)
61 memset(buf
, 0, sizeof(buf
));
66 fill_a_buffer_memwipe(void)
71 memwipe(buf
, 0, sizeof(buf
));
76 fill_a_buffer_nothing(void)
85 vmemeq(volatile char *a
, const char *b
, size_t n
)
98 volatile char buf
[BUF_LEN
];
101 /* See if this buffer has the string in it.
103 YES, THIS DOES INVOKE UNDEFINED BEHAVIOR BY READING FROM AN UNINITIALIZED
106 If you know a better way to figure out whether the compiler eliminated
107 the memset/memwipe calls or not, please let me know.
109 for (i
= 0; i
< BUF_LEN
- strlen(s
); ++i
) {
110 if (vmemeq(buf
+i
, s
, strlen(s
)))
117 static char *heap_buf
= NULL
;
120 fill_heap_buffer_memset(void)
122 char *buf
= heap_buf
= raw_malloc(BUF_LEN
);
125 memset(buf
, 0, BUF_LEN
);
131 fill_heap_buffer_memwipe(void)
133 char *buf
= heap_buf
= raw_malloc(BUF_LEN
);
136 memwipe(buf
, 0, BUF_LEN
);
142 fill_heap_buffer_nothing(void)
144 char *buf
= heap_buf
= raw_malloc(BUF_LEN
);
152 check_heap_buffer(void)
156 volatile char *buf
= heap_buf
;
158 /* See if this buffer has the string in it.
160 YES, THIS DOES INVOKE UNDEFINED BEHAVIOR BY READING FROM A FREED BUFFER.
162 If you know a better way to figure out whether the compiler eliminated
163 the memset/memwipe calls or not, please let me know.
165 for (i
= 0; i
< BUF_LEN
- strlen(s
); ++i
) {
166 if (vmemeq(buf
+i
, s
, strlen(s
)))
173 static struct testcase
{
175 /* this spacing satisfies make check-spaces */
181 { "nil", fill_a_buffer_nothing
, check_a_buffer
},
182 { "nil-heap", fill_heap_buffer_nothing
, check_heap_buffer
},
183 { "memset", fill_a_buffer_memset
, check_a_buffer
},
184 { "memset-heap", fill_heap_buffer_memset
, check_heap_buffer
},
185 { "memwipe", fill_a_buffer_memwipe
, check_a_buffer
},
186 { "memwipe-heap", fill_heap_buffer_memwipe
, check_heap_buffer
},
191 main(int argc
, char **argv
)
197 (void) argc
; (void) argv
;
199 s
= "squamous haberdasher gallimaufry";
201 memset(found
, 0, sizeof(found
));
203 for (i
= 0; testcases
[i
].name
; ++i
) {
204 x
= testcases
[i
].fill_fn();
205 found
[i
] = testcases
[i
].check_fn();
207 x2
= fill_a_buffer_nothing();
214 if (!working
|| !found
[0] || !found
[1]) {
215 printf("It appears that this test case may not give you reliable "
216 "information. Sorry.\n");
219 if (!found
[2] && !found
[3]) {
220 printf("It appears that memset is good enough on this platform. Good.\n");
223 if (found
[4] || found
[5]) {
224 printf("ERROR: memwipe does not wipe data!\n");
227 printf("OKAY: memwipe seems to work.\n");