diff --git a/src/basic/argv-util.c b/src/basic/argv-util.c index 6c88dcc2ee..a2bcc44678 100644 --- a/src/basic/argv-util.c +++ b/src/basic/argv-util.c @@ -81,6 +81,9 @@ static int update_argv(const char name[], size_t l) { static int can_do = -1; int r; + assert(name); + assert(l < SIZE_MAX); + if (can_do == 0) return 0; can_do = false; /* We'll set it to true only if the whole process works */ @@ -102,6 +105,9 @@ static int update_argv(const char name[], size_t l) { char *nn; nn_size = PAGE_ALIGN(l+1); + if (nn_size >= SIZE_MAX) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "The requested argument is too long."); + nn = mmap(NULL, nn_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if (nn == MAP_FAILED) return log_debug_errno(errno, "mmap() failed: %m"); diff --git a/src/basic/io-util.c b/src/basic/io-util.c index ede959fabc..dee59947aa 100644 --- a/src/basic/io-util.c +++ b/src/basic/io-util.c @@ -284,7 +284,7 @@ ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) { return -EIO; } - if (lseek(fd, n, SEEK_CUR) == (off_t) -1) + if (lseek(fd, n, SEEK_CUR) < 0) return -errno; q += n; diff --git a/src/basic/macro.h b/src/basic/macro.h index dcd1ca96fd..d3eb980abd 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/basic/memory-util.h b/src/basic/memory-util.h index b5e3984a09..11795135f9 100644 --- a/src/basic/memory-util.h +++ b/src/basic/memory-util.h @@ -12,9 +12,12 @@ #include "memory-util-fundamental.h" size_t page_size(void) _pure_; -#define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) -#define PAGE_ALIGN_DOWN(l) ((l) & ~(page_size() - 1)) -#define PAGE_OFFSET(l) ((l) & (page_size() - 1)) +#define PAGE_ALIGN(l) ALIGN_TO(l, page_size()) +#define PAGE_ALIGN_U64(l) ALIGN_TO_U64(l, page_size()) +#define PAGE_ALIGN_DOWN(l) ALIGN_DOWN(l, page_size()) +#define PAGE_ALIGN_DOWN_U64(l) ALIGN_DOWN_U64(l, page_size()) +#define PAGE_OFFSET(l) ALIGN_OFFSET(l, page_size()) +#define PAGE_OFFSET_U64(l) ALIGN_OFFSET_U64(l, page_size()) /* Normal memcpy() requires src to be nonnull. We do nothing if n is 0. */ static inline void *memcpy_safe(void *dst, const void *src, size_t n) { diff --git a/src/boot/bootctl-install.c b/src/boot/bootctl-install.c index e6f66deeab..fb7cda7df5 100644 --- a/src/boot/bootctl-install.c +++ b/src/boot/bootctl-install.c @@ -233,7 +233,7 @@ static int copy_file_with_version_check(const char *from, const char *to, bool f if (r < 0) return r; - if (lseek(fd_from, 0, SEEK_SET) == (off_t) -1) + if (lseek(fd_from, 0, SEEK_SET) < 0) return log_error_errno(errno, "Failed to seek in \"%s\": %m", from); fd_to = safe_close(fd_to); diff --git a/src/core/execute.c b/src/core/execute.c index 11513b267d..df4c213c6d 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -405,7 +405,7 @@ int exec_spawn(Unit *unit, if (r < 0) return log_unit_error_errno(unit, r, "Failed to serialize parameters: %m"); - if (fseeko(f, 0, SEEK_SET) == (off_t) -1) + if (fseeko(f, 0, SEEK_SET) < 0) return log_unit_error_errno(unit, errno, "Failed to reseek on serialization stream: %m"); r = fd_cloexec(fileno(f), false); diff --git a/src/core/main.c b/src/core/main.c index cbcf3ddeea..cfa29f3a58 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1108,7 +1108,7 @@ static int prepare_reexecute( if (r < 0) return r; - if (fseeko(f, 0, SEEK_SET) == (off_t) -1) + if (fseeko(f, 0, SEEK_SET) < 0) return log_error_errno(errno, "Failed to rewind serialization fd: %m"); r = fd_cloexec(fileno(f), false); diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 1a49c8d777..40505e35f3 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -531,7 +531,7 @@ static int save_external_coredump( _cleanup_close_ int fd_compressed = -EBADF; uint64_t uncompressed_size = 0; - if (lseek(fd, 0, SEEK_SET) == (off_t) -1) + if (lseek(fd, 0, SEEK_SET) < 0) return log_error_errno(errno, "Failed to seek on coredump %s: %m", fn); fn_compressed = strjoin(fn, default_compression_extension()); @@ -595,7 +595,7 @@ static int save_external_coredump( if (fstat(fd, &st) < 0) return log_error_errno(errno, "Failed to fstat core file %s: %m", coredump_tmpfile_name(tmp)); - if (lseek(fd, 0, SEEK_SET) == (off_t) -1) + if (lseek(fd, 0, SEEK_SET) < 0) return log_error_errno(errno, "Failed to seek on coredump %s: %m", fn); *ret_filename = TAKE_PTR(fn); @@ -614,7 +614,7 @@ static int allocate_journal_field(int fd, size_t size, char **ret, size_t *ret_s assert(ret); assert(ret_size); - if (lseek(fd, 0, SEEK_SET) == (off_t) -1) + if (lseek(fd, 0, SEEK_SET) < 0) return log_warning_errno(errno, "Failed to seek: %m"); field = malloc(9 + size); diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h index fa9aeafb98..797330dd97 100644 --- a/src/fundamental/macro-fundamental.h +++ b/src/fundamental/macro-fundamental.h @@ -376,7 +376,40 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) { if (l > SIZE_MAX - (ali - 1)) return SIZE_MAX; /* indicate overflow */ - return ((l + ali - 1) & ~(ali - 1)); + return ((l + (ali - 1)) & ~(ali - 1)); +} + +static inline uint64_t ALIGN_TO_U64(uint64_t l, uint64_t ali) { + assert(ISPOWEROF2(ali)); + + if (l > UINT64_MAX - (ali - 1)) + return UINT64_MAX; /* indicate overflow */ + + return ((l + (ali - 1)) & ~(ali - 1)); +} + +static inline size_t ALIGN_DOWN(size_t l, size_t ali) { + assert(ISPOWEROF2(ali)); + + return l & ~(ali - 1); +} + +static inline uint64_t ALIGN_DOWN_U64(uint64_t l, uint64_t ali) { + assert(ISPOWEROF2(ali)); + + return l & ~(ali - 1); +} + +static inline size_t ALIGN_OFFSET(size_t l, size_t ali) { + assert(ISPOWEROF2(ali)); + + return l & (ali - 1); +} + +static inline uint64_t ALIGN_OFFSET_U64(uint64_t l, uint64_t ali) { + assert(ISPOWEROF2(ali)); + + return l & (ali - 1); } #define ALIGN2(l) ALIGN_TO(l, 2) diff --git a/src/home/homed-home.c b/src/home/homed-home.c index 206f6480ac..749670f94b 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -519,7 +519,7 @@ static int home_parse_worker_stdout(int _fd, UserRecord **ret) { return 0; } - if (lseek(fd, SEEK_SET, 0) == (off_t) -1) + if (lseek(fd, SEEK_SET, 0) < 0) return log_error_errno(errno, "Failed to seek to beginning of memfd: %m"); f = take_fdopen(&fd, "r"); diff --git a/src/import/import-raw.c b/src/import/import-raw.c index feb6ac1bdd..2db3198ba6 100644 --- a/src/import/import-raw.c +++ b/src/import/import-raw.c @@ -303,7 +303,7 @@ static int raw_import_open_disk(RawImport *i) { "Target file is not a regular file or block device"); if (i->offset != UINT64_MAX) { - if (lseek(i->output_fd, i->offset, SEEK_SET) == (off_t) -1) + if (lseek(i->output_fd, i->offset, SEEK_SET) < 0) return log_error_errno(errno, "Failed to seek to offset: %m"); } @@ -328,7 +328,7 @@ static int raw_import_try_reflink(RawImport *i) { return 0; p = lseek(i->input_fd, 0, SEEK_CUR); - if (p == (off_t) -1) + if (p < 0) return log_error_errno(errno, "Failed to read file offset of input file: %m"); /* Let's only try a btrfs reflink, if we are reading from the beginning of the file */ diff --git a/src/import/pull-job.c b/src/import/pull-job.c index d05bf3cd49..bed7e64030 100644 --- a/src/import/pull-job.c +++ b/src/import/pull-job.c @@ -415,7 +415,7 @@ static int pull_job_open_disk(PullJob *j) { return log_error_errno(errno, "Failed to stat disk file: %m"); if (j->offset != UINT64_MAX) { - if (lseek(j->disk_fd, j->offset, SEEK_SET) == (off_t) -1) + if (lseek(j->disk_fd, j->offset, SEEK_SET) < 0) return log_error_errno(errno, "Failed to seek on file descriptor: %m"); } } diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c index 3befa96a04..e96be4dd7d 100644 --- a/src/import/pull-raw.c +++ b/src/import/pull-raw.c @@ -370,7 +370,7 @@ static int raw_pull_make_local_copy(RawPull *i) { assert(i->raw_job->disk_fd >= 0); assert(i->offset == UINT64_MAX); - if (lseek(i->raw_job->disk_fd, SEEK_SET, 0) == (off_t) -1) + if (lseek(i->raw_job->disk_fd, SEEK_SET, 0) < 0) return log_error_errno(errno, "Failed to seek to beginning of vendor image: %m"); } diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index 980b98137e..09194710cb 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -233,7 +233,7 @@ static ssize_t request_reader_entries( } sz = ftello(m->tmp); - if (sz == (off_t) -1) { + if (sz < 0) { log_error_errno(errno, "Failed to retrieve file position: %m"); return MHD_CONTENT_READER_END_WITH_ERROR; } @@ -582,7 +582,7 @@ static ssize_t request_reader_fields( } sz = ftello(m->tmp); - if (sz == (off_t) -1) { + if (sz < 0) { log_error_errno(errno, "Failed to retrieve file position: %m"); return MHD_CONTENT_READER_END_WITH_ERROR; } diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index 06073ac0a5..4f030dda86 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -405,6 +405,7 @@ void server_process_native_file( /* The file is sealed, we can just map it and use it. */ ps = PAGE_ALIGN(st.st_size); + assert(ps < SIZE_MAX); p = mmap(NULL, ps, PROT_READ, MAP_PRIVATE, fd, 0); if (p == MAP_FAILED) { log_ratelimit_error_errno(errno, JOURNAL_LOG_RATELIMIT, diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c index b553f15396..d7ff83441b 100644 --- a/src/libsystemd/sd-bus/bus-kernel.c +++ b/src/libsystemd/sd-bus/bus-kernel.c @@ -27,8 +27,11 @@ #include "memory-util.h" void close_and_munmap(int fd, void *address, size_t size) { - if (size > 0) - assert_se(munmap(address, PAGE_ALIGN(size)) >= 0); + if (size > 0) { + size = PAGE_ALIGN(size); + assert(size < SIZE_MAX); + assert_se(munmap(address, size) >= 0); + } safe_close(fd); } diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index f0818b801c..ff0228081f 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -2490,6 +2490,8 @@ int bus_body_part_map(struct bus_body_part *part) { shift = PAGE_OFFSET(part->memfd_offset); psz = PAGE_ALIGN(part->size + shift); + if (psz >= SIZE_MAX) + return -EFBIG; if (part->memfd >= 0) p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE, part->memfd, part->memfd_offset - shift); diff --git a/src/libsystemd/sd-journal/journal-authenticate.c b/src/libsystemd/sd-journal/journal-authenticate.c index 42af483d22..10e5eafbfc 100644 --- a/src/libsystemd/sd-journal/journal-authenticate.c +++ b/src/libsystemd/sd-journal/journal-authenticate.c @@ -379,7 +379,9 @@ int journal_file_fss_load(JournalFile *f) { if (le64toh(header->start_usec) <= 0 || le64toh(header->interval_usec) <= 0) return -EBADMSG; - f->fss_file = mmap(NULL, PAGE_ALIGN(f->fss_file_size), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + size_t sz = PAGE_ALIGN(f->fss_file_size); + assert(sz < SIZE_MAX); + f->fss_file = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (f->fss_file == MAP_FAILED) { f->fss_file = NULL; return -errno; diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c index 5982938fb9..334a28f948 100644 --- a/src/libsystemd/sd-journal/journal-file.c +++ b/src/libsystemd/sd-journal/journal-file.c @@ -47,30 +47,31 @@ #define DEFAULT_COMPRESS_THRESHOLD (512ULL) #define MIN_COMPRESS_THRESHOLD (8ULL) -/* This is the minimum journal file size */ -#define JOURNAL_FILE_SIZE_MIN (512 * 1024ULL) /* 512 KiB */ -#define JOURNAL_COMPACT_SIZE_MAX UINT32_MAX /* 4 GiB */ +#define U64_KB UINT64_C(1024) +#define U64_MB (UINT64_C(1024) * U64_KB) +#define U64_GB (UINT64_C(1024) * U64_MB) -/* These are the lower and upper bounds if we deduce the max_use value - * from the file system size */ -#define MAX_USE_LOWER (1 * 1024 * 1024ULL) /* 1 MiB */ -#define MAX_USE_UPPER (4 * 1024 * 1024 * 1024ULL) /* 4 GiB */ +/* This is the minimum journal file size */ +#define JOURNAL_FILE_SIZE_MIN (512 * U64_KB) /* 512 KiB */ +#define JOURNAL_COMPACT_SIZE_MAX ((uint64_t) UINT32_MAX) /* 4 GiB */ + +/* These are the lower and upper bounds if we deduce the max_use value from the file system size */ +#define MAX_USE_LOWER (1 * U64_MB) /* 1 MiB */ +#define MAX_USE_UPPER (4 * U64_GB) /* 4 GiB */ /* Those are the lower and upper bounds for the minimal use limit, * i.e. how much we'll use even if keep_free suggests otherwise. */ -#define MIN_USE_LOW (1 * 1024 * 1024ULL) /* 1 MiB */ -#define MIN_USE_HIGH (16 * 1024 * 1024ULL) /* 16 MiB */ +#define MIN_USE_LOW (1 * U64_MB) /* 1 MiB */ +#define MIN_USE_HIGH (16 * U64_MB) /* 16 MiB */ /* This is the upper bound if we deduce max_size from max_use */ -#define MAX_SIZE_UPPER (128 * 1024 * 1024ULL) /* 128 MiB */ +#define MAX_SIZE_UPPER (128 * U64_MB) /* 128 MiB */ -/* This is the upper bound if we deduce the keep_free value from the - * file system size */ -#define KEEP_FREE_UPPER (4 * 1024 * 1024 * 1024ULL) /* 4 GiB */ +/* This is the upper bound if we deduce the keep_free value from the file system size */ +#define KEEP_FREE_UPPER (4 * U64_GB) /* 4 GiB */ -/* This is the keep_free value when we can't determine the system - * size */ -#define DEFAULT_KEEP_FREE (1024 * 1024ULL) /* 1 MB */ +/* This is the keep_free value when we can't determine the system size */ +#define DEFAULT_KEEP_FREE (1 * U64_MB) /* 1 MB */ /* This is the default maximum number of journal files to keep around. */ #define DEFAULT_N_MAX_FILES 100 @@ -82,7 +83,7 @@ #define CHAIN_CACHE_MAX 20 /* How much to increase the journal file size at once each time we allocate something new. */ -#define FILE_SIZE_INCREASE (8 * 1024 * 1024ULL) /* 8MB */ +#define FILE_SIZE_INCREASE (8 * U64_MB) /* 8MB */ /* Reread fstat() of the file for detecting deletions at least this often */ #define LAST_STAT_REFRESH_USEC (5*USEC_PER_SEC) @@ -301,9 +302,11 @@ JournalFile* journal_file_close(JournalFile *f) { #endif #if HAVE_GCRYPT - if (f->fss_file) - munmap(f->fss_file, PAGE_ALIGN(f->fss_file_size)); - else + if (f->fss_file) { + size_t sz = PAGE_ALIGN(f->fss_file_size); + assert(sz < SIZE_MAX); + munmap(f->fss_file, sz); + } else free(f->fsprg_state); free(f->fsprg_seed); @@ -750,7 +753,7 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) /* We assume that this file is not sparse, and we know that for sure, since we always call * posix_fallocate() ourselves */ - if (size > PAGE_ALIGN_DOWN(UINT64_MAX) - offset) + if (size > PAGE_ALIGN_DOWN_U64(UINT64_MAX) - offset) return -EINVAL; if (mmap_cache_fd_got_sigbus(f->cache_fd)) @@ -758,12 +761,12 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) old_header_size = le64toh(READ_NOW(f->header->header_size)); old_arena_size = le64toh(READ_NOW(f->header->arena_size)); - if (old_arena_size > PAGE_ALIGN_DOWN(UINT64_MAX) - old_header_size) + if (old_arena_size > PAGE_ALIGN_DOWN_U64(UINT64_MAX) - old_header_size) return -EBADMSG; old_size = old_header_size + old_arena_size; - new_size = MAX(PAGE_ALIGN(offset + size), old_header_size); + new_size = MAX(PAGE_ALIGN_U64(offset + size), old_header_size); if (new_size <= old_size) { @@ -794,7 +797,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; @@ -3880,19 +3883,19 @@ 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"); if (m->max_use == UINT64_MAX) { if (fs_size > 0) - m->max_use = CLAMP(PAGE_ALIGN(fs_size / 10), /* 10% of file system size */ + m->max_use = CLAMP(PAGE_ALIGN_U64(fs_size / 10), /* 10% of file system size */ MAX_USE_LOWER, MAX_USE_UPPER); else m->max_use = MAX_USE_LOWER; } else { - m->max_use = PAGE_ALIGN(m->max_use); + m->max_use = PAGE_ALIGN_U64(m->max_use); if (m->max_use != 0 && m->max_use < JOURNAL_FILE_SIZE_MIN*2) m->max_use = JOURNAL_FILE_SIZE_MIN*2; @@ -3900,7 +3903,7 @@ static void journal_default_metrics(JournalMetrics *m, int fd, bool compact) { if (m->min_use == UINT64_MAX) { if (fs_size > 0) - m->min_use = CLAMP(PAGE_ALIGN(fs_size / 50), /* 2% of file system size */ + m->min_use = CLAMP(PAGE_ALIGN_U64(fs_size / 50), /* 2% of file system size */ MIN_USE_LOW, MIN_USE_HIGH); else m->min_use = MIN_USE_LOW; @@ -3910,10 +3913,10 @@ static void journal_default_metrics(JournalMetrics *m, int fd, bool compact) { m->min_use = m->max_use; if (m->max_size == UINT64_MAX) - m->max_size = MIN(PAGE_ALIGN(m->max_use / 8), /* 8 chunks */ + m->max_size = MIN(PAGE_ALIGN_U64(m->max_use / 8), /* 8 chunks */ MAX_SIZE_UPPER); else - m->max_size = PAGE_ALIGN(m->max_size); + m->max_size = PAGE_ALIGN_U64(m->max_size); if (compact && m->max_size > JOURNAL_COMPACT_SIZE_MAX) m->max_size = JOURNAL_COMPACT_SIZE_MAX; @@ -3929,13 +3932,13 @@ static void journal_default_metrics(JournalMetrics *m, int fd, bool compact) { if (m->min_size == UINT64_MAX) m->min_size = JOURNAL_FILE_SIZE_MIN; else - m->min_size = CLAMP(PAGE_ALIGN(m->min_size), + m->min_size = CLAMP(PAGE_ALIGN_U64(m->min_size), JOURNAL_FILE_SIZE_MIN, m->max_size ?: UINT64_MAX); if (m->keep_free == UINT64_MAX) { if (fs_size > 0) - m->keep_free = MIN(PAGE_ALIGN(fs_size / 20), /* 5% of file system size */ + m->keep_free = MIN(PAGE_ALIGN_U64(fs_size / 20), /* 5% of file system size */ KEEP_FREE_UPPER); else m->keep_free = DEFAULT_KEEP_FREE; diff --git a/src/libsystemd/sd-journal/mmap-cache.c b/src/libsystemd/sd-journal/mmap-cache.c index 8b3f644f2d..e5e03bf83c 100644 --- a/src/libsystemd/sd-journal/mmap-cache.c +++ b/src/libsystemd/sd-journal/mmap-cache.c @@ -71,7 +71,7 @@ struct MMapCache { /* Tiny windows increase mmap activity and the chance of exposing unsafe use. */ # define WINDOW_SIZE (page_size()) #else -# define WINDOW_SIZE (8ULL*1024ULL*1024ULL) +# define WINDOW_SIZE ((size_t) (UINT64_C(8) * UINT64_C(1024) * UINT64_C(1024))) #endif MMapCache* mmap_cache_new(void) { @@ -269,7 +269,6 @@ static int add_mmap( struct stat *st, Window **ret) { - uint64_t woffset, wsize; Window *w; void *d; int r; @@ -278,41 +277,42 @@ static int add_mmap( assert(size > 0); assert(ret); - woffset = offset & ~((uint64_t) page_size() - 1ULL); - wsize = size + (offset - woffset); - wsize = PAGE_ALIGN(wsize); + /* overflow check */ + if (size > SIZE_MAX - PAGE_OFFSET_U64(offset)) + return -EADDRNOTAVAIL; - if (wsize < WINDOW_SIZE) { + size = PAGE_ALIGN(size + PAGE_OFFSET_U64(offset)); + offset = PAGE_ALIGN_DOWN_U64(offset); + + if (size < WINDOW_SIZE) { uint64_t delta; - delta = PAGE_ALIGN((WINDOW_SIZE - wsize) / 2); - - if (delta > offset) - woffset = 0; - else - woffset -= delta; - - wsize = WINDOW_SIZE; + delta = PAGE_ALIGN((WINDOW_SIZE - size) / 2); + offset = LESS_BY(offset, delta); + size = WINDOW_SIZE; } if (st) { /* Memory maps that are larger then the files underneath have undefined behavior. Hence, * clamp things to the file size if we know it */ - if (woffset >= (uint64_t) st->st_size) + if (offset >= (uint64_t) st->st_size) return -EADDRNOTAVAIL; - if (woffset + wsize > (uint64_t) st->st_size) - wsize = PAGE_ALIGN(st->st_size - woffset); + if (size > (uint64_t) st->st_size - offset) + size = PAGE_ALIGN((uint64_t) st->st_size - offset); } - r = mmap_try_harder(f, NULL, MAP_SHARED, woffset, wsize, &d); + if (size >= SIZE_MAX) + return -EADDRNOTAVAIL; + + r = mmap_try_harder(f, NULL, MAP_SHARED, offset, size, &d); if (r < 0) return r; - w = window_add(f, woffset, wsize, d); + w = window_add(f, offset, size, d); if (!w) { - (void) munmap(d, wsize); + (void) munmap(d, size); return -ENOMEM; } diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 979eb3cee7..a12eb516cc 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -613,7 +613,7 @@ static int clean_pool_done(Operation *operation, int ret, sd_bus_error *error) { assert(operation); assert(operation->extra_fd >= 0); - if (lseek(operation->extra_fd, 0, SEEK_SET) == (off_t) -1) + if (lseek(operation->extra_fd, 0, SEEK_SET) < 0) return -errno; f = take_fdopen(&operation->extra_fd, "r"); diff --git a/src/partition/repart.c b/src/partition/repart.c index 9109ea1823..e8a492c7ce 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -3561,7 +3561,7 @@ static int partition_target_prepare( }; if (!need_path) { - if (lseek(whole_fd, p->offset, SEEK_SET) == (off_t) -1) + if (lseek(whole_fd, p->offset, SEEK_SET) < 0) return log_error_errno(errno, "Failed to seek to partition offset: %m"); t->whole_fd = whole_fd; @@ -3637,10 +3637,10 @@ static int partition_target_sync(Context *context, Partition *p, PartitionTarget } else if (t->fd >= 0) { struct stat st; - if (lseek(whole_fd, p->offset, SEEK_SET) == (off_t) -1) + if (lseek(whole_fd, p->offset, SEEK_SET) < 0) return log_error_errno(errno, "Failed to seek to partition offset: %m"); - if (lseek(t->fd, 0, SEEK_SET) == (off_t) -1) + if (lseek(t->fd, 0, SEEK_SET) < 0) return log_error_errno(errno, "Failed to seek to start of temporary file: %m"); if (fstat(t->fd, &st) < 0) @@ -4194,7 +4194,7 @@ static int partition_format_verity_sig(Context *context, Partition *p) { if (r < 0) return log_error_errno(r, "Failed to pad string to %s", FORMAT_BYTES(p->new_size)); - if (lseek(whole_fd, p->offset, SEEK_SET) == (off_t) -1) + if (lseek(whole_fd, p->offset, SEEK_SET) < 0) return log_error_errno(errno, "Failed to seek to partition %s offset: %m", strna(hint)); r = loop_write(whole_fd, text, p->new_size); diff --git a/src/shared/elf-util.c b/src/shared/elf-util.c index 57a1bb9daa..5a4d3bbb50 100644 --- a/src/shared/elf-util.c +++ b/src/shared/elf-util.c @@ -588,7 +588,7 @@ static int parse_core(int fd, const char *executable, char **ret, JsonVariant ** assert(fd >= 0); - if (lseek(fd, 0, SEEK_SET) == (off_t) -1) + if (lseek(fd, 0, SEEK_SET) < 0) return log_warning_errno(errno, "Failed to seek to beginning of the core file: %m"); if (ret && !memstream_init(&c.m)) @@ -644,7 +644,7 @@ static int parse_elf(int fd, const char *executable, char **ret, JsonVariant **r assert(fd >= 0); - if (lseek(fd, 0, SEEK_SET) == (off_t) -1) + if (lseek(fd, 0, SEEK_SET) < 0) return log_warning_errno(errno, "Failed to seek to beginning of the ELF file: %m"); if (ret && !memstream_init(&c.m)) diff --git a/src/shared/machine-id-setup.c b/src/shared/machine-id-setup.c index 7263b6a204..d6aa667ada 100644 --- a/src/shared/machine-id-setup.c +++ b/src/shared/machine-id-setup.c @@ -151,7 +151,7 @@ int machine_id_setup(const char *root, bool force_transient, sd_id128_t machine_ } if (writable) { - if (lseek(fd, 0, SEEK_SET) == (off_t) -1) + if (lseek(fd, 0, SEEK_SET) < 0) return log_error_errno(errno, "Failed to seek %s: %m", etc_machine_id); if (ftruncate(fd, 0) < 0) diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c index 43e04c6518..8d50971356 100644 --- a/src/shared/tpm2-util.c +++ b/src/shared/tpm2-util.c @@ -4594,7 +4594,7 @@ static int tpm2_userspace_log( if (r < 0) return log_debug_errno(r, "Failed to format JSON: %m"); - if (lseek(fd, 0, SEEK_END) == (off_t) -1) + if (lseek(fd, 0, SEEK_END) < 0) return log_debug_errno(errno, "Failed to seek to end of JSON log: %m"); r = loop_write(fd, f, SIZE_MAX); diff --git a/src/test/test-macro.c b/src/test/test-macro.c index 810ebc580e..63fe6ea95e 100644 --- a/src/test/test-macro.c +++ b/src/test/test-macro.c @@ -513,6 +513,34 @@ TEST(align_to) { assert_se(ALIGN_TO(SIZE_MAX-1, 4) == SIZE_MAX); /* overflow */ assert_se(ALIGN_TO(SIZE_MAX, 4) == SIZE_MAX); /* overflow */ + assert_se(ALIGN_TO_U64(0, 1) == 0); + assert_se(ALIGN_TO_U64(1, 1) == 1); + assert_se(ALIGN_TO_U64(2, 1) == 2); + assert_se(ALIGN_TO_U64(3, 1) == 3); + assert_se(ALIGN_TO_U64(4, 1) == 4); + assert_se(ALIGN_TO_U64(UINT64_MAX-1, 1) == UINT64_MAX-1); + assert_se(ALIGN_TO_U64(UINT64_MAX, 1) == UINT64_MAX); + + assert_se(ALIGN_TO_U64(0, 2) == 0); + assert_se(ALIGN_TO_U64(1, 2) == 2); + assert_se(ALIGN_TO_U64(2, 2) == 2); + assert_se(ALIGN_TO_U64(3, 2) == 4); + assert_se(ALIGN_TO_U64(4, 2) == 4); + assert_se(ALIGN_TO_U64(UINT64_MAX-3, 2) == UINT64_MAX-3); + assert_se(ALIGN_TO_U64(UINT64_MAX-2, 2) == UINT64_MAX-1); + assert_se(ALIGN_TO_U64(UINT64_MAX-1, 2) == UINT64_MAX-1); + assert_se(ALIGN_TO_U64(UINT64_MAX, 2) == UINT64_MAX); /* overflow */ + + assert_se(ALIGN_TO_U64(0, 4) == 0); + assert_se(ALIGN_TO_U64(1, 4) == 4); + assert_se(ALIGN_TO_U64(2, 4) == 4); + assert_se(ALIGN_TO_U64(3, 4) == 4); + assert_se(ALIGN_TO_U64(4, 4) == 4); + assert_se(ALIGN_TO_U64(UINT64_MAX-3, 4) == UINT64_MAX-3); + assert_se(ALIGN_TO_U64(UINT64_MAX-2, 4) == UINT64_MAX); /* overflow */ + assert_se(ALIGN_TO_U64(UINT64_MAX-1, 4) == UINT64_MAX); /* overflow */ + assert_se(ALIGN_TO_U64(UINT64_MAX, 4) == UINT64_MAX); /* overflow */ + assert_cc(CONST_ALIGN_TO(96, 512) == 512); assert_cc(CONST_ALIGN_TO(511, 512) == 512); assert_cc(CONST_ALIGN_TO(512, 512) == 512); @@ -523,6 +551,106 @@ TEST(align_to) { assert_cc(__builtin_types_compatible_p(typeof(CONST_ALIGN_TO(SIZE_MAX, 512)), void)); } +TEST(align_down) { + assert_se(ALIGN_DOWN(0, 1) == 0); + assert_se(ALIGN_DOWN(1, 1) == 1); + assert_se(ALIGN_DOWN(2, 1) == 2); + assert_se(ALIGN_DOWN(3, 1) == 3); + assert_se(ALIGN_DOWN(4, 1) == 4); + assert_se(ALIGN_DOWN(SIZE_MAX-1, 1) == SIZE_MAX-1); + assert_se(ALIGN_DOWN(SIZE_MAX, 1) == SIZE_MAX); + + assert_se(ALIGN_DOWN(0, 2) == 0); + assert_se(ALIGN_DOWN(1, 2) == 0); + assert_se(ALIGN_DOWN(2, 2) == 2); + assert_se(ALIGN_DOWN(3, 2) == 2); + assert_se(ALIGN_DOWN(4, 2) == 4); + assert_se(ALIGN_DOWN(SIZE_MAX-1, 2) == SIZE_MAX-1); + assert_se(ALIGN_DOWN(SIZE_MAX, 2) == SIZE_MAX-1); + + assert_se(ALIGN_DOWN(0, 4) == 0); + assert_se(ALIGN_DOWN(1, 4) == 0); + assert_se(ALIGN_DOWN(2, 4) == 0); + assert_se(ALIGN_DOWN(3, 4) == 0); + assert_se(ALIGN_DOWN(4, 4) == 4); + assert_se(ALIGN_DOWN(SIZE_MAX-1, 4) == SIZE_MAX-3); + assert_se(ALIGN_DOWN(SIZE_MAX, 4) == SIZE_MAX-3); + + assert_se(ALIGN_DOWN_U64(0, 1) == 0); + assert_se(ALIGN_DOWN_U64(1, 1) == 1); + assert_se(ALIGN_DOWN_U64(2, 1) == 2); + assert_se(ALIGN_DOWN_U64(3, 1) == 3); + assert_se(ALIGN_DOWN_U64(4, 1) == 4); + assert_se(ALIGN_DOWN_U64(UINT64_MAX-1, 1) == UINT64_MAX-1); + assert_se(ALIGN_DOWN_U64(UINT64_MAX, 1) == UINT64_MAX); + + assert_se(ALIGN_DOWN_U64(0, 2) == 0); + assert_se(ALIGN_DOWN_U64(1, 2) == 0); + assert_se(ALIGN_DOWN_U64(2, 2) == 2); + assert_se(ALIGN_DOWN_U64(3, 2) == 2); + assert_se(ALIGN_DOWN_U64(4, 2) == 4); + assert_se(ALIGN_DOWN_U64(UINT64_MAX-1, 2) == UINT64_MAX-1); + assert_se(ALIGN_DOWN_U64(UINT64_MAX, 2) == UINT64_MAX-1); + + assert_se(ALIGN_DOWN_U64(0, 4) == 0); + assert_se(ALIGN_DOWN_U64(1, 4) == 0); + assert_se(ALIGN_DOWN_U64(2, 4) == 0); + assert_se(ALIGN_DOWN_U64(3, 4) == 0); + assert_se(ALIGN_DOWN_U64(4, 4) == 4); + assert_se(ALIGN_DOWN_U64(UINT64_MAX-1, 4) == UINT64_MAX-3); + assert_se(ALIGN_DOWN_U64(UINT64_MAX, 4) == UINT64_MAX-3); +} + +TEST(align_offset) { + assert_se(ALIGN_OFFSET(0, 1) == 0); + assert_se(ALIGN_OFFSET(1, 1) == 0); + assert_se(ALIGN_OFFSET(2, 1) == 0); + assert_se(ALIGN_OFFSET(3, 1) == 0); + assert_se(ALIGN_OFFSET(4, 1) == 0); + assert_se(ALIGN_OFFSET(SIZE_MAX-1, 1) == 0); + assert_se(ALIGN_OFFSET(SIZE_MAX, 1) == 0); + + assert_se(ALIGN_OFFSET(0, 2) == 0); + assert_se(ALIGN_OFFSET(1, 2) == 1); + assert_se(ALIGN_OFFSET(2, 2) == 0); + assert_se(ALIGN_OFFSET(3, 2) == 1); + assert_se(ALIGN_OFFSET(4, 2) == 0); + assert_se(ALIGN_OFFSET(SIZE_MAX-1, 2) == 0); + assert_se(ALIGN_OFFSET(SIZE_MAX, 2) == 1); + + assert_se(ALIGN_OFFSET(0, 4) == 0); + assert_se(ALIGN_OFFSET(1, 4) == 1); + assert_se(ALIGN_OFFSET(2, 4) == 2); + assert_se(ALIGN_OFFSET(3, 4) == 3); + assert_se(ALIGN_OFFSET(4, 4) == 0); + assert_se(ALIGN_OFFSET(SIZE_MAX-1, 4) == 2); + assert_se(ALIGN_OFFSET(SIZE_MAX, 4) == 3); + + assert_se(ALIGN_OFFSET_U64(0, 1) == 0); + assert_se(ALIGN_OFFSET_U64(1, 1) == 0); + assert_se(ALIGN_OFFSET_U64(2, 1) == 0); + assert_se(ALIGN_OFFSET_U64(3, 1) == 0); + assert_se(ALIGN_OFFSET_U64(4, 1) == 0); + assert_se(ALIGN_OFFSET_U64(UINT64_MAX-1, 1) == 0); + assert_se(ALIGN_OFFSET_U64(UINT64_MAX, 1) == 0); + + assert_se(ALIGN_OFFSET_U64(0, 2) == 0); + assert_se(ALIGN_OFFSET_U64(1, 2) == 1); + assert_se(ALIGN_OFFSET_U64(2, 2) == 0); + assert_se(ALIGN_OFFSET_U64(3, 2) == 1); + assert_se(ALIGN_OFFSET_U64(4, 2) == 0); + assert_se(ALIGN_OFFSET_U64(UINT64_MAX-1, 2) == 0); + assert_se(ALIGN_OFFSET_U64(UINT64_MAX, 2) == 1); + + assert_se(ALIGN_OFFSET_U64(0, 4) == 0); + assert_se(ALIGN_OFFSET_U64(1, 4) == 1); + assert_se(ALIGN_OFFSET_U64(2, 4) == 2); + assert_se(ALIGN_OFFSET_U64(3, 4) == 3); + assert_se(ALIGN_OFFSET_U64(4, 4) == 0); + assert_se(ALIGN_OFFSET_U64(UINT64_MAX-1, 4) == 2); + assert_se(ALIGN_OFFSET_U64(UINT64_MAX, 4) == 3); +} + TEST(flags) { enum { F1 = 1 << 0, @@ -884,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); diff --git a/src/test/test-memory-util.c b/src/test/test-memory-util.c index 2f8384ac09..cd4b64ac16 100644 --- a/src/test/test-memory-util.c +++ b/src/test/test-memory-util.c @@ -52,4 +52,74 @@ TEST(cleanup_array) { free(saved_iov); } +TEST(page_align) { + assert_se(PAGE_ALIGN(page_size() - 1) == page_size()); + assert_se(PAGE_ALIGN(page_size() ) == page_size()); + assert_se(PAGE_ALIGN(page_size() + 1) == page_size() * 2); + assert_se(PAGE_ALIGN(page_size() * 123 - 1) == page_size() * 123); + assert_se(PAGE_ALIGN(page_size() * 123 ) == page_size() * 123); + assert_se(PAGE_ALIGN(page_size() * 123 + 1) == page_size() * 124); + assert_se(PAGE_ALIGN(SIZE_MAX - page_size() - 1) == SIZE_MAX - page_size() + 1); + assert_se(PAGE_ALIGN(SIZE_MAX - page_size() ) == SIZE_MAX - page_size() + 1); + assert_se(PAGE_ALIGN(SIZE_MAX - page_size() + 1) == SIZE_MAX - page_size() + 1); + assert_se(PAGE_ALIGN(SIZE_MAX - page_size() + 2) == SIZE_MAX); /* overflow */ + assert_se(PAGE_ALIGN(SIZE_MAX) == SIZE_MAX); /* overflow */ + + assert_se(PAGE_ALIGN_U64(page_size() - 1) == page_size()); + assert_se(PAGE_ALIGN_U64(page_size() ) == page_size()); + assert_se(PAGE_ALIGN_U64(page_size() + 1) == page_size() * 2); + assert_se(PAGE_ALIGN_U64(page_size() * 123 - 1) == page_size() * 123); + assert_se(PAGE_ALIGN_U64(page_size() * 123 ) == page_size() * 123); + assert_se(PAGE_ALIGN_U64(page_size() * 123 + 1) == page_size() * 124); + assert_se(PAGE_ALIGN_U64(UINT64_MAX - page_size() - 1) == UINT64_MAX - page_size() + 1); + assert_se(PAGE_ALIGN_U64(UINT64_MAX - page_size() ) == UINT64_MAX - page_size() + 1); + assert_se(PAGE_ALIGN_U64(UINT64_MAX - page_size() + 1) == UINT64_MAX - page_size() + 1); + assert_se(PAGE_ALIGN_U64(UINT64_MAX - page_size() + 2) == UINT64_MAX); /* overflow */ + assert_se(PAGE_ALIGN_U64(UINT64_MAX) == UINT64_MAX); /* overflow */ + + assert_se(PAGE_ALIGN_DOWN(page_size() - 1) == 0); + assert_se(PAGE_ALIGN_DOWN(page_size() ) == page_size()); + assert_se(PAGE_ALIGN_DOWN(page_size() + 1) == page_size()); + assert_se(PAGE_ALIGN_DOWN(page_size() * 123 - 1) == page_size() * 122); + assert_se(PAGE_ALIGN_DOWN(page_size() * 123 ) == page_size() * 123); + assert_se(PAGE_ALIGN_DOWN(page_size() * 123 + 1) == page_size() * 123); + assert_se(PAGE_ALIGN_DOWN(SIZE_MAX - page_size() - 1) == SIZE_MAX - page_size() * 2 + 1); + assert_se(PAGE_ALIGN_DOWN(SIZE_MAX - page_size() ) == SIZE_MAX - page_size() * 2 + 1); + assert_se(PAGE_ALIGN_DOWN(SIZE_MAX - page_size() + 1) == SIZE_MAX - page_size() + 1); + assert_se(PAGE_ALIGN_DOWN(SIZE_MAX - page_size() + 2) == SIZE_MAX - page_size() + 1); + + assert_se(PAGE_ALIGN_DOWN_U64(page_size() - 1) == 0); + assert_se(PAGE_ALIGN_DOWN_U64(page_size() ) == page_size()); + assert_se(PAGE_ALIGN_DOWN_U64(page_size() + 1) == page_size()); + assert_se(PAGE_ALIGN_DOWN_U64(page_size() * 123 - 1) == page_size() * 122); + assert_se(PAGE_ALIGN_DOWN_U64(page_size() * 123 ) == page_size() * 123); + assert_se(PAGE_ALIGN_DOWN_U64(page_size() * 123 + 1) == page_size() * 123); + assert_se(PAGE_ALIGN_DOWN_U64(SIZE_MAX - page_size() - 1) == SIZE_MAX - page_size() * 2 + 1); + assert_se(PAGE_ALIGN_DOWN_U64(SIZE_MAX - page_size() ) == SIZE_MAX - page_size() * 2 + 1); + assert_se(PAGE_ALIGN_DOWN_U64(SIZE_MAX - page_size() + 1) == SIZE_MAX - page_size() + 1); + assert_se(PAGE_ALIGN_DOWN_U64(SIZE_MAX - page_size() + 2) == SIZE_MAX - page_size() + 1); + + assert_se(PAGE_OFFSET(page_size() - 1) == page_size() - 1); + assert_se(PAGE_OFFSET(page_size() ) == 0); + assert_se(PAGE_OFFSET(page_size() + 1) == 1); + assert_se(PAGE_OFFSET(page_size() * 123 - 1) == page_size() - 1); + assert_se(PAGE_OFFSET(page_size() * 123 ) == 0); + assert_se(PAGE_OFFSET(page_size() * 123 + 1) == 1); + assert_se(PAGE_OFFSET(SIZE_MAX - page_size() - 1) == page_size() - 2); + assert_se(PAGE_OFFSET(SIZE_MAX - page_size() ) == page_size() - 1); + assert_se(PAGE_OFFSET(SIZE_MAX - page_size() + 1) == 0); + assert_se(PAGE_OFFSET(SIZE_MAX - page_size() + 2) == 1); + + assert_se(PAGE_OFFSET_U64(page_size() - 1) == page_size() - 1); + assert_se(PAGE_OFFSET_U64(page_size() ) == 0); + assert_se(PAGE_OFFSET_U64(page_size() + 1) == 1); + assert_se(PAGE_OFFSET_U64(page_size() * 123 - 1) == page_size() - 1); + assert_se(PAGE_OFFSET_U64(page_size() * 123 ) == 0); + assert_se(PAGE_OFFSET_U64(page_size() * 123 + 1) == 1); + assert_se(PAGE_OFFSET_U64(UINT64_MAX - page_size() - 1) == page_size() - 2); + assert_se(PAGE_OFFSET_U64(UINT64_MAX - page_size() ) == page_size() - 1); + assert_se(PAGE_OFFSET_U64(UINT64_MAX - page_size() + 1) == 0); + assert_se(PAGE_OFFSET_U64(UINT64_MAX - page_size() + 2) == 1); +} + DEFINE_TEST_MAIN(LOG_INFO);