From mboxrd@z Thu Jan 1 00:00:00 1970 Received: by passt.top (Postfix, from userid 1000) id 527C05A031C; Thu, 27 Jun 2024 01:45:36 +0200 (CEST) From: Stefano Brivio To: passt-dev@passt.top Subject: [PATCH 3/4] util, lineread, tap: Overflow checks on long signed sums and subtractions Date: Thu, 27 Jun 2024 01:45:35 +0200 Message-ID: <20240626234536.3306466-4-sbrivio@redhat.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240626234536.3306466-1-sbrivio@redhat.com> References: <20240626234536.3306466-1-sbrivio@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: 3FMROJGZTQPLZJM654RN6WH2PJQEZ53B X-Message-ID-Hash: 3FMROJGZTQPLZJM654RN6WH2PJQEZ53B X-MailFrom: sbrivio@passt.top X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Matej Hrica X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Potential sum and subtraction overflows were reported by Coverity in a few places where we use size_t and ssize_t types. Strictly speaking, those are not false positives even if I don't see a way to trigger those: for instance, if we receive up to n bytes from a socket up, the return value from recv() is already constrained and can't overflow for the usage we make in tap_handler_passt(). In any case, take care of those by adding two functions that explicitly check for overflows in sums and subtractions of long signed values, and using them. Signed-off-by: Stefano Brivio --- lineread.c | 5 +++-- tap.c | 21 +++++++++++++++------ util.c | 7 +++++-- util.h | 46 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 68 insertions(+), 11 deletions(-) diff --git a/lineread.c b/lineread.c index 0387f4a..12f2d24 100644 --- a/lineread.c +++ b/lineread.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "lineread.h" #include "util.h" @@ -102,8 +103,8 @@ ssize_t lineread_get(struct lineread *lr, char **line) if (rc == 0) eof = true; - else - lr->count += rc; + else if (saddl_overflow(lr->count, rc, &lr->count)) + return -ERANGE; } *line = lr->buf + lr->next_line; diff --git a/tap.c b/tap.c index ec994a2..7f8c26d 100644 --- a/tap.c +++ b/tap.c @@ -1031,7 +1031,11 @@ redo: */ if (l2len > n) { rem = recv(c->fd_tap, p + n, l2len - n, 0); - if ((n += rem) != l2len) + + if (saddl_overflow(n, rem, &n)) + return; + + if (n != l2len) return; } @@ -1046,7 +1050,9 @@ redo: next: p += l2len; - n -= l2len; + + if (ssubl_overflow(n, l2len, &n)) + return; } tap_handler(c, now); @@ -1077,17 +1083,20 @@ redo: tap_flush_pools(); restart: while ((len = read(c->fd_tap, pkt_buf + n, TAP_BUF_BYTES - n)) > 0) { - if (len < (ssize_t)sizeof(struct ethhdr) || len > (ssize_t)ETH_MAX_MTU) { - n += len; + if (saddl_overflow(n, len, &n)) + return; + continue; } - tap_add_packet(c, len, pkt_buf + n); - if ((n += len) == TAP_BUF_BYTES) + if (saddl_overflow(n, len, &n)) + return; + + if (n == TAP_BUF_BYTES) break; } diff --git a/util.c b/util.c index dd2e57f..a72d6c5 100644 --- a/util.c +++ b/util.c @@ -567,7 +567,7 @@ int do_clone(int (*fn)(void *), char *stack_area, size_t stack_size, int flags, * * #syscalls write writev */ -int write_remainder(int fd, const struct iovec *iov, int iovcnt, size_t skip) +int write_remainder(int fd, const struct iovec *iov, int iovcnt, ssize_t skip) { int i; size_t offset; @@ -585,7 +585,10 @@ int write_remainder(int fd, const struct iovec *iov, int iovcnt, size_t skip) if (rc < 0) return -1; - skip += rc; + if (saddl_overflow(skip, rc, &skip)) { + errno = -ERANGE; + return -1; + } } return 0; diff --git a/util.h b/util.h index eebb027..497d2fd 100644 --- a/util.h +++ b/util.h @@ -161,7 +161,7 @@ void pidfile_write(int fd, pid_t pid); int __daemon(int pidfile_fd, int devnull_fd); int fls(unsigned long x); int write_file(const char *path, const char *buf); -int write_remainder(int fd, const struct iovec *iov, int iovcnt, size_t skip); +int write_remainder(int fd, const struct iovec *iov, int iovcnt, ssize_t skip); /** * af_name() - Return name of an address family @@ -223,6 +223,50 @@ static inline bool mod_between(unsigned x, unsigned i, unsigned j, unsigned m) return mod_sub(x, i, m) < mod_sub(j, i, m); } +/** + * saddl_overflow() - Sum with overflow check for long signed values + * @a: First value + * @b: Second value + * @sum: Pointer to result of sum, if it doesn't overflow + * + * Return: true if the sum would overflow, false otherwise + */ +static inline bool saddl_overflow(long a, long b, long *sum) +{ +#if __GNUC__ + return __builtin_saddl_overflow(a, b, sum); +#else + if ((a > 0 && a > LONG_MAX - b) || + (b < 0 && a < LONG_MIN - b)) + return true; + + *sum = a + b; + return false; +#endif +} + +/** + * saddl_overflow() - Subtraction with overflow check for long signed values + * @a: Minuend + * @b: Subtrahend + * @sum: Pointer to result of subtraction, if it doesn't overflow + * + * Return: true if the subtraction would overflow, false otherwise + */ +static inline bool ssubl_overflow(long a, long b, long *diff) +{ +#if __GNUC__ + return __builtin_ssubl_overflow(a, b, diff); +#else + if ((b > 0 && a < LONG_MIN + b) || + (b < 0 && a > LONG_MAX + b)) + return true; + + *diff = a - b; + return false; +#endif +} + /* * Workarounds for https://github.com/llvm/llvm-project/issues/58992 * -- 2.43.0