From 6b58c306f2b5b2dcef66386167df6c8703c397b2 Mon Sep 17 00:00:00 2001
From: matthew <>
Date: Thu, 12 Jun 2014 22:01:55 +0000
Subject: Add regress test for explicit_bzero.

---
 src/regress/lib/libc/Makefile                      |   4 +-
 src/regress/lib/libc/explicit_bzero/Makefile       |   5 +
 .../lib/libc/explicit_bzero/explicit_bzero.c       | 138 +++++++++++++++++++++
 3 files changed, 145 insertions(+), 2 deletions(-)
 create mode 100644 src/regress/lib/libc/explicit_bzero/Makefile
 create mode 100644 src/regress/lib/libc/explicit_bzero/explicit_bzero.c

(limited to 'src')

diff --git a/src/regress/lib/libc/Makefile b/src/regress/lib/libc/Makefile
index f138f16ffd..71eb6398a8 100644
--- a/src/regress/lib/libc/Makefile
+++ b/src/regress/lib/libc/Makefile
@@ -1,7 +1,7 @@
-#	$OpenBSD: Makefile,v 1.39 2014/06/07 01:46:40 tobiasu Exp $
+#	$OpenBSD: Makefile,v 1.40 2014/06/12 22:01:55 matthew Exp $
 
 SUBDIR+= _setjmp alloca atexit basename cephes cxa-atexit db dirname env
-SUBDIR+= fmemopen fnmatch fpclassify getcap getopt_long glob
+SUBDIR+= explicit_bzero fmemopen fnmatch fpclassify getcap getopt_long glob
 SUBDIR+= hsearch longjmp locale malloc mkstemp modf netdb open_memstream
 SUBDIR+= orientation popen printf
 SUBDIR+= regex setjmp setjmp-signal sigreturn sigsetjmp sprintf
diff --git a/src/regress/lib/libc/explicit_bzero/Makefile b/src/regress/lib/libc/explicit_bzero/Makefile
new file mode 100644
index 0000000000..cd514a43a1
--- /dev/null
+++ b/src/regress/lib/libc/explicit_bzero/Makefile
@@ -0,0 +1,5 @@
+#	$OpenBSD: Makefile,v 1.1 2014/06/12 22:01:55 matthew Exp $
+
+PROG=	explicit_bzero
+
+.include <bsd.regress.mk>
diff --git a/src/regress/lib/libc/explicit_bzero/explicit_bzero.c b/src/regress/lib/libc/explicit_bzero/explicit_bzero.c
new file mode 100644
index 0000000000..b4b6c9e559
--- /dev/null
+++ b/src/regress/lib/libc/explicit_bzero/explicit_bzero.c
@@ -0,0 +1,138 @@
+/*	$OpenBSD: explicit_bzero.c,v 1.1 2014/06/12 22:01:55 matthew Exp $	*/
+/*
+ * Copyright (c) 2014 Google Inc.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+#define ASSERT_EQ(a, b) assert((a) == (b))
+#define ASSERT_NE(a, b) assert((a) != (b))
+#define ASSERT_GE(a, b) assert((a) >= (b))
+
+static void
+call_on_stack(void (*fn)(int), void *stack, size_t stacklen)
+{
+	/*
+	 * This is a bit more complicated than strictly necessary, but
+	 * it ensures we don't have any flaky test failures due to
+	 * inherited signal masks/actions/etc.
+	 *
+	 * On systems where SA_ONSTACK is not supported, this could
+	 * alternatively be implemented using makecontext() or
+	 * pthread_attr_setstack().
+	 */
+
+	const struct sigaction sigact = {
+		.sa_handler = fn,
+		.sa_flags = SA_ONSTACK,
+	};
+	const stack_t sigstk = {
+		.ss_sp = stack,
+		.ss_size = stacklen,
+	};
+	struct sigaction oldsigact;
+	stack_t oldsigstk;
+	sigset_t sigset, oldsigset;
+
+	/* First, block all signals. */
+	ASSERT_EQ(0, sigemptyset(&sigset));
+	ASSERT_EQ(0, sigfillset(&sigset));
+	ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &sigset, &oldsigset));
+
+	/* Next setup the signal stack and handler for SIGUSR1. */
+	ASSERT_EQ(0, sigaltstack(&sigstk, &oldsigstk));
+	ASSERT_EQ(0, sigaction(SIGUSR1, &sigact, &oldsigact));
+
+	/* Raise SIGUSR1 and momentarily unblock it to run the handler. */
+	ASSERT_EQ(0, raise(SIGUSR1));
+	ASSERT_EQ(0, sigdelset(&sigset, SIGUSR1));
+	ASSERT_EQ(-1, sigsuspend(&sigset));
+	ASSERT_EQ(EINTR, errno);
+
+	/* Restore the original signal action, stack, and mask. */
+	ASSERT_EQ(0, sigaction(SIGUSR1, &oldsigact, NULL));
+	ASSERT_EQ(0, sigaltstack(&oldsigstk, NULL));
+	ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &oldsigset, NULL));
+}
+
+/* 128 bits of random data. */
+static const char secret[16] = {
+	0xa0, 0x6c, 0x0c, 0x81, 0xba, 0xd8, 0x5b, 0x0c,
+	0xb0, 0xd6, 0xd4, 0xe3, 0xeb, 0x52, 0x5f, 0x96,
+};
+
+enum {
+	SECRETCOUNT = 16,
+	SECRETBYTES = SECRETCOUNT * sizeof(secret)
+};
+
+static void
+populate_secret(char *buf, size_t len)
+{
+	int i, fds[2];
+	ASSERT_EQ(0, pipe(fds));
+
+	for (i = 0; i < SECRETCOUNT; i++)
+		ASSERT_EQ(sizeof(secret), write(fds[1], secret, sizeof(secret)));
+	ASSERT_EQ(0, close(fds[1]));
+
+	ASSERT_EQ(len, read(fds[0], buf, len));
+	ASSERT_EQ(0, close(fds[0]));
+}
+
+static void
+test_without_bzero(int signo)
+{
+	char buf[SECRETBYTES];
+	populate_secret(buf, sizeof(buf));
+}
+
+static void
+test_with_bzero(int signo)
+{
+	char buf[SECRETBYTES];
+	populate_secret(buf, sizeof(buf));
+	explicit_bzero(buf, sizeof(buf));
+}
+
+static char altstack[SIGSTKSZ];
+
+int
+main()
+{
+	/*
+	 * First, test that if we *don't* call explicit_bzero, that we
+	 * *are* able to find the secret data on the stack.  This
+	 * sanity checks that call_on_stack() and populare_secret()
+	 * work as intended.
+	 */
+	memset(altstack, 0, sizeof(altstack));
+	call_on_stack(test_without_bzero, altstack, sizeof(altstack));
+	ASSERT_NE(NULL, memmem(altstack, sizeof(altstack), secret, sizeof(secret)));
+
+	/*
+	 * Now test with a call to explicit_bzero() and check that we
+	 * *don't* find the secret data.
+	 */
+	memset(altstack, 0, sizeof(altstack));
+	call_on_stack(test_with_bzero, altstack, sizeof(altstack));
+	ASSERT_EQ(NULL, memmem(altstack, sizeof(altstack), secret, sizeof(secret)));
+
+	return (0);
+}
-- 
cgit v1.2.3-55-g6feb