]> Savannah Git Hosting - gnulib.git/commitdiff
explicit_bzero: Add tests.
authorBruno Haible <bruno@clisp.org>
Sun, 12 Apr 2020 19:00:10 +0000 (21:00 +0200)
committerBruno Haible <bruno@clisp.org>
Sun, 12 Apr 2020 19:00:10 +0000 (21:00 +0200)
* tests/test-explicit_bzero.c: New file.
* modules/explicit_bzero-tests: New file.

ChangeLog
modules/explicit_bzero-tests [new file with mode: 0644]
tests/test-explicit_bzero.c [new file with mode: 0644]

index eec41fb33727dff555ec8312645012a3daa19051..25ce2691297e0cbe1b310e581a127b56909fd666 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2020-04-12  Bruno Haible  <bruno@clisp.org>
+
+       explicit_bzero: Add tests.
+       * tests/test-explicit_bzero.c: New file.
+       * modules/explicit_bzero-tests: New file.
+
 2020-04-11  Bruno Haible  <bruno@clisp.org>
 
        explicit_bzero: Relicense under LGPLv2+.
diff --git a/modules/explicit_bzero-tests b/modules/explicit_bzero-tests
new file mode 100644 (file)
index 0000000..77719da
--- /dev/null
@@ -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 (file)
index 0000000..526ccfd
--- /dev/null
@@ -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 <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2020.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <string.h>
+
+#include "signature.h"
+SIGNATURE_CHECK (explicit_bzero, void, (void *, size_t));
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#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;
+}