git: 062d9380b986 - main - include: ssp: fortify <sys/random.h>
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 13 Jul 2024 05:23:05 UTC
The branch main has been updated by kevans: URL: https://cgit.FreeBSD.org/src/commit/?id=062d9380b98663eb2a4a3d7ce9e919e743984060 commit 062d9380b98663eb2a4a3d7ce9e919e743984060 Author: Kyle Evans <kevans@FreeBSD.org> AuthorDate: 2024-07-13 05:16:11 +0000 Commit: Kyle Evans <kevans@FreeBSD.org> CommitDate: 2024-07-13 05:16:25 +0000 include: ssp: fortify <sys/random.h> That is to say, fortify getrandom(2). Reviewed by: markj Sponsored by: Klara, Inc. Sponsored by: Stormshield Differential Revision: https://reviews.freebsd.org/D45683 --- include/ssp/Makefile | 3 +- include/ssp/random.h | 42 ++++ lib/libc/tests/secure/Makefile | 4 + lib/libc/tests/secure/fortify_poll_test.c | 1 + lib/libc/tests/secure/fortify_random_test.c | 253 +++++++++++++++++++++++ lib/libc/tests/secure/fortify_stdio_test.c | 1 + lib/libc/tests/secure/fortify_stdlib_test.c | 1 + lib/libc/tests/secure/fortify_string_test.c | 1 + lib/libc/tests/secure/fortify_strings_test.c | 1 + lib/libc/tests/secure/fortify_unistd_test.c | 1 + lib/libc/tests/secure/fortify_wchar_test.c | 1 + lib/libc/tests/secure/generate-fortify-tests.lua | 13 ++ sys/sys/random.h | 4 + 13 files changed, 325 insertions(+), 1 deletion(-) diff --git a/include/ssp/Makefile b/include/ssp/Makefile index 725d82ff10e5..d6e0e0698e36 100644 --- a/include/ssp/Makefile +++ b/include/ssp/Makefile @@ -1,4 +1,5 @@ -INCS= poll.h ssp.h stdio.h stdlib.h string.h strings.h unistd.h wchar.h +INCS= poll.h random.h ssp.h stdio.h stdlib.h string.h strings.h unistd.h +INCS+= wchar.h INCSDIR= ${INCLUDEDIR}/ssp .include <bsd.prog.mk> diff --git a/include/ssp/random.h b/include/ssp/random.h new file mode 100644 index 000000000000..9f98ad2315a1 --- /dev/null +++ b/include/ssp/random.h @@ -0,0 +1,42 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024, Klara, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _SSP_RANDOM_H_ +#define _SSP_RANDOM_H_ + +#include <ssp/ssp.h> + +#if __SSP_FORTIFY_LEVEL > 0 + +__BEGIN_DECLS + +__ssp_redirect(ssize_t, getrandom, (void *__buf, size_t __len, + unsigned int __flags), (__buf, __len, __flags)); + +__END_DECLS + +#endif /* __SSP_FORTIFY_LEVEL > 0 */ +#endif /* _SSP_RANDOM_H_ */ diff --git a/lib/libc/tests/secure/Makefile b/lib/libc/tests/secure/Makefile index 27d29eabe689..87c491d9cf2f 100644 --- a/lib/libc/tests/secure/Makefile +++ b/lib/libc/tests/secure/Makefile @@ -2,6 +2,10 @@ TESTSDIR:= ${TESTSBASE}/${RELDIR:C/libc\/tests/libc/} +# sys/ headers +FORTIFY_TCATS+= random + +# non-sys/ headers FORTIFY_TCATS+= poll FORTIFY_TCATS+= stdlib FORTIFY_TCATS+= stdio diff --git a/lib/libc/tests/secure/fortify_poll_test.c b/lib/libc/tests/secure/fortify_poll_test.c index 447ff400dc05..2723052ac501 100644 --- a/lib/libc/tests/secure/fortify_poll_test.c +++ b/lib/libc/tests/secure/fortify_poll_test.c @@ -4,6 +4,7 @@ #define TMPFILE_SIZE (1024 * 32) #include <sys/param.h> +#include <sys/random.h> #include <sys/resource.h> #include <sys/time.h> #include <sys/wait.h> diff --git a/lib/libc/tests/secure/fortify_random_test.c b/lib/libc/tests/secure/fortify_random_test.c new file mode 100644 index 000000000000..b89410a702d0 --- /dev/null +++ b/lib/libc/tests/secure/fortify_random_test.c @@ -0,0 +1,253 @@ +/* @generated by `generate-fortify-tests.lua "random"` */ + +#define _FORTIFY_SOURCE 2 +#define TMPFILE_SIZE (1024 * 32) + +#include <sys/param.h> +#include <sys/random.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 <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); +} + +/* + * 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_WITHOUT_HEAD(getrandom_before_end); +ATF_TC_BODY(getrandom_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; + + getrandom(__stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getrandom_end); +ATF_TC_BODY(getrandom_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; + + getrandom(__stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getrandom_heap_before_end); +ATF_TC_BODY(getrandom_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); + + getrandom(__stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getrandom_heap_end); +ATF_TC_BODY(getrandom_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); + + getrandom(__stack.__buf, __len, 0); +#undef BUF + +} + +ATF_TC_WITHOUT_HEAD(getrandom_heap_after_end); +ATF_TC_BODY(getrandom_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); + + getrandom(__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_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, getrandom_before_end); + ATF_TP_ADD_TC(tp, getrandom_end); + ATF_TP_ADD_TC(tp, getrandom_heap_before_end); + ATF_TP_ADD_TC(tp, getrandom_heap_end); + ATF_TP_ADD_TC(tp, getrandom_heap_after_end); + return (atf_no_error()); +} diff --git a/lib/libc/tests/secure/fortify_stdio_test.c b/lib/libc/tests/secure/fortify_stdio_test.c index f399a32f3ca2..a19bfebba1bb 100644 --- a/lib/libc/tests/secure/fortify_stdio_test.c +++ b/lib/libc/tests/secure/fortify_stdio_test.c @@ -4,6 +4,7 @@ #define TMPFILE_SIZE (1024 * 32) #include <sys/param.h> +#include <sys/random.h> #include <sys/resource.h> #include <sys/time.h> #include <sys/wait.h> diff --git a/lib/libc/tests/secure/fortify_stdlib_test.c b/lib/libc/tests/secure/fortify_stdlib_test.c index 87e6b4b86302..47f4157b5a01 100644 --- a/lib/libc/tests/secure/fortify_stdlib_test.c +++ b/lib/libc/tests/secure/fortify_stdlib_test.c @@ -4,6 +4,7 @@ #define TMPFILE_SIZE (1024 * 32) #include <sys/param.h> +#include <sys/random.h> #include <sys/resource.h> #include <sys/time.h> #include <sys/wait.h> diff --git a/lib/libc/tests/secure/fortify_string_test.c b/lib/libc/tests/secure/fortify_string_test.c index 0ba1cf0160b4..6a4f08705602 100644 --- a/lib/libc/tests/secure/fortify_string_test.c +++ b/lib/libc/tests/secure/fortify_string_test.c @@ -4,6 +4,7 @@ #define TMPFILE_SIZE (1024 * 32) #include <sys/param.h> +#include <sys/random.h> #include <sys/resource.h> #include <sys/time.h> #include <sys/wait.h> diff --git a/lib/libc/tests/secure/fortify_strings_test.c b/lib/libc/tests/secure/fortify_strings_test.c index a476564f1596..ec6340e77f74 100644 --- a/lib/libc/tests/secure/fortify_strings_test.c +++ b/lib/libc/tests/secure/fortify_strings_test.c @@ -4,6 +4,7 @@ #define TMPFILE_SIZE (1024 * 32) #include <sys/param.h> +#include <sys/random.h> #include <sys/resource.h> #include <sys/time.h> #include <sys/wait.h> diff --git a/lib/libc/tests/secure/fortify_unistd_test.c b/lib/libc/tests/secure/fortify_unistd_test.c index cfd9267d0d79..fa478955283e 100644 --- a/lib/libc/tests/secure/fortify_unistd_test.c +++ b/lib/libc/tests/secure/fortify_unistd_test.c @@ -4,6 +4,7 @@ #define TMPFILE_SIZE (1024 * 32) #include <sys/param.h> +#include <sys/random.h> #include <sys/resource.h> #include <sys/time.h> #include <sys/wait.h> diff --git a/lib/libc/tests/secure/fortify_wchar_test.c b/lib/libc/tests/secure/fortify_wchar_test.c index f02e4045c8f2..cd09e5dac93c 100644 --- a/lib/libc/tests/secure/fortify_wchar_test.c +++ b/lib/libc/tests/secure/fortify_wchar_test.c @@ -4,6 +4,7 @@ #define TMPFILE_SIZE (1024 * 32) #include <sys/param.h> +#include <sys/random.h> #include <sys/resource.h> #include <sys/time.h> #include <sys/wait.h> diff --git a/lib/libc/tests/secure/generate-fortify-tests.lua b/lib/libc/tests/secure/generate-fortify-tests.lua index 1807cbf477e9..259c9a7825d9 100755 --- a/lib/libc/tests/secure/generate-fortify-tests.lua +++ b/lib/libc/tests/secure/generate-fortify-tests.lua @@ -62,6 +62,7 @@ local includes = { "sys/param.h", + "sys/random.h", "sys/resource.h", "sys/time.h", "sys/wait.h", @@ -147,6 +148,18 @@ local wstring_init = [[ -- circumstances it's useful to use a different type (e.g., for alignment -- requirements). local all_tests = { + random = { + -- <sys/random.h> + { + func = "getrandom", + arguments = { + "__buf", + "__len", + "0", + }, + exclude = excludes_stack_overflow, + }, + }, poll = { -- <poll.h> { diff --git a/sys/sys/random.h b/sys/sys/random.h index aa4457fc8c22..31071d356714 100644 --- a/sys/sys/random.h +++ b/sys/sys/random.h @@ -161,6 +161,10 @@ void random_harvest_deregister_source(enum random_entropy_source); #define GRND_RANDOM 0x2 #define GRND_INSECURE 0x4 +#if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 +#include <ssp/random.h> +#endif + __BEGIN_DECLS ssize_t getrandom(void *buf, size_t buflen, unsigned int flags); __END_DECLS