git: 020d003c8636 - main - libc: tests: add testing infrastructure for _FORTIFY_SOURCE

From: Kyle Evans <kevans_at_FreeBSD.org>
Date: Sat, 13 Jul 2024 05:22:58 UTC
The branch main has been updated by kevans:

URL: https://cgit.FreeBSD.org/src/commit/?id=020d003c86367bb5751b6d58fb58611242802c7f

commit 020d003c86367bb5751b6d58fb58611242802c7f
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2024-07-13 05:16:10 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2024-07-13 05:16:23 +0000

    libc: tests: add testing infrastructure for _FORTIFY_SOURCE
    
    The _FORTIFY_SOURCE tests will be generated by a lua script to avoid a
    lot of redundancy in writing these tests.  For each function that we're
    fortifying, the plan is to test at least the following three scenarios:
    
     - Writing up to one byte before the end of the buffer,
     - Writing up to the end of the buffer,
     - Writing one byte past the end of the buffer
    
    The buffer is shoved into a struct on the stack to guarantee a stack
    layout in which we have a valid byte after the buffer so that level 2
    fortification will trip and we can have confidence that it wasn't some
    other stack/memory protection instead.
    
    The generated tests are divided roughly into which header we're
    attributing them to so that we can parallelize the build -- the full set
    is a bit over 9000 lines of C and takes 11s to build on the hardware
    that I'm testing on if it's a single monolothic file.
    
    Reviewed by:    markj
    Sponsored by:   Klara, Inc.
    Sponsored by:   Stormshield
    Differential Revision:  https://reviews.freebsd.org/D45678
---
 etc/mtree/BSD.tests.dist                         |    2 +
 lib/libc/tests/Makefile                          |    1 +
 lib/libc/tests/secure/Makefile                   |   20 +
 lib/libc/tests/secure/fortify_stdio_test.c       |  383 ++++++
 lib/libc/tests/secure/fortify_string_test.c      | 1415 ++++++++++++++++++++++
 lib/libc/tests/secure/fortify_strings_test.c     |  354 ++++++
 lib/libc/tests/secure/fortify_unistd_test.c      |  505 ++++++++
 lib/libc/tests/secure/generate-fortify-tests.lua |  706 +++++++++++
 8 files changed, 3386 insertions(+)

diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist
index 375e4900b5d5..bd9edc786f17 100644
--- a/etc/mtree/BSD.tests.dist
+++ b/etc/mtree/BSD.tests.dist
@@ -372,6 +372,8 @@
             ..
             rpc
             ..
+            secure
+            ..
             setjmp
             ..
             ssp
diff --git a/lib/libc/tests/Makefile b/lib/libc/tests/Makefile
index 7b262ea646fb..7f72fb619004 100644
--- a/lib/libc/tests/Makefile
+++ b/lib/libc/tests/Makefile
@@ -13,6 +13,7 @@ TESTS_SUBDIRS+=	nss
 TESTS_SUBDIRS+=	regex
 TESTS_SUBDIRS+=	resolv
 TESTS_SUBDIRS+=	rpc
+TESTS_SUBDIRS+=	secure
 TESTS_SUBDIRS+=	setjmp
 TESTS_SUBDIRS+=	stdio
 TESTS_SUBDIRS+=	stdlib
diff --git a/lib/libc/tests/secure/Makefile b/lib/libc/tests/secure/Makefile
new file mode 100644
index 000000000000..d809f7cadd74
--- /dev/null
+++ b/lib/libc/tests/secure/Makefile
@@ -0,0 +1,20 @@
+.include <bsd.own.mk>
+
+TESTSDIR:=	${TESTSBASE}/${RELDIR:C/libc\/tests/libc/}
+
+FORTIFY_TCATS+=	stdio
+FORTIFY_TCATS+=	string
+FORTIFY_TCATS+=	strings
+FORTIFY_TCATS+=	unistd
+
+# Manually run after updating the test generator.
+generate-tests: .PHONY
+.for tcat in ${FORTIFY_TCATS}
+ATF_TESTS_C+=	fortify_${tcat}_test
+
+generate-tests: generate-tests-${tcat}
+generate-tests-${tcat}: .PHONY
+	${.CURDIR}/generate-fortify-tests.lua ${tcat} > ${.CURDIR}/fortify_${tcat}_test.c
+.endfor
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/secure/fortify_stdio_test.c b/lib/libc/tests/secure/fortify_stdio_test.c
new file mode 100644
index 000000000000..20ecdab89a8b
--- /dev/null
+++ b/lib/libc/tests/secure/fortify_stdio_test.c
@@ -0,0 +1,383 @@
+/* @generated by `generate-fortify-tests.lua "stdio"` */
+
+#define	_FORTIFY_SOURCE	2
+#define	TMPFILE_SIZE	(1024 * 32)
+
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <atf-c.h>
+
+/*
+ * Create a new symlink to use for readlink(2) style tests, we'll just use a
+ * random target name to have something interesting to look at.
+ */
+static const char * __unused
+new_symlink(size_t __len)
+{
+	static const char linkname[] = "link";
+	char target[MAXNAMLEN];
+	int error;
+
+	ATF_REQUIRE(__len <= sizeof(target));
+
+	arc4random_buf(target, sizeof(target));
+
+	error = unlink(linkname);
+	ATF_REQUIRE(error == 0 || errno == ENOENT);
+
+	error = symlink(target, linkname);
+	ATF_REQUIRE(error == 0);
+
+	return (linkname);
+}
+
+/*
+ * Constructs a tmpfile that we can use for testing read(2) and friends.
+ */
+static int __unused
+new_tmpfile(void)
+{
+	char buf[1024];
+	ssize_t rv;
+	size_t written;
+	int fd;
+
+	fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644);
+	ATF_REQUIRE(fd >= 0);
+
+	written = 0;
+	while (written < TMPFILE_SIZE) {
+		rv = write(fd, buf, sizeof(buf));
+		ATF_REQUIRE(rv > 0);
+
+		written += rv;
+	}
+
+	ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET));
+	return (fd);
+}
+
+static void
+disable_coredumps(void)
+{
+	struct rlimit rl = { 0 };
+
+	if (setrlimit(RLIMIT_CORE, &rl) == -1)
+		_exit(EX_OSERR);
+}
+
+ATF_TC_WITHOUT_HEAD(sprintf_before_end);
+ATF_TC_BODY(sprintf_before_end, tc)
+{
+#define BUF &__stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char __buf[42];
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(__stack.__buf);
+	const size_t __len = 42 - 1;
+	const size_t __idx __unused = __len - 1;
+	char srcvar[__len + 10];
+
+	memset(srcvar, 'A', sizeof(srcvar) - 1);
+	srcvar[sizeof(srcvar) - 1] = '\0';
+
+	sprintf(__stack.__buf, "%.*s", (int)__len - 1, srcvar);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(sprintf_end);
+ATF_TC_BODY(sprintf_end, tc)
+{
+#define BUF &__stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char __buf[42];
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(__stack.__buf);
+	const size_t __len = 42;
+	const size_t __idx __unused = __len - 1;
+	char srcvar[__len + 10];
+
+	memset(srcvar, 'A', sizeof(srcvar) - 1);
+	srcvar[sizeof(srcvar) - 1] = '\0';
+
+	sprintf(__stack.__buf, "%.*s", (int)__len - 1, srcvar);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(sprintf_heap_before_end);
+ATF_TC_BODY(sprintf_heap_before_end, tc)
+{
+#define BUF __stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char * __buf;
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42);
+	const size_t __len = 42 - 1;
+	const size_t __idx __unused = __len - 1;
+	char srcvar[__len + 10];
+
+	__stack.__buf = malloc(__bufsz);
+	memset(srcvar, 'A', sizeof(srcvar) - 1);
+	srcvar[sizeof(srcvar) - 1] = '\0';
+
+	sprintf(__stack.__buf, "%.*s", (int)__len - 1, srcvar);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(sprintf_heap_end);
+ATF_TC_BODY(sprintf_heap_end, tc)
+{
+#define BUF __stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char * __buf;
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42);
+	const size_t __len = 42;
+	const size_t __idx __unused = __len - 1;
+	char srcvar[__len + 10];
+
+	__stack.__buf = malloc(__bufsz);
+	memset(srcvar, 'A', sizeof(srcvar) - 1);
+	srcvar[sizeof(srcvar) - 1] = '\0';
+
+	sprintf(__stack.__buf, "%.*s", (int)__len - 1, srcvar);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(sprintf_heap_after_end);
+ATF_TC_BODY(sprintf_heap_after_end, tc)
+{
+#define BUF __stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char * __buf;
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42);
+	const size_t __len = 42 + 1;
+	const size_t __idx __unused = __len - 1;
+	pid_t __child;
+	int __status;
+	char srcvar[__len + 10];
+
+	__child = fork();
+	ATF_REQUIRE(__child >= 0);
+	if (__child > 0)
+		goto monitor;
+
+	/* Child */
+	disable_coredumps();
+	__stack.__buf = malloc(__bufsz);
+	memset(srcvar, 'A', sizeof(srcvar) - 1);
+	srcvar[sizeof(srcvar) - 1] = '\0';
+
+	sprintf(__stack.__buf, "%.*s", (int)__len - 1, srcvar);
+	_exit(EX_SOFTWARE);	/* Should have aborted. */
+
+monitor:
+	while (waitpid(__child, &__status, 0) != __child) {
+		ATF_REQUIRE_EQ(EINTR, errno);
+	}
+
+	if (!WIFSIGNALED(__status)) {
+		switch (WEXITSTATUS(__status)) {
+		case EX_SOFTWARE:
+			atf_tc_fail("FORTIFY_SOURCE failed to abort");
+			break;
+		case EX_OSERR:
+			atf_tc_fail("setrlimit(2) failed");
+			break;
+		default:
+			atf_tc_fail("child exited with status %d",
+			    WEXITSTATUS(__status));
+		}
+	} else {
+		ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status));
+	}
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(snprintf_before_end);
+ATF_TC_BODY(snprintf_before_end, tc)
+{
+#define BUF &__stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char __buf[42];
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(__stack.__buf);
+	const size_t __len = 42 - 1;
+	const size_t __idx __unused = __len - 1;
+	char srcvar[__len + 10];
+
+	memset(srcvar, 'A', sizeof(srcvar) - 1);
+	srcvar[sizeof(srcvar) - 1] = '\0';
+
+	snprintf(__stack.__buf, __len, "%.*s", (int)__len - 1, srcvar);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(snprintf_end);
+ATF_TC_BODY(snprintf_end, tc)
+{
+#define BUF &__stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char __buf[42];
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(__stack.__buf);
+	const size_t __len = 42;
+	const size_t __idx __unused = __len - 1;
+	char srcvar[__len + 10];
+
+	memset(srcvar, 'A', sizeof(srcvar) - 1);
+	srcvar[sizeof(srcvar) - 1] = '\0';
+
+	snprintf(__stack.__buf, __len, "%.*s", (int)__len - 1, srcvar);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(snprintf_heap_before_end);
+ATF_TC_BODY(snprintf_heap_before_end, tc)
+{
+#define BUF __stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char * __buf;
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42);
+	const size_t __len = 42 - 1;
+	const size_t __idx __unused = __len - 1;
+	char srcvar[__len + 10];
+
+	__stack.__buf = malloc(__bufsz);
+	memset(srcvar, 'A', sizeof(srcvar) - 1);
+	srcvar[sizeof(srcvar) - 1] = '\0';
+
+	snprintf(__stack.__buf, __len, "%.*s", (int)__len - 1, srcvar);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(snprintf_heap_end);
+ATF_TC_BODY(snprintf_heap_end, tc)
+{
+#define BUF __stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char * __buf;
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42);
+	const size_t __len = 42;
+	const size_t __idx __unused = __len - 1;
+	char srcvar[__len + 10];
+
+	__stack.__buf = malloc(__bufsz);
+	memset(srcvar, 'A', sizeof(srcvar) - 1);
+	srcvar[sizeof(srcvar) - 1] = '\0';
+
+	snprintf(__stack.__buf, __len, "%.*s", (int)__len - 1, srcvar);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(snprintf_heap_after_end);
+ATF_TC_BODY(snprintf_heap_after_end, tc)
+{
+#define BUF __stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char * __buf;
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42);
+	const size_t __len = 42 + 1;
+	const size_t __idx __unused = __len - 1;
+	pid_t __child;
+	int __status;
+	char srcvar[__len + 10];
+
+	__child = fork();
+	ATF_REQUIRE(__child >= 0);
+	if (__child > 0)
+		goto monitor;
+
+	/* Child */
+	disable_coredumps();
+	__stack.__buf = malloc(__bufsz);
+	memset(srcvar, 'A', sizeof(srcvar) - 1);
+	srcvar[sizeof(srcvar) - 1] = '\0';
+
+	snprintf(__stack.__buf, __len, "%.*s", (int)__len - 1, srcvar);
+	_exit(EX_SOFTWARE);	/* Should have aborted. */
+
+monitor:
+	while (waitpid(__child, &__status, 0) != __child) {
+		ATF_REQUIRE_EQ(EINTR, errno);
+	}
+
+	if (!WIFSIGNALED(__status)) {
+		switch (WEXITSTATUS(__status)) {
+		case EX_SOFTWARE:
+			atf_tc_fail("FORTIFY_SOURCE failed to abort");
+			break;
+		case EX_OSERR:
+			atf_tc_fail("setrlimit(2) failed");
+			break;
+		default:
+			atf_tc_fail("child exited with status %d",
+			    WEXITSTATUS(__status));
+		}
+	} else {
+		ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status));
+	}
+#undef BUF
+
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+	ATF_TP_ADD_TC(tp, sprintf_before_end);
+	ATF_TP_ADD_TC(tp, sprintf_end);
+	ATF_TP_ADD_TC(tp, sprintf_heap_before_end);
+	ATF_TP_ADD_TC(tp, sprintf_heap_end);
+	ATF_TP_ADD_TC(tp, sprintf_heap_after_end);
+	ATF_TP_ADD_TC(tp, snprintf_before_end);
+	ATF_TP_ADD_TC(tp, snprintf_end);
+	ATF_TP_ADD_TC(tp, snprintf_heap_before_end);
+	ATF_TP_ADD_TC(tp, snprintf_heap_end);
+	ATF_TP_ADD_TC(tp, snprintf_heap_after_end);
+	return (atf_no_error());
+}
diff --git a/lib/libc/tests/secure/fortify_string_test.c b/lib/libc/tests/secure/fortify_string_test.c
new file mode 100644
index 000000000000..109ef40fd62d
--- /dev/null
+++ b/lib/libc/tests/secure/fortify_string_test.c
@@ -0,0 +1,1415 @@
+/* @generated by `generate-fortify-tests.lua "string"` */
+
+#define	_FORTIFY_SOURCE	2
+#define	TMPFILE_SIZE	(1024 * 32)
+
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <atf-c.h>
+
+/*
+ * Create a new symlink to use for readlink(2) style tests, we'll just use a
+ * random target name to have something interesting to look at.
+ */
+static const char * __unused
+new_symlink(size_t __len)
+{
+	static const char linkname[] = "link";
+	char target[MAXNAMLEN];
+	int error;
+
+	ATF_REQUIRE(__len <= sizeof(target));
+
+	arc4random_buf(target, sizeof(target));
+
+	error = unlink(linkname);
+	ATF_REQUIRE(error == 0 || errno == ENOENT);
+
+	error = symlink(target, linkname);
+	ATF_REQUIRE(error == 0);
+
+	return (linkname);
+}
+
+/*
+ * Constructs a tmpfile that we can use for testing read(2) and friends.
+ */
+static int __unused
+new_tmpfile(void)
+{
+	char buf[1024];
+	ssize_t rv;
+	size_t written;
+	int fd;
+
+	fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644);
+	ATF_REQUIRE(fd >= 0);
+
+	written = 0;
+	while (written < TMPFILE_SIZE) {
+		rv = write(fd, buf, sizeof(buf));
+		ATF_REQUIRE(rv > 0);
+
+		written += rv;
+	}
+
+	ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET));
+	return (fd);
+}
+
+static void
+disable_coredumps(void)
+{
+	struct rlimit rl = { 0 };
+
+	if (setrlimit(RLIMIT_CORE, &rl) == -1)
+		_exit(EX_OSERR);
+}
+
+ATF_TC_WITHOUT_HEAD(memcpy_before_end);
+ATF_TC_BODY(memcpy_before_end, tc)
+{
+#define BUF &__stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char __buf[42];
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(__stack.__buf);
+	const size_t __len = 42 - 1;
+	const size_t __idx __unused = __len - 1;
+	char src[__len + 10];
+
+	memcpy(__stack.__buf, src, __len);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(memcpy_end);
+ATF_TC_BODY(memcpy_end, tc)
+{
+#define BUF &__stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char __buf[42];
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(__stack.__buf);
+	const size_t __len = 42;
+	const size_t __idx __unused = __len - 1;
+	char src[__len + 10];
+
+	memcpy(__stack.__buf, src, __len);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(memcpy_heap_before_end);
+ATF_TC_BODY(memcpy_heap_before_end, tc)
+{
+#define BUF __stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char * __buf;
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42);
+	const size_t __len = 42 - 1;
+	const size_t __idx __unused = __len - 1;
+	char src[__len + 10];
+
+	__stack.__buf = malloc(__bufsz);
+
+	memcpy(__stack.__buf, src, __len);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(memcpy_heap_end);
+ATF_TC_BODY(memcpy_heap_end, tc)
+{
+#define BUF __stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char * __buf;
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42);
+	const size_t __len = 42;
+	const size_t __idx __unused = __len - 1;
+	char src[__len + 10];
+
+	__stack.__buf = malloc(__bufsz);
+
+	memcpy(__stack.__buf, src, __len);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(memcpy_heap_after_end);
+ATF_TC_BODY(memcpy_heap_after_end, tc)
+{
+#define BUF __stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char * __buf;
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42);
+	const size_t __len = 42 + 1;
+	const size_t __idx __unused = __len - 1;
+	pid_t __child;
+	int __status;
+	char src[__len + 10];
+
+	__child = fork();
+	ATF_REQUIRE(__child >= 0);
+	if (__child > 0)
+		goto monitor;
+
+	/* Child */
+	disable_coredumps();
+	__stack.__buf = malloc(__bufsz);
+
+	memcpy(__stack.__buf, src, __len);
+	_exit(EX_SOFTWARE);	/* Should have aborted. */
+
+monitor:
+	while (waitpid(__child, &__status, 0) != __child) {
+		ATF_REQUIRE_EQ(EINTR, errno);
+	}
+
+	if (!WIFSIGNALED(__status)) {
+		switch (WEXITSTATUS(__status)) {
+		case EX_SOFTWARE:
+			atf_tc_fail("FORTIFY_SOURCE failed to abort");
+			break;
+		case EX_OSERR:
+			atf_tc_fail("setrlimit(2) failed");
+			break;
+		default:
+			atf_tc_fail("child exited with status %d",
+			    WEXITSTATUS(__status));
+		}
+	} else {
+		ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status));
+	}
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(memmove_before_end);
+ATF_TC_BODY(memmove_before_end, tc)
+{
+#define BUF &__stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char __buf[42];
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(__stack.__buf);
+	const size_t __len = 42 - 1;
+	const size_t __idx __unused = __len - 1;
+	char src[__len + 10];
+
+	memmove(__stack.__buf, src, __len);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(memmove_end);
+ATF_TC_BODY(memmove_end, tc)
+{
+#define BUF &__stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char __buf[42];
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(__stack.__buf);
+	const size_t __len = 42;
+	const size_t __idx __unused = __len - 1;
+	char src[__len + 10];
+
+	memmove(__stack.__buf, src, __len);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(memmove_heap_before_end);
+ATF_TC_BODY(memmove_heap_before_end, tc)
+{
+#define BUF __stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char * __buf;
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42);
+	const size_t __len = 42 - 1;
+	const size_t __idx __unused = __len - 1;
+	char src[__len + 10];
+
+	__stack.__buf = malloc(__bufsz);
+
+	memmove(__stack.__buf, src, __len);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(memmove_heap_end);
+ATF_TC_BODY(memmove_heap_end, tc)
+{
+#define BUF __stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char * __buf;
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42);
+	const size_t __len = 42;
+	const size_t __idx __unused = __len - 1;
+	char src[__len + 10];
+
+	__stack.__buf = malloc(__bufsz);
+
+	memmove(__stack.__buf, src, __len);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(memmove_heap_after_end);
+ATF_TC_BODY(memmove_heap_after_end, tc)
+{
+#define BUF __stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char * __buf;
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42);
+	const size_t __len = 42 + 1;
+	const size_t __idx __unused = __len - 1;
+	pid_t __child;
+	int __status;
+	char src[__len + 10];
+
+	__child = fork();
+	ATF_REQUIRE(__child >= 0);
+	if (__child > 0)
+		goto monitor;
+
+	/* Child */
+	disable_coredumps();
+	__stack.__buf = malloc(__bufsz);
+
+	memmove(__stack.__buf, src, __len);
+	_exit(EX_SOFTWARE);	/* Should have aborted. */
+
+monitor:
+	while (waitpid(__child, &__status, 0) != __child) {
+		ATF_REQUIRE_EQ(EINTR, errno);
+	}
+
+	if (!WIFSIGNALED(__status)) {
+		switch (WEXITSTATUS(__status)) {
+		case EX_SOFTWARE:
+			atf_tc_fail("FORTIFY_SOURCE failed to abort");
+			break;
+		case EX_OSERR:
+			atf_tc_fail("setrlimit(2) failed");
+			break;
+		default:
+			atf_tc_fail("child exited with status %d",
+			    WEXITSTATUS(__status));
+		}
+	} else {
+		ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status));
+	}
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(memset_before_end);
+ATF_TC_BODY(memset_before_end, tc)
+{
+#define BUF &__stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char __buf[42];
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(__stack.__buf);
+	const size_t __len = 42 - 1;
+	const size_t __idx __unused = __len - 1;
+
+	memset(__stack.__buf, 0, __len);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(memset_end);
+ATF_TC_BODY(memset_end, tc)
+{
+#define BUF &__stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char __buf[42];
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(__stack.__buf);
+	const size_t __len = 42;
+	const size_t __idx __unused = __len - 1;
+
+	memset(__stack.__buf, 0, __len);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(memset_heap_before_end);
+ATF_TC_BODY(memset_heap_before_end, tc)
+{
+#define BUF __stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char * __buf;
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42);
+	const size_t __len = 42 - 1;
+	const size_t __idx __unused = __len - 1;
+
+	__stack.__buf = malloc(__bufsz);
+
+	memset(__stack.__buf, 0, __len);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(memset_heap_end);
+ATF_TC_BODY(memset_heap_end, tc)
+{
+#define BUF __stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char * __buf;
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42);
+	const size_t __len = 42;
+	const size_t __idx __unused = __len - 1;
+
+	__stack.__buf = malloc(__bufsz);
+
+	memset(__stack.__buf, 0, __len);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(memset_heap_after_end);
+ATF_TC_BODY(memset_heap_after_end, tc)
+{
+#define BUF __stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char * __buf;
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42);
+	const size_t __len = 42 + 1;
+	const size_t __idx __unused = __len - 1;
+	pid_t __child;
+	int __status;
+
+	__child = fork();
+	ATF_REQUIRE(__child >= 0);
+	if (__child > 0)
+		goto monitor;
+
+	/* Child */
+	disable_coredumps();
+	__stack.__buf = malloc(__bufsz);
+
+	memset(__stack.__buf, 0, __len);
+	_exit(EX_SOFTWARE);	/* Should have aborted. */
+
+monitor:
+	while (waitpid(__child, &__status, 0) != __child) {
+		ATF_REQUIRE_EQ(EINTR, errno);
+	}
+
+	if (!WIFSIGNALED(__status)) {
+		switch (WEXITSTATUS(__status)) {
+		case EX_SOFTWARE:
+			atf_tc_fail("FORTIFY_SOURCE failed to abort");
+			break;
+		case EX_OSERR:
+			atf_tc_fail("setrlimit(2) failed");
+			break;
+		default:
+			atf_tc_fail("child exited with status %d",
+			    WEXITSTATUS(__status));
+		}
+	} else {
+		ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status));
+	}
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(stpcpy_before_end);
+ATF_TC_BODY(stpcpy_before_end, tc)
+{
+#define BUF &__stack.__buf
+	struct {
+		uint8_t padding_l;
+		unsigned char __buf[42];
+		uint8_t padding_r;
+	} __stack;
+	const size_t __bufsz __unused = sizeof(__stack.__buf);
+	const size_t __len = 42 - 1;
+	const size_t __idx __unused = __len - 1;
+	char src[__len];
+
+	memset(__stack.__buf, 0, __len);
+	memset(src, 'A', __len - 1);
+	src[__len - 1] = '\0';
+
+	stpcpy(__stack.__buf, src);
+#undef BUF
+
+}
+
*** 2503 LINES SKIPPED ***