From 7397561e64f9b96a4a1638117ce18d06133a60f1 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sun, 12 Apr 2020 21:00:10 +0200 Subject: [PATCH] explicit_bzero: Add tests. * tests/test-explicit_bzero.c: New file. * modules/explicit_bzero-tests: New file. --- ChangeLog | 6 ++ modules/explicit_bzero-tests | 14 +++ tests/test-explicit_bzero.c | 175 +++++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 modules/explicit_bzero-tests create mode 100644 tests/test-explicit_bzero.c diff --git a/ChangeLog b/ChangeLog index eec41fb337..25ce269129 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2020-04-12 Bruno Haible + + explicit_bzero: Add tests. + * tests/test-explicit_bzero.c: New file. + * modules/explicit_bzero-tests: New file. + 2020-04-11 Bruno Haible explicit_bzero: Relicense under LGPLv2+. diff --git a/modules/explicit_bzero-tests b/modules/explicit_bzero-tests new file mode 100644 index 0000000000..77719dafb3 --- /dev/null +++ b/modules/explicit_bzero-tests @@ -0,0 +1,14 @@ +Files: +tests/test-explicit_bzero.c +tests/signature.h +tests/macros.h + +Depends-on: +stdint +vma-iter + +configure.ac: + +Makefile.am: +TESTS += test-explicit_bzero +check_PROGRAMS += test-explicit_bzero diff --git a/tests/test-explicit_bzero.c b/tests/test-explicit_bzero.c new file mode 100644 index 0000000000..526ccfd48d --- /dev/null +++ b/tests/test-explicit_bzero.c @@ -0,0 +1,175 @@ +/* Test of explicit_bzero() function. + Copyright (C) 2020 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Bruno Haible , 2020. */ + +#include + +/* Specification. */ +#include + +#include "signature.h" +SIGNATURE_CHECK (explicit_bzero, void, (void *, size_t)); + +#include +#include +#include +#include + +#include "vma-iter.h" +#include "macros.h" + +#define SECRET "xyzzy1729" +#define SECRET_SIZE 9 + +static char zero[SECRET_SIZE] = { 0 }; + +/* Enable this to verify that the test is effective. */ +#if 0 +# define explicit_bzero(a, n) memset (a, '\0', n) +#endif + +/* =================== Verify operation on static memory =================== */ + +static char stbuf[SECRET_SIZE]; + +static void +test_static (void) +{ + memcpy (stbuf, SECRET, SECRET_SIZE); + explicit_bzero (stbuf, SECRET_SIZE); + ASSERT (memcmp (zero, stbuf, SECRET_SIZE) == 0); +} + +/* =============== Verify operation on heap-allocated memory =============== */ + +/* Test whether an address range is mapped in memory. */ +#if VMA_ITERATE_SUPPORTED + +struct locals +{ + uintptr_t range_start; + uintptr_t range_end; +}; + +static int +vma_iterate_callback (void *data, uintptr_t start, uintptr_t end, + unsigned int flags) +{ + struct locals *lp = (struct locals *) data; + + /* Remove from [range_start, range_end) the part at the beginning or at the + end that is covered by [start, end). */ + if (start <= lp->range_start && end > lp->range_start) + lp->range_start = (end < lp->range_end ? end : lp->range_end); + if (start < lp->range_end && end >= lp->range_end) + lp->range_end = (start > lp->range_start ? start : lp->range_start); + + return 0; +} + +static bool +is_range_mapped (uintptr_t range_start, uintptr_t range_end) +{ + struct locals l; + + l.range_start = range_start; + l.range_end = range_end; + vma_iterate (vma_iterate_callback, &l); + return l.range_start == l.range_end; +} + +#else + +static bool +is_range_mapped (uintptr_t range_start, uintptr_t range_end) +{ + return true; +} + +#endif + +static void +test_heap (void) +{ + char *heapbuf = (char *) malloc (SECRET_SIZE); + uintptr_t addr = (uintptr_t) heapbuf; + memcpy (heapbuf, SECRET, SECRET_SIZE); + explicit_bzero (heapbuf, SECRET_SIZE); + free (heapbuf); + if (is_range_mapped (addr, addr + SECRET_SIZE)) + { + ASSERT (memcmp (zero, heapbuf, SECRET_SIZE) == 0); + printf ("test_heap: address range is still mapped after free().\n"); + } + else + printf ("test_heap: address range is unmapped after free().\n"); +} + +/* =============== Verify operation on stack-allocated memory =============== */ + +/* There are two passes: + 1. Put a secret in memory and invoke explicit_bzero on it. + 2. Verify that the memory has been erased. + Implement them in the same function, so that they access the same memory + range on the stack. */ +int +do_secret_stuff (volatile int pass) +{ + char stackbuf[SECRET_SIZE]; + if (pass == 1) + { + memcpy (stackbuf, SECRET, SECRET_SIZE); + explicit_bzero (stackbuf, SECRET_SIZE); + return 0; + } + else /* pass == 2 */ + { + return memcmp (zero, stackbuf, SECRET_SIZE) != 0; + } +} + +void +test_stack (void) +{ + int count = 0; + int repeat; + + for (repeat = 1000; repeat > 0; repeat--) + { + do_secret_stuff (1); + count += do_secret_stuff (2); + } + /* If explicit_bzero works, count is near 0. (It may be > 0 if there were + some asynchronous signal invocations between the two calls of + do_secret_stuff.) + If explicit_bzero is optimized away by the compiler, count comes out as + approximately 1000. */ + printf ("test_stack: count = %d\n", count); + ASSERT (count < 50); +} + +/* ========================================================================== */ + +int +main () +{ + test_static (); + test_heap (); + test_stack (); + + return 0; +} -- 2.39.5