From: Yu Watanabe Date: Wed, 18 Oct 2023 09:10:50 +0000 (+0900) Subject: macro: introduce u64_multiply_safe() to avoid overflow X-Git-Tag: v255-rc1~156^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ffee7b97e3009d7d7370c80da42af766cc718c72;p=thirdparty%2Fsystemd.git macro: introduce u64_multiply_safe() to avoid overflow Just a paranoia. --- diff --git a/src/basic/macro.h b/src/basic/macro.h index dcd1ca96fd4..d3eb980abd3 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -51,6 +51,13 @@ #error "neither int nor long are four bytes long?!?" #endif +static inline uint64_t u64_multiply_safe(uint64_t a, uint64_t b) { + if (_unlikely_(a != 0 && b > (UINT64_MAX / a))) + return 0; /* overflow */ + + return a * b; +} + /* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */ static inline unsigned long ALIGN_POWER2(unsigned long u) { diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c index 7af439c2e73..d138e380963 100644 --- a/src/libsystemd/sd-journal/journal-file.c +++ b/src/libsystemd/sd-journal/journal-file.c @@ -795,7 +795,7 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) if (fstatvfs(f->fd, &svfs) >= 0) { uint64_t available; - available = LESS_BY((uint64_t) svfs.f_bfree * (uint64_t) svfs.f_bsize, f->metrics.keep_free); + available = LESS_BY(u64_multiply_safe(svfs.f_bfree, svfs.f_bsize), f->metrics.keep_free); if (new_size - old_size > available) return -E2BIG; @@ -3881,7 +3881,7 @@ static void journal_default_metrics(JournalMetrics *m, int fd, bool compact) { assert(fd >= 0); if (fstatvfs(fd, &ss) >= 0) - fs_size = ss.f_frsize * ss.f_blocks; + fs_size = u64_multiply_safe(ss.f_frsize, ss.f_blocks); else log_debug_errno(errno, "Failed to determine disk size: %m"); diff --git a/src/test/test-macro.c b/src/test/test-macro.c index 1b5ef9718e0..63fe6ea95e7 100644 --- a/src/test/test-macro.c +++ b/src/test/test-macro.c @@ -1012,4 +1012,29 @@ TEST(round_up) { TEST_ROUND_UP_BY_TYPE(uint64_t, UINT64_MAX); } +TEST(u64_multiply_safe) { + assert_se(u64_multiply_safe(0, 0) == 0); + assert_se(u64_multiply_safe(10, 0) == 0); + assert_se(u64_multiply_safe(0, 10) == 0); + assert_se(u64_multiply_safe(10, 10) == 100); + + assert_se(u64_multiply_safe(UINT64_MAX, 0) == 0); + assert_se(u64_multiply_safe(UINT64_MAX, 1) == UINT64_MAX); + assert_se(u64_multiply_safe(UINT64_MAX, 2) == 0); + assert_se(u64_multiply_safe(0, UINT64_MAX) == 0); + assert_se(u64_multiply_safe(1, UINT64_MAX) == UINT64_MAX); + assert_se(u64_multiply_safe(2, UINT64_MAX) == 0); + + assert_se(u64_multiply_safe(UINT64_MAX / 2, 0) == 0); + assert_se(u64_multiply_safe(UINT64_MAX / 2, 1) == UINT64_MAX / 2); + assert_se(u64_multiply_safe(UINT64_MAX / 2, 2) == UINT64_MAX - 1); + assert_se(u64_multiply_safe(UINT64_MAX / 2, 3) == 0); + assert_se(u64_multiply_safe(0, UINT64_MAX / 2) == 0); + assert_se(u64_multiply_safe(1, UINT64_MAX / 2) == UINT64_MAX / 2); + assert_se(u64_multiply_safe(2, UINT64_MAX / 2) == UINT64_MAX - 1); + assert_se(u64_multiply_safe(3, UINT64_MAX / 2) == 0); + + assert_se(u64_multiply_safe(UINT64_MAX, UINT64_MAX) == 0); +} + DEFINE_TEST_MAIN(LOG_INFO);