]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Do not truncate seek requests 2686/head
authorTobias Stoeckmann <tobias@stoeckmann.org>
Fri, 27 Jun 2025 15:24:15 +0000 (17:24 +0200)
committerTobias Stoeckmann <tobias@stoeckmann.org>
Sun, 29 Jun 2025 19:35:44 +0000 (21:35 +0200)
If a seek cannot be fulfilled, fail directly with EOVERFLOW to match
regular lseek behavior.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
libarchive/archive_read_open_fd.c
libarchive/archive_read_open_file.c
libarchive/archive_read_open_filename.c

index edb78b0329ad42e773c23f7e6305fc57e56b0073..c85a62a3e2d73f38174663828c22ecbdfe7d81a4 100644 (file)
@@ -193,21 +193,22 @@ file_seek(struct archive *a, void *client_data, int64_t request, int whence)
 
        /* We use off_t here because lseek() is declared that way. */
 
-       /* Reduce a request that would overflow the 'seek' variable. */
+       /* Do not perform a seek which cannot be fulfilled. */
        if (sizeof(request) > sizeof(seek)) {
                const int64_t max_seek =
                    (((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1;
                const int64_t min_seek = ~max_seek;
-               if (request > max_seek)
-                       seek = (off_t)max_seek;
-               else if (request < min_seek)
-                       seek = (off_t)min_seek;
+               if (request < min_seek || request > max_seek) {
+                       errno = EOVERFLOW;
+                       goto err;
+               }
        }
 
        r = lseek(mine->fd, seek, whence);
        if (r >= 0)
                return r;
 
+err:
        if (errno == ESPIPE) {
                archive_set_error(a, errno,
                    "A file descriptor(%d) is not seekable(PIPE)", mine->fd);
index b0eb5b0ea5d69c1276122fe26fa4f6cfe01c00bf..6ca2ff191aa8daab047acc56c00aa5e074e5072b 100644 (file)
@@ -206,15 +206,15 @@ FILE_seek(struct archive *a, void *client_data, int64_t request, int whence)
        int seek_bits = sizeof(seek) * 8 - 1;
        (void)a; /* UNUSED */
 
-       /* Reduce a request that would overflow the 'seek' variable. */
+       /* Do not perform a seek which cannot be fulfilled. */
        if (sizeof(request) > sizeof(seek)) {
                const int64_t max_seek =
                    (((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1;
                const int64_t min_seek = ~max_seek;
-               if (request > max_seek)
-                       seek = max_seek;
-               else if (request < min_seek)
-                       seek = min_seek;
+               if (request < min_seek || request > max_seek) {
+                       errno = EOVERFLOW;
+                       goto err;
+               }
        }
 
 #ifdef __ANDROID__
@@ -237,6 +237,7 @@ FILE_seek(struct archive *a, void *client_data, int64_t request, int whence)
        }
 #endif
        /* If we arrive here, the input is corrupted or truncated so fail. */
+err:
        archive_set_error(a, errno, "Error seeking in FILE* pointer");
        return (ARCHIVE_FATAL);
 }
index b9d30bf4464ea2475dcf7c1611b204be3ea9dda5..a910eefcbfd23243fccb049ed7336aafd5ad1890 100644 (file)
@@ -564,15 +564,15 @@ file_seek(struct archive *a, void *client_data, int64_t request, int whence)
 
        /* We use off_t here because lseek() is declared that way. */
 
-       /* Reduce a request that would overflow the 'seek' variable. */
+       /* Do not perform a seek which cannot be fulfilled. */
        if (sizeof(request) > sizeof(seek)) {
                const int64_t max_seek =
                    (((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1;
                const int64_t min_seek = ~max_seek;
-               if (request > max_seek)
-                       seek = (off_t)max_seek;
-               else if (request < min_seek)
-                       seek = (off_t)min_seek;
+               if (request < min_seek || request > max_seek) {
+                       errno = EOVERFLOW;
+                       goto err;
+               }
        }
 
        r = lseek(mine->fd, seek, whence);
@@ -580,6 +580,7 @@ file_seek(struct archive *a, void *client_data, int64_t request, int whence)
                return r;
 
        /* If the input is corrupted or truncated, fail. */
+err:
        if (mine->filename_type == FNT_STDIN)
                archive_set_error(a, errno, "Error seeking in stdin");
        else if (mine->filename_type == FNT_MBS)