From 4674e3899afcc6b3ac8a48cdb716695d5489d26b Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 2 Feb 2015 09:15:19 -0800 Subject: [PATCH] Fortify poll and ppoll. And remove the test for FD_ZERO fortification, which never made much sense anyway. Change-Id: Id1009c5298d461fa4722189e8ecaf22f0c529536 --- libc/Android.mk | 1 + libc/bionic/__poll_chk.cpp | 49 ++++++++++++++++++++++++++++++++++++++ libc/include/poll.h | 48 +++++++++++++++++++++++++++++++++++-- tests/fortify_test.cpp | 22 ++++++++++------- 4 files changed, 109 insertions(+), 11 deletions(-) create mode 100644 libc/bionic/__poll_chk.cpp diff --git a/libc/Android.mk b/libc/Android.mk index 691017a8b..90f1a1213 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -69,6 +69,7 @@ libc_common_src_files += \ bionic/__FD_chk.cpp \ bionic/__fgets_chk.cpp \ bionic/__memmove_chk.cpp \ + bionic/__poll_chk.cpp \ bionic/__read_chk.cpp \ bionic/__recvfrom_chk.cpp \ bionic/__stpcpy_chk.cpp \ diff --git a/libc/bionic/__poll_chk.cpp b/libc/bionic/__poll_chk.cpp new file mode 100644 index 000000000..3acac4e6a --- /dev/null +++ b/libc/bionic/__poll_chk.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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. + */ + +#undef _FORTIFY_SOURCE +#include +#include "private/libc_logging.h" + +#include + +extern "C" int __poll_chk(struct pollfd* fds, nfds_t fd_count, int timeout, size_t fds_size) { +fprintf(stderr, "__poll_chk %p %i %i %i\n", fds, (int)fd_count, timeout, (int) fds_size); + if (__predict_false(fds_size / sizeof(*fds) < fd_count)) { + __fortify_chk_fail("poll: pollfd array smaller than fd count", 0); + } + return poll(fds, fd_count, timeout); +} + +extern "C" int __ppoll_chk(struct pollfd* fds, nfds_t fd_count, const struct timespec* timeout, const sigset_t* mask, size_t fds_size) { +fprintf(stderr, "__ppoll_chk %p %i %p %p %i\n", fds, (int)fd_count, timeout, mask, (int) fds_size); + if (__predict_false(fds_size / sizeof(*fds) < fd_count)) { + __fortify_chk_fail("ppoll: pollfd array smaller than fd count", 0); + } + return ppoll(fds, fd_count, timeout, mask); +} diff --git a/libc/include/poll.h b/libc/include/poll.h index 0199cab2c..7c16d8173 100644 --- a/libc/include/poll.h +++ b/libc/include/poll.h @@ -38,8 +38,52 @@ __BEGIN_DECLS typedef unsigned int nfds_t; -extern int poll(struct pollfd*, nfds_t, int); -extern int ppoll(struct pollfd*, nfds_t, const struct timespec*, const sigset_t*); +int poll(struct pollfd*, nfds_t, int); +int ppoll(struct pollfd*, nfds_t, const struct timespec*, const sigset_t*); + +int __poll_chk(struct pollfd*, nfds_t, int, size_t); +int __poll_real(struct pollfd*, nfds_t, int) __RENAME(poll); +__errordecl(__poll_too_small_error, "poll: pollfd array smaller than fd count"); + +int __ppoll_chk(struct pollfd*, nfds_t, const struct timespec*, const sigset_t*, size_t); +int __ppoll_real(struct pollfd*, nfds_t, const struct timespec*, const sigset_t*) __RENAME(ppoll); +__errordecl(__ppoll_too_small_error, "ppoll: pollfd array smaller than fd count"); + +#if defined(__BIONIC_FORTIFY) + +__BIONIC_FORTIFY_INLINE +int poll(struct pollfd* fds, nfds_t fd_count, int timeout) { +#if defined(__clang__) + return __poll_chk(fds, fd_count, timeout, __bos(fds)); +#else + if (__bos(fds) != __BIONIC_FORTIFY_UNKNOWN_SIZE) { + if (!__builtin_constant_p(fd_count)) { + return __poll_chk(fds, fd_count, timeout, __bos(fds)); + } else if (__bos(fds) / sizeof(*fds) < fd_count) { + __poll_too_small_error(); + } + } + return __poll_real(fds, fd_count, timeout); +#endif +} + +__BIONIC_FORTIFY_INLINE +int ppoll(struct pollfd* fds, nfds_t fd_count, const struct timespec* timeout, const sigset_t* mask) { +#if defined(__clang__) + return __ppoll_chk(fds, fd_count, timeout, mask, __bos(fds)); +#else + if (__bos(fds) != __BIONIC_FORTIFY_UNKNOWN_SIZE) { + if (!__builtin_constant_p(fd_count)) { + return __ppoll_chk(fds, fd_count, timeout, mask, __bos(fds)); + } else if (__bos(fds) / sizeof(*fds) < fd_count) { + __ppoll_too_small_error(); + } + } + return __ppoll_real(fds, fd_count, timeout, mask); +#endif +} + +#endif __END_DECLS diff --git a/tests/fortify_test.cpp b/tests/fortify_test.cpp index 48764aa9f..de279b1a2 100644 --- a/tests/fortify_test.cpp +++ b/tests/fortify_test.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -629,15 +630,6 @@ TEST_F(DEATHTEST, FD_ISSET_2_fortified) { ASSERT_EXIT(FD_ISSET(0, set), testing::KilledBySignal(SIGABRT), ""); } -// gtest's ASSERT_EXIT needs a valid expression, but glibc has a do-while macro. -static void FD_ZERO_function(fd_set* s) { FD_ZERO(s); } - -TEST_F(DEATHTEST, FD_ZERO_fortified) { - char buf[1]; - fd_set* set = (fd_set*) buf; - ASSERT_EXIT(FD_ZERO_function(set), testing::KilledBySignal(SIGABRT), ""); -} - TEST_F(DEATHTEST, read_fortified) { char buf[1]; size_t ct = atoi("2"); // prevent optimizations @@ -950,3 +942,15 @@ TEST(TEST_NAME, s_n_printf_macro_expansion) { sprintf(BUF_AND_CONTENTS(buf)); EXPECT_STREQ(CONTENTS, buf); } + +TEST_F(DEATHTEST, poll_fortified) { + nfds_t fd_count = atoi("2"); // suppress compiler optimizations + pollfd buf[1] = {{0, POLLIN, 0}}; + ASSERT_EXIT(poll(buf, fd_count, -1), testing::KilledBySignal(SIGABRT), ""); +} + +TEST_F(DEATHTEST, ppoll_fortified) { + nfds_t fd_count = atoi("2"); // suppress compiler optimizations + pollfd buf[1] = {{0, POLLIN, 0}}; + ASSERT_EXIT(ppoll(buf, fd_count, NULL, NULL), testing::KilledBySignal(SIGABRT), ""); +}