summaryrefslogtreecommitdiff
path: root/regress/lib/libc/arc4random-fork
diff options
context:
space:
mode:
authorMatthew Dempsky <matthew@cvs.openbsd.org>2014-06-18 08:24:01 +0000
committerMatthew Dempsky <matthew@cvs.openbsd.org>2014-06-18 08:24:01 +0000
commitf64e519739a20e65a083dc525468a39c5f7a4529 (patch)
tree09f6af12401bfbf391b1c05dda1f7219fd91357b /regress/lib/libc/arc4random-fork
parent3dd53c2d4a7800aa76ac493de665ece6db85e402 (diff)
Add regress tests to make sure arc4random(3) is reinitialized
correctly in fork children.
Diffstat (limited to 'regress/lib/libc/arc4random-fork')
-rw-r--r--regress/lib/libc/arc4random-fork/Makefile25
-rw-r--r--regress/lib/libc/arc4random-fork/arc4random-fork.c153
2 files changed, 178 insertions, 0 deletions
diff --git a/regress/lib/libc/arc4random-fork/Makefile b/regress/lib/libc/arc4random-fork/Makefile
new file mode 100644
index 00000000000..05762e33ffc
--- /dev/null
+++ b/regress/lib/libc/arc4random-fork/Makefile
@@ -0,0 +1,25 @@
+# $OpenBSD: Makefile,v 1.1 2014/06/18 08:24:00 matthew Exp $
+
+PROG= arc4random-fork
+
+REGRESS_TARGETS= \
+ run \
+ run-buf \
+ run-prefork \
+ run-buf-prefork
+
+run: ${PROG}
+ ./${PROG}
+
+run-buf: ${PROG}
+ ./${PROG} -b
+
+run-prefork: ${PROG}
+ ./${PROG} -p
+
+run-buf-prefork: ${PROG}
+ ./${PROG} -bp
+
+.PHONY: ${REGRESS_TARGETS}
+
+.include <bsd.regress.mk>
diff --git a/regress/lib/libc/arc4random-fork/arc4random-fork.c b/regress/lib/libc/arc4random-fork/arc4random-fork.c
new file mode 100644
index 00000000000..35a9ea6a980
--- /dev/null
+++ b/regress/lib/libc/arc4random-fork/arc4random-fork.c
@@ -0,0 +1,153 @@
+/*
+ * 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 <sys/mman.h>
+#include <sys/wait.h>
+#include <assert.h>
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define CHECK(x) assert(x)
+#define CHECK_EQ(a, b) assert((a) == (b))
+#define CHECK_NE(a, b) assert((a) != (b))
+#define CHECK_GE(a, b) assert((a) >= (b))
+#define CHECK_LE(a, b) assert((a) <= (b))
+
+/* Test arc4random_buf(3) instead of arc4random(3). */
+static int flagbuf;
+
+/* Initialize arc4random(3) before forking. */
+static int flagprefork;
+
+enum {
+ N = 4096
+};
+
+typedef struct {
+ uint32_t x[N];
+} Buf;
+
+static int
+isfullbuf(const Buf *buf)
+{
+ size_t i;
+ for (i = 0; i < N; i++)
+ if (buf->x[i])
+ return (1);
+ return (0);
+}
+
+static void
+fillbuf(Buf *buf)
+{
+ if (flagbuf) {
+ arc4random_buf(buf->x, sizeof(buf->x));
+ } else {
+ size_t i;
+ for (i = 0; i < N; i++)
+ buf->x[i] = arc4random();
+ }
+}
+
+static void
+usage()
+{
+ extern const char *__progname;
+ errx(1, "usage: %s [-bp]", __progname);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int opt, status;
+ Buf *bufparent, *bufchildone, *bufchildtwo;
+ pid_t pidone, pidtwo;
+ size_t i, countone = 0, counttwo = 0, countkids = 0;
+
+ while ((opt = getopt(argc, argv, "bp")) != -1) {
+ switch (opt) {
+ case 'b':
+ flagbuf = 1;
+ break;
+ case 'p':
+ flagprefork = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (flagprefork)
+ arc4random();
+
+ bufparent = mmap(NULL, sizeof(Buf), PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_PRIVATE, -1, 0);
+ CHECK_NE(MAP_FAILED, bufparent);
+
+ bufchildone = mmap(NULL, sizeof(Buf), PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_SHARED, -1, 0);
+ CHECK_NE(MAP_FAILED, bufchildone);
+
+ bufchildtwo = mmap(NULL, sizeof(Buf), PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_SHARED, -1, 0);
+ CHECK_NE(MAP_FAILED, bufchildtwo);
+
+ pidone = fork();
+ CHECK_GE(pidone, 0);
+ if (pidone == 0) {
+ fillbuf(bufchildone);
+ _exit(0);
+ }
+
+ pidtwo = fork();
+ CHECK_GE(pidtwo, 0);
+ if (pidtwo == 0) {
+ fillbuf(bufchildtwo);
+ _exit(0);
+ }
+
+ fillbuf(bufparent);
+
+ CHECK_EQ(pidone, waitpid(pidone, &status, 0));
+ CHECK(WIFEXITED(status));
+ CHECK_EQ(0, WEXITSTATUS(status));
+
+ CHECK_EQ(pidtwo, waitpid(pidtwo, &status, 0));
+ CHECK(WIFEXITED(status));
+ CHECK_EQ(0, WEXITSTATUS(status));
+
+ CHECK(isfullbuf(bufchildone));
+ CHECK(isfullbuf(bufchildtwo));
+
+ for (i = 0; i < N; i++) {
+ countone += bufparent->x[i] == bufchildone->x[i];
+ counttwo += bufparent->x[i] == bufchildtwo->x[i];
+ countkids += bufchildone->x[i] == bufchildtwo->x[i];
+ }
+
+ /*
+ * These checks are inherently probabilistic and theoretically risk
+ * flaking, but there's less than a 1 in 2^40 chance of more than
+ * one pairwise match between two vectors of 4096 32-bit integers.
+ */
+ CHECK_LE(countone, 1);
+ CHECK_LE(counttwo, 1);
+ CHECK_LE(countkids, 1);
+
+ return (0);
+}