The branch main has been updated by kevans:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=2aba0eea3ffffce74f9d8df20e0aaf49ea6d76c3

commit 2aba0eea3ffffce74f9d8df20e0aaf49ea6d76c3
Author:     Kyle Evans <[email protected]>
AuthorDate: 2024-07-13 05:16:12 +0000
Commit:     Kyle Evans <[email protected]>
CommitDate: 2024-07-13 05:16:25 +0000

    include: ssp: fortify <sys/select.h>
    
    Notably sanity check indices passed to the FD_*() macros against the
    size of the fd_set itself.
    
    Reviewed by:    markj
    Sponsored by:   Klara, Inc.
    Sponsored by:   Stormshield
    Differential Revision:  https://reviews.freebsd.org/D45685
---
 lib/libc/tests/secure/Makefile                   |   1 +
 lib/libc/tests/secure/fortify_poll_test.c        |   1 +
 lib/libc/tests/secure/fortify_random_test.c      |   1 +
 lib/libc/tests/secure/fortify_select_test.c      | 669 +++++++++++++++++++++++
 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_uio_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 |  31 ++
 sys/sys/select.h                                 |  32 +-
 13 files changed, 739 insertions(+), 3 deletions(-)

diff --git a/lib/libc/tests/secure/Makefile b/lib/libc/tests/secure/Makefile
index 7aa9212b97a8..996536beac91 100644
--- a/lib/libc/tests/secure/Makefile
+++ b/lib/libc/tests/secure/Makefile
@@ -4,6 +4,7 @@ TESTSDIR:=      ${TESTSBASE}/${RELDIR:C/libc\/tests/libc/}
 
 # sys/ headers
 FORTIFY_TCATS+=        random
+FORTIFY_TCATS+=        select
 FORTIFY_TCATS+=        uio
 
 # non-sys/ headers
diff --git a/lib/libc/tests/secure/fortify_poll_test.c 
b/lib/libc/tests/secure/fortify_poll_test.c
index 83c0f68b0daa..47648fe54b47 100644
--- a/lib/libc/tests/secure/fortify_poll_test.c
+++ b/lib/libc/tests/secure/fortify_poll_test.c
@@ -6,6 +6,7 @@
 #include <sys/param.h>
 #include <sys/random.h>
 #include <sys/resource.h>
+#include <sys/select.h>
 #include <sys/time.h>
 #include <sys/uio.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
index 1eb18cfcaaf4..64c32c6c6a8f 100644
--- a/lib/libc/tests/secure/fortify_random_test.c
+++ b/lib/libc/tests/secure/fortify_random_test.c
@@ -6,6 +6,7 @@
 #include <sys/param.h>
 #include <sys/random.h>
 #include <sys/resource.h>
+#include <sys/select.h>
 #include <sys/time.h>
 #include <sys/uio.h>
 #include <sys/wait.h>
diff --git a/lib/libc/tests/secure/fortify_select_test.c 
b/lib/libc/tests/secure/fortify_select_test.c
new file mode 100644
index 000000000000..ccd3f97004fc
--- /dev/null
+++ b/lib/libc/tests/secure/fortify_select_test.c
@@ -0,0 +1,669 @@
+/* @generated by `generate-fortify-tests.lua "select"` */
+
+#define        _FORTIFY_SOURCE 2
+#define        TMPFILE_SIZE    (1024 * 32)
+
+#include <sys/param.h>
+#include <sys/random.h>
+#include <sys/resource.h>
+#include <sys/select.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);
+}
+
+/*
+ * 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(FD_SET_before_end);
+ATF_TC_BODY(FD_SET_before_end, tc)
+{
+#define BUF &__stack.__buf
+       struct {
+               uint8_t padding_l;
+               fd_set __buf;
+               uint8_t padding_r;
+       } __stack;
+       const size_t __bufsz __unused = sizeof(__stack.__buf);
+       const size_t __len = FD_SETSIZE - 1;
+       const size_t __idx __unused = __len - 1;
+
+       FD_SET(__idx, &__stack.__buf);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(FD_SET_end);
+ATF_TC_BODY(FD_SET_end, tc)
+{
+#define BUF &__stack.__buf
+       struct {
+               uint8_t padding_l;
+               fd_set __buf;
+               uint8_t padding_r;
+       } __stack;
+       const size_t __bufsz __unused = sizeof(__stack.__buf);
+       const size_t __len = FD_SETSIZE;
+       const size_t __idx __unused = __len - 1;
+
+       FD_SET(__idx, &__stack.__buf);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(FD_SET_after_end);
+ATF_TC_BODY(FD_SET_after_end, tc)
+{
+#define BUF &__stack.__buf
+       struct {
+               uint8_t padding_l;
+               fd_set __buf;
+               uint8_t padding_r;
+       } __stack;
+       const size_t __bufsz __unused = sizeof(__stack.__buf);
+       const size_t __len = FD_SETSIZE + 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();
+       FD_SET(__idx, &__stack.__buf);
+       _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(FD_SET_heap_before_end);
+ATF_TC_BODY(FD_SET_heap_before_end, tc)
+{
+#define BUF __stack.__buf
+       struct {
+               uint8_t padding_l;
+               fd_set * __buf;
+               uint8_t padding_r;
+       } __stack;
+       const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1);
+       const size_t __len = FD_SETSIZE - 1;
+       const size_t __idx __unused = __len - 1;
+
+       __stack.__buf = malloc(__bufsz);
+
+       FD_SET(__idx, __stack.__buf);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(FD_SET_heap_end);
+ATF_TC_BODY(FD_SET_heap_end, tc)
+{
+#define BUF __stack.__buf
+       struct {
+               uint8_t padding_l;
+               fd_set * __buf;
+               uint8_t padding_r;
+       } __stack;
+       const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1);
+       const size_t __len = FD_SETSIZE;
+       const size_t __idx __unused = __len - 1;
+
+       __stack.__buf = malloc(__bufsz);
+
+       FD_SET(__idx, __stack.__buf);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(FD_SET_heap_after_end);
+ATF_TC_BODY(FD_SET_heap_after_end, tc)
+{
+#define BUF __stack.__buf
+       struct {
+               uint8_t padding_l;
+               fd_set * __buf;
+               uint8_t padding_r;
+       } __stack;
+       const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1);
+       const size_t __len = FD_SETSIZE + 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);
+
+       FD_SET(__idx, __stack.__buf);
+       _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(FD_CLR_before_end);
+ATF_TC_BODY(FD_CLR_before_end, tc)
+{
+#define BUF &__stack.__buf
+       struct {
+               uint8_t padding_l;
+               fd_set __buf;
+               uint8_t padding_r;
+       } __stack;
+       const size_t __bufsz __unused = sizeof(__stack.__buf);
+       const size_t __len = FD_SETSIZE - 1;
+       const size_t __idx __unused = __len - 1;
+
+       FD_CLR(__idx, &__stack.__buf);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(FD_CLR_end);
+ATF_TC_BODY(FD_CLR_end, tc)
+{
+#define BUF &__stack.__buf
+       struct {
+               uint8_t padding_l;
+               fd_set __buf;
+               uint8_t padding_r;
+       } __stack;
+       const size_t __bufsz __unused = sizeof(__stack.__buf);
+       const size_t __len = FD_SETSIZE;
+       const size_t __idx __unused = __len - 1;
+
+       FD_CLR(__idx, &__stack.__buf);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(FD_CLR_after_end);
+ATF_TC_BODY(FD_CLR_after_end, tc)
+{
+#define BUF &__stack.__buf
+       struct {
+               uint8_t padding_l;
+               fd_set __buf;
+               uint8_t padding_r;
+       } __stack;
+       const size_t __bufsz __unused = sizeof(__stack.__buf);
+       const size_t __len = FD_SETSIZE + 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();
+       FD_CLR(__idx, &__stack.__buf);
+       _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(FD_CLR_heap_before_end);
+ATF_TC_BODY(FD_CLR_heap_before_end, tc)
+{
+#define BUF __stack.__buf
+       struct {
+               uint8_t padding_l;
+               fd_set * __buf;
+               uint8_t padding_r;
+       } __stack;
+       const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1);
+       const size_t __len = FD_SETSIZE - 1;
+       const size_t __idx __unused = __len - 1;
+
+       __stack.__buf = malloc(__bufsz);
+
+       FD_CLR(__idx, __stack.__buf);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(FD_CLR_heap_end);
+ATF_TC_BODY(FD_CLR_heap_end, tc)
+{
+#define BUF __stack.__buf
+       struct {
+               uint8_t padding_l;
+               fd_set * __buf;
+               uint8_t padding_r;
+       } __stack;
+       const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1);
+       const size_t __len = FD_SETSIZE;
+       const size_t __idx __unused = __len - 1;
+
+       __stack.__buf = malloc(__bufsz);
+
+       FD_CLR(__idx, __stack.__buf);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(FD_CLR_heap_after_end);
+ATF_TC_BODY(FD_CLR_heap_after_end, tc)
+{
+#define BUF __stack.__buf
+       struct {
+               uint8_t padding_l;
+               fd_set * __buf;
+               uint8_t padding_r;
+       } __stack;
+       const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1);
+       const size_t __len = FD_SETSIZE + 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);
+
+       FD_CLR(__idx, __stack.__buf);
+       _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(FD_ISSET_before_end);
+ATF_TC_BODY(FD_ISSET_before_end, tc)
+{
+#define BUF &__stack.__buf
+       struct {
+               uint8_t padding_l;
+               fd_set __buf;
+               uint8_t padding_r;
+       } __stack;
+       const size_t __bufsz __unused = sizeof(__stack.__buf);
+       const size_t __len = FD_SETSIZE - 1;
+       const size_t __idx __unused = __len - 1;
+
+       FD_ISSET(__idx, &__stack.__buf);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(FD_ISSET_end);
+ATF_TC_BODY(FD_ISSET_end, tc)
+{
+#define BUF &__stack.__buf
+       struct {
+               uint8_t padding_l;
+               fd_set __buf;
+               uint8_t padding_r;
+       } __stack;
+       const size_t __bufsz __unused = sizeof(__stack.__buf);
+       const size_t __len = FD_SETSIZE;
+       const size_t __idx __unused = __len - 1;
+
+       FD_ISSET(__idx, &__stack.__buf);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(FD_ISSET_after_end);
+ATF_TC_BODY(FD_ISSET_after_end, tc)
+{
+#define BUF &__stack.__buf
+       struct {
+               uint8_t padding_l;
+               fd_set __buf;
+               uint8_t padding_r;
+       } __stack;
+       const size_t __bufsz __unused = sizeof(__stack.__buf);
+       const size_t __len = FD_SETSIZE + 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();
+       FD_ISSET(__idx, &__stack.__buf);
+       _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(FD_ISSET_heap_before_end);
+ATF_TC_BODY(FD_ISSET_heap_before_end, tc)
+{
+#define BUF __stack.__buf
+       struct {
+               uint8_t padding_l;
+               fd_set * __buf;
+               uint8_t padding_r;
+       } __stack;
+       const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1);
+       const size_t __len = FD_SETSIZE - 1;
+       const size_t __idx __unused = __len - 1;
+
+       __stack.__buf = malloc(__bufsz);
+
+       FD_ISSET(__idx, __stack.__buf);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(FD_ISSET_heap_end);
+ATF_TC_BODY(FD_ISSET_heap_end, tc)
+{
+#define BUF __stack.__buf
+       struct {
+               uint8_t padding_l;
+               fd_set * __buf;
+               uint8_t padding_r;
+       } __stack;
+       const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1);
+       const size_t __len = FD_SETSIZE;
+       const size_t __idx __unused = __len - 1;
+
+       __stack.__buf = malloc(__bufsz);
+
+       FD_ISSET(__idx, __stack.__buf);
+#undef BUF
+
+}
+
+ATF_TC_WITHOUT_HEAD(FD_ISSET_heap_after_end);
+ATF_TC_BODY(FD_ISSET_heap_after_end, tc)
+{
+#define BUF __stack.__buf
+       struct {
+               uint8_t padding_l;
+               fd_set * __buf;
+               uint8_t padding_r;
+       } __stack;
+       const size_t __bufsz __unused = sizeof(*__stack.__buf) * (1);
+       const size_t __len = FD_SETSIZE + 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);
+
+       FD_ISSET(__idx, __stack.__buf);
+       _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, FD_SET_before_end);
+       ATF_TP_ADD_TC(tp, FD_SET_end);
+       ATF_TP_ADD_TC(tp, FD_SET_after_end);
+       ATF_TP_ADD_TC(tp, FD_SET_heap_before_end);
+       ATF_TP_ADD_TC(tp, FD_SET_heap_end);
+       ATF_TP_ADD_TC(tp, FD_SET_heap_after_end);
+       ATF_TP_ADD_TC(tp, FD_CLR_before_end);
+       ATF_TP_ADD_TC(tp, FD_CLR_end);
+       ATF_TP_ADD_TC(tp, FD_CLR_after_end);
+       ATF_TP_ADD_TC(tp, FD_CLR_heap_before_end);
+       ATF_TP_ADD_TC(tp, FD_CLR_heap_end);
+       ATF_TP_ADD_TC(tp, FD_CLR_heap_after_end);
+       ATF_TP_ADD_TC(tp, FD_ISSET_before_end);
+       ATF_TP_ADD_TC(tp, FD_ISSET_end);
+       ATF_TP_ADD_TC(tp, FD_ISSET_after_end);
+       ATF_TP_ADD_TC(tp, FD_ISSET_heap_before_end);
+       ATF_TP_ADD_TC(tp, FD_ISSET_heap_end);
+       ATF_TP_ADD_TC(tp, FD_ISSET_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 75f81c0a0750..61ccc8fc5592 100644
--- a/lib/libc/tests/secure/fortify_stdio_test.c
+++ b/lib/libc/tests/secure/fortify_stdio_test.c
@@ -6,6 +6,7 @@
 #include <sys/param.h>
 #include <sys/random.h>
 #include <sys/resource.h>
+#include <sys/select.h>
 #include <sys/time.h>
 #include <sys/uio.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 8556e1110156..5383b73d4058 100644
--- a/lib/libc/tests/secure/fortify_stdlib_test.c
+++ b/lib/libc/tests/secure/fortify_stdlib_test.c
@@ -6,6 +6,7 @@
 #include <sys/param.h>
 #include <sys/random.h>
 #include <sys/resource.h>
+#include <sys/select.h>
 #include <sys/time.h>
 #include <sys/uio.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 70f247b09e39..918445ca68a1 100644
--- a/lib/libc/tests/secure/fortify_string_test.c
+++ b/lib/libc/tests/secure/fortify_string_test.c
@@ -6,6 +6,7 @@
 #include <sys/param.h>
 #include <sys/random.h>
 #include <sys/resource.h>
+#include <sys/select.h>
 #include <sys/time.h>
 #include <sys/uio.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 e6a8ea0291de..1cecd7033ae3 100644
--- a/lib/libc/tests/secure/fortify_strings_test.c
+++ b/lib/libc/tests/secure/fortify_strings_test.c
@@ -6,6 +6,7 @@
 #include <sys/param.h>
 #include <sys/random.h>
 #include <sys/resource.h>
+#include <sys/select.h>
 #include <sys/time.h>
 #include <sys/uio.h>
 #include <sys/wait.h>
diff --git a/lib/libc/tests/secure/fortify_uio_test.c 
b/lib/libc/tests/secure/fortify_uio_test.c
index 56d7cf5d9a84..0c709ac8b945 100644
--- a/lib/libc/tests/secure/fortify_uio_test.c
+++ b/lib/libc/tests/secure/fortify_uio_test.c
@@ -6,6 +6,7 @@
 #include <sys/param.h>
 #include <sys/random.h>
 #include <sys/resource.h>
+#include <sys/select.h>
 #include <sys/time.h>
 #include <sys/uio.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 7a91d3b06c75..e2127450f565 100644
--- a/lib/libc/tests/secure/fortify_unistd_test.c
+++ b/lib/libc/tests/secure/fortify_unistd_test.c
@@ -6,6 +6,7 @@
 #include <sys/param.h>
 #include <sys/random.h>
 #include <sys/resource.h>
+#include <sys/select.h>
 #include <sys/time.h>
 #include <sys/uio.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 8c5e0782c65a..31ae02c412a7 100644
--- a/lib/libc/tests/secure/fortify_wchar_test.c
+++ b/lib/libc/tests/secure/fortify_wchar_test.c
@@ -6,6 +6,7 @@
 #include <sys/param.h>
 #include <sys/random.h>
 #include <sys/resource.h>
+#include <sys/select.h>
 #include <sys/time.h>
 #include <sys/uio.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 23b33acb757b..fdbc6c550551 100755
--- a/lib/libc/tests/secure/generate-fortify-tests.lua
+++ b/lib/libc/tests/secure/generate-fortify-tests.lua
@@ -64,6 +64,7 @@ local includes = {
        "sys/param.h",
        "sys/random.h",
        "sys/resource.h",
+       "sys/select.h",
        "sys/time.h",
        "sys/uio.h",
        "sys/wait.h",
@@ -169,6 +170,36 @@ local all_tests = {
                        exclude = excludes_stack_overflow,
                },
        },
+       select = {
+               -- <sys/select.h>
+               {
+                       func = "FD_SET",
+                       bufsize = "FD_SETSIZE",
+                       buftype = "fd_set",
+                       arguments = {
+                               "__idx",
+                               "__buf",
+                       },
+               },
+               {
+                       func = "FD_CLR",
+                       bufsize = "FD_SETSIZE",
+                       buftype = "fd_set",
+                       arguments = {
+                               "__idx",
+                               "__buf",
+                       },
+               },
+               {
+                       func = "FD_ISSET",
+                       bufsize = "FD_SETSIZE",
+                       buftype = "fd_set",
+                       arguments = {
+                               "__idx",
+                               "__buf",
+                       },
+               },
+       },
        uio = {
                -- <sys/uio.h>
                {
diff --git a/sys/sys/select.h b/sys/sys/select.h
index 1ded44197de9..9b734754b944 100644
--- a/sys/sys/select.h
+++ b/sys/sys/select.h
@@ -49,6 +49,12 @@ typedef      __fd_mask       fd_mask;
 typedef        __sigset_t      sigset_t;
 #endif
 
+#if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0
+#include <ssp/ssp.h>
+#else
+#define        __SSP_FORTIFY_LEVEL     0
+#endif
+
 /*
  * Select uses bit masks of file descriptors in longs.  These macros
  * manipulate such bit fields (the filesystem macros use chars).
@@ -75,13 +81,33 @@ typedef     struct fd_set {
 #define        fds_bits        __fds_bits
 #endif
 
+#define        __fdset_idx_(p, n)      ((n) / _NFDBITS)
+#if __SSP_FORTIFY_LEVEL == 0
+#define        __fdset_idx(p, n)       __fdset_idx_(p, n)
+#else
+__ssp_inline unsigned long
+__fdset_idx(fd_set *p, unsigned long idx)
+{
+       __size_t psz = __ssp_bos0(p);
+       unsigned long sidx = __fdset_idx_(p, idx);
+
+       if (idx >= FD_SETSIZE)
+               __chk_fail();
+       if (psz / sizeof(__fd_mask) < (sidx + 1))
+               __chk_fail();
+
+       return (sidx);
+}
+#endif
+
 #define        __fdset_mask(n) ((__fd_mask)1 << ((n) % _NFDBITS))
-#define        FD_CLR(n, p)    ((p)->__fds_bits[(n)/_NFDBITS] &= 
~__fdset_mask(n))
+#define        FD_CLR(n, p)    ((p)->__fds_bits[__fdset_idx(p, n)] &= 
~__fdset_mask(n))
 #if __BSD_VISIBLE
 #define        FD_COPY(f, t)   (void)(*(t) = *(f))
 #endif
-#define        FD_ISSET(n, p)  (((p)->__fds_bits[(n)/_NFDBITS] & 
__fdset_mask(n)) != 0)
-#define        FD_SET(n, p)    ((p)->__fds_bits[(n)/_NFDBITS] |= 
__fdset_mask(n))
+#define        FD_ISSET(n, p)  \
+    (((p)->__fds_bits[__fdset_idx(p, n)] & __fdset_mask(n)) != 0)
+#define        FD_SET(n, p)    ((p)->__fds_bits[__fdset_idx(p, n)] |= 
__fdset_mask(n))
 #define        FD_ZERO(p) do {                                 \
        fd_set *_p;                                     \
        __size_t _n;                                    \

Reply via email to