git: 020d003c8636 - main - libc: tests: add testing infrastructure for _FORTIFY_SOURCE
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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 ***