diff options
Diffstat (limited to 'lib/libc/tests/secure/fortify_poll_test.c')
| -rw-r--r-- | lib/libc/tests/secure/fortify_poll_test.c | 617 | 
1 files changed, 617 insertions, 0 deletions
| diff --git a/lib/libc/tests/secure/fortify_poll_test.c b/lib/libc/tests/secure/fortify_poll_test.c new file mode 100644 index 000000000000..3810c16c122f --- /dev/null +++ b/lib/libc/tests/secure/fortify_poll_test.c @@ -0,0 +1,617 @@ +/* @generated by `generate-fortify-tests.lua "poll"` */ + +#define	_FORTIFY_SOURCE	2 +#define	TMPFILE_SIZE	(1024 * 32) + +#include <sys/param.h> +#include <sys/jail.h> +#include <sys/random.h> +#include <sys/resource.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <poll.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <sysexits.h> +#include <unistd.h> +#include <wchar.h> +#include <atf-c.h> + +static FILE * __unused +new_fp(size_t __len) +{ +	static char fpbuf[LINE_MAX]; +	FILE *fp; + +	ATF_REQUIRE(__len <= sizeof(fpbuf)); + +	memset(fpbuf, 'A', sizeof(fpbuf) - 1); +	fpbuf[sizeof(fpbuf) - 1] = '\0'; + +	fp = fmemopen(fpbuf, sizeof(fpbuf), "rb"); +	ATF_REQUIRE(fp != NULL); + +	return (fp); +} + +/* + * 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); +} + +/* + * For our purposes, first descriptor will be the reader; we'll send both + * raw data and a control message over it so that the result can be used for + * any of our recv*() tests. + */ +static void __unused +new_socket(int sock[2]) +{ +	unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 }; +	static char sockbuf[256]; +	ssize_t rv; +	size_t total = 0; +	struct msghdr hdr = { 0 }; +	struct cmsghdr *cmsg; +	int error, fd; + +	error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock); +	ATF_REQUIRE(error == 0); + +	while (total != sizeof(sockbuf)) { +		rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0); + +		ATF_REQUIRE_MSG(rv > 0, +		    "expected bytes sent, got %zd with %zu left (size %zu, total %zu)", +		    rv, sizeof(sockbuf) - total, sizeof(sockbuf), total); +		ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf), +		    "%zd exceeds total %zu", rv, sizeof(sockbuf)); +		total += rv; +	} + +	hdr.msg_control = ctrl; +	hdr.msg_controllen = sizeof(ctrl); + +	cmsg = CMSG_FIRSTHDR(&hdr); +	cmsg->cmsg_level = SOL_SOCKET; +	cmsg->cmsg_type = SCM_RIGHTS; +	cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); +	fd = STDIN_FILENO; +	memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd)); + +	error = sendmsg(sock[1], &hdr, 0); +	ATF_REQUIRE(error != -1); +} + +/* + * 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); +} + +/* + * Replaces stdin with a file that we can actually read from, for tests where + * we want a FILE * or fd that we can get data from. + */ +static void __unused +replace_stdin(void) +{ +	int fd; + +	fd = new_tmpfile(); + +	(void)dup2(fd, STDIN_FILENO); +	if (fd != STDIN_FILENO) +		close(fd); +} + +ATF_TC(poll_before_end); +ATF_TC_HEAD(poll_before_end, tc) +{ +} +ATF_TC_BODY(poll_before_end, tc) +{ +#define BUF &__stack.__buf +	struct { +		uint8_t padding_l; +		struct pollfd __buf[4]; +		uint8_t padding_r; +	} __stack; +	const size_t __bufsz __unused = sizeof(__stack.__buf); +	const size_t __len = 4 - 1; +	const size_t __idx __unused = __len - 1; + +	for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { +		__stack.__buf[i].fd = -1; +	} + +	poll(__stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(poll_end); +ATF_TC_HEAD(poll_end, tc) +{ +} +ATF_TC_BODY(poll_end, tc) +{ +#define BUF &__stack.__buf +	struct { +		uint8_t padding_l; +		struct pollfd __buf[4]; +		uint8_t padding_r; +	} __stack; +	const size_t __bufsz __unused = sizeof(__stack.__buf); +	const size_t __len = 4; +	const size_t __idx __unused = __len - 1; + +	for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { +		__stack.__buf[i].fd = -1; +	} + +	poll(__stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(poll_after_end); +ATF_TC_HEAD(poll_after_end, tc) +{ +} +ATF_TC_BODY(poll_after_end, tc) +{ +#define BUF &__stack.__buf +	struct { +		uint8_t padding_l; +		struct pollfd __buf[4]; +		uint8_t padding_r; +	} __stack; +	const size_t __bufsz __unused = sizeof(__stack.__buf); +	const size_t __len = 4 + 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(); +	for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { +		__stack.__buf[i].fd = -1; +	} + +	poll(__stack.__buf, __len, 0); +	_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(poll_heap_before_end); +ATF_TC_HEAD(poll_heap_before_end, tc) +{ +} +ATF_TC_BODY(poll_heap_before_end, tc) +{ +#define BUF __stack.__buf +	struct { +		uint8_t padding_l; +		struct pollfd * __buf; +		uint8_t padding_r; +	} __stack; +	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); +	const size_t __len = 4 - 1; +	const size_t __idx __unused = __len - 1; + +	__stack.__buf = malloc(__bufsz); +	for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { +		__stack.__buf[i].fd = -1; +	} + +	poll(__stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(poll_heap_end); +ATF_TC_HEAD(poll_heap_end, tc) +{ +} +ATF_TC_BODY(poll_heap_end, tc) +{ +#define BUF __stack.__buf +	struct { +		uint8_t padding_l; +		struct pollfd * __buf; +		uint8_t padding_r; +	} __stack; +	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); +	const size_t __len = 4; +	const size_t __idx __unused = __len - 1; + +	__stack.__buf = malloc(__bufsz); +	for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { +		__stack.__buf[i].fd = -1; +	} + +	poll(__stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC(poll_heap_after_end); +ATF_TC_HEAD(poll_heap_after_end, tc) +{ +} +ATF_TC_BODY(poll_heap_after_end, tc) +{ +#define BUF __stack.__buf +	struct { +		uint8_t padding_l; +		struct pollfd * __buf; +		uint8_t padding_r; +	} __stack; +	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); +	const size_t __len = 4 + 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); +	for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { +		__stack.__buf[i].fd = -1; +	} + +	poll(__stack.__buf, __len, 0); +	_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(ppoll_before_end); +ATF_TC_HEAD(ppoll_before_end, tc) +{ +} +ATF_TC_BODY(ppoll_before_end, tc) +{ +#define BUF &__stack.__buf +	struct { +		uint8_t padding_l; +		struct pollfd __buf[4]; +		uint8_t padding_r; +	} __stack; +	const size_t __bufsz __unused = sizeof(__stack.__buf); +	const size_t __len = 4 - 1; +	const size_t __idx __unused = __len - 1; +	struct timespec tv = { 0 }; + +	for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { +		__stack.__buf[i].fd = -1; +	} + +	ppoll(__stack.__buf, __len, &tv, NULL); +#undef BUF + +} + +ATF_TC(ppoll_end); +ATF_TC_HEAD(ppoll_end, tc) +{ +} +ATF_TC_BODY(ppoll_end, tc) +{ +#define BUF &__stack.__buf +	struct { +		uint8_t padding_l; +		struct pollfd __buf[4]; +		uint8_t padding_r; +	} __stack; +	const size_t __bufsz __unused = sizeof(__stack.__buf); +	const size_t __len = 4; +	const size_t __idx __unused = __len - 1; +	struct timespec tv = { 0 }; + +	for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { +		__stack.__buf[i].fd = -1; +	} + +	ppoll(__stack.__buf, __len, &tv, NULL); +#undef BUF + +} + +ATF_TC(ppoll_after_end); +ATF_TC_HEAD(ppoll_after_end, tc) +{ +} +ATF_TC_BODY(ppoll_after_end, tc) +{ +#define BUF &__stack.__buf +	struct { +		uint8_t padding_l; +		struct pollfd __buf[4]; +		uint8_t padding_r; +	} __stack; +	const size_t __bufsz __unused = sizeof(__stack.__buf); +	const size_t __len = 4 + 1; +	const size_t __idx __unused = __len - 1; +	pid_t __child; +	int __status; +	struct timespec tv = { 0 }; + +	__child = fork(); +	ATF_REQUIRE(__child >= 0); +	if (__child > 0) +		goto monitor; + +	/* Child */ +	disable_coredumps(); +	for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { +		__stack.__buf[i].fd = -1; +	} + +	ppoll(__stack.__buf, __len, &tv, NULL); +	_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(ppoll_heap_before_end); +ATF_TC_HEAD(ppoll_heap_before_end, tc) +{ +} +ATF_TC_BODY(ppoll_heap_before_end, tc) +{ +#define BUF __stack.__buf +	struct { +		uint8_t padding_l; +		struct pollfd * __buf; +		uint8_t padding_r; +	} __stack; +	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); +	const size_t __len = 4 - 1; +	const size_t __idx __unused = __len - 1; +	struct timespec tv = { 0 }; + +	__stack.__buf = malloc(__bufsz); +	for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { +		__stack.__buf[i].fd = -1; +	} + +	ppoll(__stack.__buf, __len, &tv, NULL); +#undef BUF + +} + +ATF_TC(ppoll_heap_end); +ATF_TC_HEAD(ppoll_heap_end, tc) +{ +} +ATF_TC_BODY(ppoll_heap_end, tc) +{ +#define BUF __stack.__buf +	struct { +		uint8_t padding_l; +		struct pollfd * __buf; +		uint8_t padding_r; +	} __stack; +	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); +	const size_t __len = 4; +	const size_t __idx __unused = __len - 1; +	struct timespec tv = { 0 }; + +	__stack.__buf = malloc(__bufsz); +	for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { +		__stack.__buf[i].fd = -1; +	} + +	ppoll(__stack.__buf, __len, &tv, NULL); +#undef BUF + +} + +ATF_TC(ppoll_heap_after_end); +ATF_TC_HEAD(ppoll_heap_after_end, tc) +{ +} +ATF_TC_BODY(ppoll_heap_after_end, tc) +{ +#define BUF __stack.__buf +	struct { +		uint8_t padding_l; +		struct pollfd * __buf; +		uint8_t padding_r; +	} __stack; +	const size_t __bufsz __unused = sizeof(*__stack.__buf) * (4); +	const size_t __len = 4 + 1; +	const size_t __idx __unused = __len - 1; +	pid_t __child; +	int __status; +	struct timespec tv = { 0 }; + +	__child = fork(); +	ATF_REQUIRE(__child >= 0); +	if (__child > 0) +		goto monitor; + +	/* Child */ +	disable_coredumps(); +	__stack.__buf = malloc(__bufsz); +	for (size_t i = 0; i < howmany(__bufsz, sizeof(struct pollfd)); i++) { +		__stack.__buf[i].fd = -1; +	} + +	ppoll(__stack.__buf, __len, &tv, NULL); +	_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, poll_before_end); +	ATF_TP_ADD_TC(tp, poll_end); +	ATF_TP_ADD_TC(tp, poll_after_end); +	ATF_TP_ADD_TC(tp, poll_heap_before_end); +	ATF_TP_ADD_TC(tp, poll_heap_end); +	ATF_TP_ADD_TC(tp, poll_heap_after_end); +	ATF_TP_ADD_TC(tp, ppoll_before_end); +	ATF_TP_ADD_TC(tp, ppoll_end); +	ATF_TP_ADD_TC(tp, ppoll_after_end); +	ATF_TP_ADD_TC(tp, ppoll_heap_before_end); +	ATF_TP_ADD_TC(tp, ppoll_heap_end); +	ATF_TP_ADD_TC(tp, ppoll_heap_after_end); +	return (atf_no_error()); +} | 
