]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lib/fileeq: Check arithmetic in ul_fileeq_set_size
authorTobias Stoeckmann <tobias@stoeckmann.org>
Tue, 24 Feb 2026 20:43:16 +0000 (21:43 +0100)
committerTobias Stoeckmann <tobias@stoeckmann.org>
Thu, 26 Feb 2026 19:41:23 +0000 (20:41 +0100)
Make sure that arithmetics do not overflow data types. Such overflows
could occur with large hardlink options or on 32 bit systems with large
files (due to size_t usage).

If possible, reduce sizes so operations can continue successfully.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
include/fileeq.h
lib/fileeq.c
misc-utils/hardlink.c

index df5e6d8222f0a06ca269a5ae7a30f281665afddd..90b8d5118a01df23bb782a09473dbb2c8649ae66 100644 (file)
@@ -53,8 +53,8 @@ extern void ul_fileeq_data_init(struct ul_fileeq_data *data);
 extern void ul_fileeq_data_deinit(struct ul_fileeq_data *data);
 extern void ul_fileeq_data_set_file(struct ul_fileeq_data *data,
                                    const char *name);
-extern size_t ul_fileeq_set_size(struct ul_fileeq *eq, uint64_t filesiz,
-                                 size_t readsiz, size_t memsiz);
+extern bool ul_fileeq_set_size(struct ul_fileeq *eq, int64_t st_size,
+                               size_t readsiz, size_t memsiz);
 
 extern int ul_fileeq(struct ul_fileeq *eq,
               struct ul_fileeq_data *a, struct ul_fileeq_data *b);
index d13fc40454a32404042255c68aa732ba614d16da..5a56b4753de8e3f3a4560d350d98d3e4af776f25 100644 (file)
@@ -250,16 +250,23 @@ void ul_fileeq_data_set_file(struct ul_fileeq_data *data, const char *name)
        data->name = name;
 }
 
-size_t ul_fileeq_set_size(struct ul_fileeq *eq, uint64_t filesiz,
-                        size_t readsiz, size_t memsiz)
+bool ul_fileeq_set_size(struct ul_fileeq *eq, int64_t st_size,
+                       size_t readsiz, size_t memsiz)
 {
-       uint64_t nreads, maxdigs;
+       uint64_t filesiz, nreads, maxdigs;
        size_t digsiz;
 
        assert(eq);
+       assert(st_size >= 0);
+       assert(readsiz);
+
+       filesiz = (uint64_t) st_size;
 
        eq->filesiz = filesiz;
 
+       if (filesiz != 0 && readsiz > filesiz)
+               readsiz = filesiz;
+
        switch (eq->method->id) {
        case UL_FILEEQ_MEMCMP:
                /* align file size */
@@ -275,22 +282,28 @@ size_t ul_fileeq_set_size(struct ul_fileeq *eq, uint64_t filesiz,
                maxdigs = memsiz / digsiz;
                if (maxdigs == 0)
                        maxdigs = 1;
+               else if (maxdigs > filesiz)
+                       maxdigs = filesiz;
                nreads = filesiz / readsiz;
                /* enlarge readsize for large files */
-               if (nreads > maxdigs)
-                       readsiz = (filesiz + maxdigs - 1) / maxdigs;
+               if (nreads > maxdigs) {
+                       uint64_t ceiling = filesiz + maxdigs - 1;
+                       if (ceiling / maxdigs > SIZE_MAX)
+                               return false;
+                       readsiz = ceiling / maxdigs;
+               }
                break;
        }
 
        eq->readsiz = readsiz;
        eq->blocksmax = (filesiz + readsiz - 1) / readsiz;
 
-       DBG(EQ, ul_debugobj(eq, "set sizes: filesiz=%" PRIu64 ", maxblocks=%" PRIu64 ", readsiz=%zu",
+       DBG(EQ, ul_debugobj(eq, "set sizes: filesiz=%" PRIu64 ", blocksmax=%" PRIu64 ", readsiz=%zu",
                                eq->filesiz, eq->blocksmax, eq->readsiz));
 
        reset_fileeq_bufs(eq);
 
-       return eq->blocksmax;
+       return true;
 }
 
 static unsigned char *get_buffer(struct ul_fileeq *eq)
@@ -624,8 +637,9 @@ int main(int argc, char *argv[])
        if (file_c)
                ul_fileeq_data_set_file(&c, file_c);
 
-       /*                     filesiz,      readsiz,   memsiz */
-       ul_fileeq_set_size(&eq, st_a.st_size, 1024*1024, 4*1024);
+       /*                           st_size,      readsiz,   memsiz */
+       if (!ul_fileeq_set_size(&eq, st_a.st_size, 1024*1024, 4*1024))
+               err(EXIT_FAILURE, "failed to set sizes");
 
        rc = ul_fileeq(&eq, &a, &b);
 
index 114b5c4c940f82fac336d5d0a31aba3e9a3938fd..2c02e25d4f9fbcd14f81e3951da7926108c53fdb 100644 (file)
@@ -1097,8 +1097,12 @@ static void visitor(const void *nodep, const VISIT which, const int depth)
 
                /* per-file cache size */
                memsiz = opts.cache_size / nnodes;
-               /*                                filesiz,      readsiz,      memsiz */
-               ul_fileeq_set_size(&fileeq, master->st.st_size, opts.io_size, memsiz);
+               /*                               st_size,            readsiz,      memsiz */
+               if (!ul_fileeq_set_size(&fileeq, master->st.st_size, opts.io_size, memsiz)) {
+                       jlog(VERBOSE2,
+                            printf(_("Skipped (memory constraints) %s"), master->links->path));
+                       continue;
+               }
 
 #ifdef USE_REFLINK
                if (reflink_mode || reflinks_skip) {