tor/src/test/test-memwipe.c
Kris Katterjohn c13a81f7f9 Fix (and make consistent) the use of OpenBSD preprocessor macro tests
Prior to this commit, the testsuite was failing on OpenBSD.  After
this commit the testsuite runs fine on OpenBSD.

It was previously decided to test for the OpenBSD macro (rather than
__OpenBSD__, etc.) because OpenBSD forks seem to have the former
macro defined.  sys/param.h must be included for the OpenBSD macro
definition; however, many files tested for the OpenBSD macro without
having this header included.

This commit includes sys/param.h in the files where the OpenBSD macro
is used (and sys/param.h is not already included), and it also
changes some instances of the __OpenBSD__ macro to OpenBSD.

See commit 27df23abb6 which changed
everything to use OpenBSD instead of __OpenBSD__ or OPENBSD.  See
also tickets #6982 and #20980 (the latter ticket is where it was
decided to use the OpenBSD macro).

Signed-off-by: Kris Katterjohn <katterjohn@gmail.com>
2019-01-09 08:51:57 -05:00

223 lines
5.5 KiB
C

/* Copyright (c) 2015-2018, The Tor Project, Inc. */
/* See LICENSE for licensing information */
#include "orconfig.h"
#include "lib/crypt_ops/crypto_util.h"
#include "lib/intmath/cmp.h"
#include "lib/malloc/malloc.h"
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
static unsigned fill_a_buffer_memset(void) __attribute__((noinline));
static unsigned fill_a_buffer_memwipe(void) __attribute__((noinline));
static unsigned fill_a_buffer_nothing(void) __attribute__((noinline));
static unsigned fill_heap_buffer_memset(void) __attribute__((noinline));
static unsigned fill_heap_buffer_memwipe(void) __attribute__((noinline));
static unsigned fill_heap_buffer_nothing(void) __attribute__((noinline));
static unsigned check_a_buffer(void) __attribute__((noinline));
extern const char *s; /* Make the linkage global */
const char *s = NULL;
#define BUF_LEN 2048
#define FILL_BUFFER_IMPL() \
unsigned int i; \
unsigned sum = 0; \
\
/* Fill up a 1k buffer with a recognizable pattern. */ \
for (i = 0; i < BUF_LEN; i += strlen(s)) { \
memcpy(buf+i, s, MIN(strlen(s), BUF_LEN-i)); \
} \
\
/* Use the buffer as input to a computation so the above can't get */ \
/* optimized away. */ \
for (i = 0; i < BUF_LEN; ++i) { \
sum += (unsigned char)buf[i]; \
}
#ifdef OpenBSD
/* Disable some of OpenBSD's malloc protections for this test. This helps
* us do bad things, such as access freed buffers, without crashing. */
const char *malloc_options="sufjj";
#endif
static unsigned
fill_a_buffer_memset(void)
{
char buf[BUF_LEN];
FILL_BUFFER_IMPL()
memset(buf, 0, sizeof(buf));
return sum;
}
static unsigned
fill_a_buffer_memwipe(void)
{
char buf[BUF_LEN];
FILL_BUFFER_IMPL()
memwipe(buf, 0, sizeof(buf));
return sum;
}
static unsigned
fill_a_buffer_nothing(void)
{
char buf[BUF_LEN];
FILL_BUFFER_IMPL()
return sum;
}
static inline int
vmemeq(volatile char *a, const char *b, size_t n)
{
while (n--) {
if (*a++ != *b++)
return 0;
}
return 1;
}
static unsigned
check_a_buffer(void)
{
unsigned int i;
volatile char buf[BUF_LEN];
unsigned sum = 0;
/* See if this buffer has the string in it.
YES, THIS DOES INVOKE UNDEFINED BEHAVIOR BY READING FROM AN UNINITIALIZED
BUFFER.
If you know a better way to figure out whether the compiler eliminated
the memset/memwipe calls or not, please let me know.
*/
for (i = 0; i < BUF_LEN - strlen(s); ++i) {
if (vmemeq(buf+i, s, strlen(s)))
++sum;
}
return sum;
}
static char *heap_buf = NULL;
static unsigned
fill_heap_buffer_memset(void)
{
char *buf = heap_buf = raw_malloc(BUF_LEN);
FILL_BUFFER_IMPL()
memset(buf, 0, BUF_LEN);
raw_free(buf);
return sum;
}
static unsigned
fill_heap_buffer_memwipe(void)
{
char *buf = heap_buf = raw_malloc(BUF_LEN);
FILL_BUFFER_IMPL()
memwipe(buf, 0, BUF_LEN);
raw_free(buf);
return sum;
}
static unsigned
fill_heap_buffer_nothing(void)
{
char *buf = heap_buf = raw_malloc(BUF_LEN);
FILL_BUFFER_IMPL()
raw_free(buf);
return sum;
}
static unsigned
check_heap_buffer(void)
{
unsigned int i;
unsigned sum = 0;
volatile char *buf = heap_buf;
/* See if this buffer has the string in it.
YES, THIS DOES INVOKE UNDEFINED BEHAVIOR BY READING FROM A FREED BUFFER.
If you know a better way to figure out whether the compiler eliminated
the memset/memwipe calls or not, please let me know.
*/
for (i = 0; i < BUF_LEN - strlen(s); ++i) {
if (vmemeq(buf+i, s, strlen(s)))
++sum;
}
return sum;
}
static struct testcase {
const char *name;
/* this spacing satisfies make check-spaces */
unsigned
(*fill_fn)(void);
unsigned
(*check_fn)(void);
} testcases[] = {
{ "nil", fill_a_buffer_nothing, check_a_buffer },
{ "nil-heap", fill_heap_buffer_nothing, check_heap_buffer },
{ "memset", fill_a_buffer_memset, check_a_buffer },
{ "memset-heap", fill_heap_buffer_memset, check_heap_buffer },
{ "memwipe", fill_a_buffer_memwipe, check_a_buffer },
{ "memwipe-heap", fill_heap_buffer_memwipe, check_heap_buffer },
{ NULL, NULL, NULL }
};
int
main(int argc, char **argv)
{
unsigned x, x2;
int i;
int working = 1;
unsigned found[6];
(void) argc; (void) argv;
s = "squamous haberdasher gallimaufry";
memset(found, 0, sizeof(found));
for (i = 0; testcases[i].name; ++i) {
x = testcases[i].fill_fn();
found[i] = testcases[i].check_fn();
x2 = fill_a_buffer_nothing();
if (x != x2) {
working = 0;
}
}
if (!working || !found[0] || !found[1]) {
printf("It appears that this test case may not give you reliable "
"information. Sorry.\n");
}
if (!found[2] && !found[3]) {
printf("It appears that memset is good enough on this platform. Good.\n");
}
if (found[4] || found[5]) {
printf("ERROR: memwipe does not wipe data!\n");
return 1;
} else {
printf("OKAY: memwipe seems to work.\n");
return 0;
}
}