diff options
4 files changed, 730 insertions, 0 deletions
diff --git a/meta/recipes-extended/libarchive/libarchive/0001-FILE-seeking-support-2539.patch b/meta/recipes-extended/libarchive/libarchive/0001-FILE-seeking-support-2539.patch new file mode 100644 index 0000000000..2126fcf058 --- /dev/null +++ b/meta/recipes-extended/libarchive/libarchive/0001-FILE-seeking-support-2539.patch | |||
| @@ -0,0 +1,190 @@ | |||
| 1 | From 09a2ed4853cd177264076a88c98e525e892a0d0b Mon Sep 17 00:00:00 2001 | ||
| 2 | From: ljdarj <ljd@luigiscorner.mu> | ||
| 3 | Date: Sat, 15 Mar 2025 19:17:27 +0100 | ||
| 4 | Subject: [PATCH] FILE* seeking support (#2539) | ||
| 5 | |||
| 6 | Adding a seeker function to archive_read_open_FILE(). | ||
| 7 | |||
| 8 | Fixes #437. | ||
| 9 | |||
| 10 | Upstream-Status: Backport [https://github.com/libarchive/libarchive/commit/09a2ed4853cd177264076a88c98e525e892a0d0b] | ||
| 11 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 12 | --- | ||
| 13 | libarchive/archive_read_open_file.c | 82 +++++++++++++++++++++++------ | ||
| 14 | libarchive/test/test_open_file.c | 9 ++-- | ||
| 15 | 2 files changed, 71 insertions(+), 20 deletions(-) | ||
| 16 | |||
| 17 | diff --git a/libarchive/archive_read_open_file.c b/libarchive/archive_read_open_file.c | ||
| 18 | index cf49ebd8..ecd56dce 100644 | ||
| 19 | --- a/libarchive/archive_read_open_file.c | ||
| 20 | +++ b/libarchive/archive_read_open_file.c | ||
| 21 | @@ -57,9 +57,10 @@ struct read_FILE_data { | ||
| 22 | char can_skip; | ||
| 23 | }; | ||
| 24 | |||
| 25 | -static int file_close(struct archive *, void *); | ||
| 26 | -static ssize_t file_read(struct archive *, void *, const void **buff); | ||
| 27 | -static int64_t file_skip(struct archive *, void *, int64_t request); | ||
| 28 | +static int FILE_close(struct archive *, void *); | ||
| 29 | +static ssize_t FILE_read(struct archive *, void *, const void **buff); | ||
| 30 | +static int64_t FILE_seek(struct archive *, void *, int64_t, int); | ||
| 31 | +static int64_t FILE_skip(struct archive *, void *, int64_t); | ||
| 32 | |||
| 33 | int | ||
| 34 | archive_read_open_FILE(struct archive *a, FILE *f) | ||
| 35 | @@ -70,7 +71,7 @@ archive_read_open_FILE(struct archive *a, FILE *f) | ||
| 36 | void *b; | ||
| 37 | |||
| 38 | archive_clear_error(a); | ||
| 39 | - mine = (struct read_FILE_data *)malloc(sizeof(*mine)); | ||
| 40 | + mine = (struct read_FILE_data *)calloc(1, sizeof(*mine)); | ||
| 41 | b = malloc(block_size); | ||
| 42 | if (mine == NULL || b == NULL) { | ||
| 43 | archive_set_error(a, ENOMEM, "No memory"); | ||
| 44 | @@ -91,22 +92,22 @@ archive_read_open_FILE(struct archive *a, FILE *f) | ||
| 45 | archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); | ||
| 46 | /* Enable the seek optimization only for regular files. */ | ||
| 47 | mine->can_skip = 1; | ||
| 48 | - } else | ||
| 49 | - mine->can_skip = 0; | ||
| 50 | + } | ||
| 51 | |||
| 52 | #if defined(__CYGWIN__) || defined(_WIN32) | ||
| 53 | setmode(fileno(mine->f), O_BINARY); | ||
| 54 | #endif | ||
| 55 | |||
| 56 | - archive_read_set_read_callback(a, file_read); | ||
| 57 | - archive_read_set_skip_callback(a, file_skip); | ||
| 58 | - archive_read_set_close_callback(a, file_close); | ||
| 59 | + archive_read_set_read_callback(a, FILE_read); | ||
| 60 | + archive_read_set_skip_callback(a, FILE_skip); | ||
| 61 | + archive_read_set_seek_callback(a, FILE_seek); | ||
| 62 | + archive_read_set_close_callback(a, FILE_close); | ||
| 63 | archive_read_set_callback_data(a, mine); | ||
| 64 | return (archive_read_open1(a)); | ||
| 65 | } | ||
| 66 | |||
| 67 | static ssize_t | ||
| 68 | -file_read(struct archive *a, void *client_data, const void **buff) | ||
| 69 | +FILE_read(struct archive *a, void *client_data, const void **buff) | ||
| 70 | { | ||
| 71 | struct read_FILE_data *mine = (struct read_FILE_data *)client_data; | ||
| 72 | size_t bytes_read; | ||
| 73 | @@ -120,13 +121,13 @@ file_read(struct archive *a, void *client_data, const void **buff) | ||
| 74 | } | ||
| 75 | |||
| 76 | static int64_t | ||
| 77 | -file_skip(struct archive *a, void *client_data, int64_t request) | ||
| 78 | +FILE_skip(struct archive *a, void *client_data, int64_t request) | ||
| 79 | { | ||
| 80 | struct read_FILE_data *mine = (struct read_FILE_data *)client_data; | ||
| 81 | -#if HAVE_FSEEKO | ||
| 82 | - off_t skip = (off_t)request; | ||
| 83 | -#elif HAVE__FSEEKI64 | ||
| 84 | +#if HAVE__FSEEKI64 | ||
| 85 | int64_t skip = request; | ||
| 86 | +#elif HAVE_FSEEKO | ||
| 87 | + off_t skip = (off_t)request; | ||
| 88 | #else | ||
| 89 | long skip = (long)request; | ||
| 90 | #endif | ||
| 91 | @@ -168,8 +169,57 @@ file_skip(struct archive *a, void *client_data, int64_t request) | ||
| 92 | return (request); | ||
| 93 | } | ||
| 94 | |||
| 95 | +/* | ||
| 96 | + * TODO: Store the offset and use it in the read callback. | ||
| 97 | + */ | ||
| 98 | +static int64_t | ||
| 99 | +FILE_seek(struct archive *a, void *client_data, int64_t request, int whence) | ||
| 100 | +{ | ||
| 101 | + struct read_FILE_data *mine = (struct read_FILE_data *)client_data; | ||
| 102 | +#if HAVE__FSEEKI64 | ||
| 103 | + int64_t skip = request; | ||
| 104 | +#elif HAVE_FSEEKO | ||
| 105 | + off_t skip = (off_t)request; | ||
| 106 | +#else | ||
| 107 | + long skip = (long)request; | ||
| 108 | +#endif | ||
| 109 | + int skip_bits = sizeof(skip) * 8 - 1; | ||
| 110 | + (void)a; /* UNUSED */ | ||
| 111 | + | ||
| 112 | + /* If request is too big for a long or an off_t, reduce it. */ | ||
| 113 | + if (sizeof(request) > sizeof(skip)) { | ||
| 114 | + int64_t max_skip = | ||
| 115 | + (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1; | ||
| 116 | + if (request > max_skip) | ||
| 117 | + skip = max_skip; | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | +#ifdef __ANDROID__ | ||
| 121 | + /* Newer Android versions have fseeko...to meditate. */ | ||
| 122 | + int64_t ret = lseek(fileno(mine->f), skip, whence); | ||
| 123 | + if (ret >= 0) { | ||
| 124 | + return ret; | ||
| 125 | + } | ||
| 126 | +#elif HAVE__FSEEKI64 | ||
| 127 | + if (_fseeki64(mine->f, skip, whence) == 0) { | ||
| 128 | + return _ftelli64(mine->f); | ||
| 129 | + } | ||
| 130 | +#elif HAVE_FSEEKO | ||
| 131 | + if (fseeko(mine->f, skip, whence) == 0) { | ||
| 132 | + return ftello(mine->f); | ||
| 133 | + } | ||
| 134 | +#else | ||
| 135 | + if (fseek(mine->f, skip, whence) == 0) { | ||
| 136 | + return ftell(mine->f); | ||
| 137 | + } | ||
| 138 | +#endif | ||
| 139 | + /* If we arrive here, the input is corrupted or truncated so fail. */ | ||
| 140 | + archive_set_error(a, errno, "Error seeking in FILE* pointer"); | ||
| 141 | + return (ARCHIVE_FATAL); | ||
| 142 | +} | ||
| 143 | + | ||
| 144 | static int | ||
| 145 | -file_close(struct archive *a, void *client_data) | ||
| 146 | +FILE_close(struct archive *a, void *client_data) | ||
| 147 | { | ||
| 148 | struct read_FILE_data *mine = (struct read_FILE_data *)client_data; | ||
| 149 | |||
| 150 | @@ -177,4 +227,4 @@ file_close(struct archive *a, void *client_data) | ||
| 151 | free(mine->buffer); | ||
| 152 | free(mine); | ||
| 153 | return (ARCHIVE_OK); | ||
| 154 | -} | ||
| 155 | +} | ||
| 156 | \ No newline at end of file | ||
| 157 | diff --git a/libarchive/test/test_open_file.c b/libarchive/test/test_open_file.c | ||
| 158 | index f4ca82bb..cc6b04d0 100644 | ||
| 159 | --- a/libarchive/test/test_open_file.c | ||
| 160 | +++ b/libarchive/test/test_open_file.c | ||
| 161 | @@ -32,14 +32,14 @@ DEFINE_TEST(test_open_file) | ||
| 162 | struct archive *a; | ||
| 163 | FILE *f; | ||
| 164 | |||
| 165 | - f = fopen("test.tar", "wb"); | ||
| 166 | + f = fopen("test.7z", "wb"); | ||
| 167 | assert(f != NULL); | ||
| 168 | if (f == NULL) | ||
| 169 | return; | ||
| 170 | |||
| 171 | /* Write an archive through this FILE *. */ | ||
| 172 | assert((a = archive_write_new()) != NULL); | ||
| 173 | - assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_ustar(a)); | ||
| 174 | + assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_7zip(a)); | ||
| 175 | assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_none(a)); | ||
| 176 | assertEqualIntA(a, ARCHIVE_OK, archive_write_open_FILE(a, f)); | ||
| 177 | |||
| 178 | @@ -71,9 +71,10 @@ DEFINE_TEST(test_open_file) | ||
| 179 | fclose(f); | ||
| 180 | |||
| 181 | /* | ||
| 182 | - * Now, read the data back. | ||
| 183 | + * Now, read the data back. 7z requiring seeking, that also | ||
| 184 | + * tests that the seeking support works. | ||
| 185 | */ | ||
| 186 | - f = fopen("test.tar", "rb"); | ||
| 187 | + f = fopen("test.7z", "rb"); | ||
| 188 | assert(f != NULL); | ||
| 189 | if (f == NULL) | ||
| 190 | return; | ||
diff --git a/meta/recipes-extended/libarchive/libarchive/0001-Improve-lseek-handling-2564.patch b/meta/recipes-extended/libarchive/libarchive/0001-Improve-lseek-handling-2564.patch new file mode 100644 index 0000000000..a00674f5dc --- /dev/null +++ b/meta/recipes-extended/libarchive/libarchive/0001-Improve-lseek-handling-2564.patch | |||
| @@ -0,0 +1,320 @@ | |||
| 1 | From 89b8c35ff4b5addc08a85bf5df02b407f8af1f6c Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Tobias Stoeckmann <stoeckmann@users.noreply.github.com> | ||
| 3 | Date: Sun, 6 Apr 2025 22:34:37 +0200 | ||
| 4 | Subject: [PATCH] Improve lseek handling (#2564) | ||
| 5 | |||
| 6 | The skip functions are limited to 1 GB for cases in which libarchive | ||
| 7 | runs on a system with an off_t or long with 32 bits. This has negative | ||
| 8 | impact on 64 bit systems. | ||
| 9 | |||
| 10 | Instead, make sure that _all_ subsequent functions truncate properly. | ||
| 11 | Some of them already did and some had regressions for over 10 years. | ||
| 12 | |||
| 13 | Tests pass on Debian 12 i686 configured with --disable-largefile, i.e. | ||
| 14 | running with an off_t with 32 bits. | ||
| 15 | |||
| 16 | Casts added where needed to still pass MSVC builds. | ||
| 17 | |||
| 18 | --------- | ||
| 19 | |||
| 20 | Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org> | ||
| 21 | |||
| 22 | Upstream-Status: Backport [https://github.com/libarchive/libarchive/commit/89b8c35ff4b5addc08a85bf5df02b407f8af1f6c] | ||
| 23 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 24 | --- | ||
| 25 | libarchive/archive_read.c | 6 ---- | ||
| 26 | libarchive/archive_read_disk_posix.c | 3 +- | ||
| 27 | libarchive/archive_read_open_fd.c | 29 +++++++++++++------ | ||
| 28 | libarchive/archive_read_open_file.c | 35 ++++++++++++----------- | ||
| 29 | libarchive/archive_read_open_filename.c | 37 ++++++++++++++++++------- | ||
| 30 | libarchive/test/read_open_memory.c | 2 +- | ||
| 31 | libarchive/test/test_sparse_basic.c | 6 ++-- | ||
| 32 | libarchive/test/test_tar_large.c | 2 +- | ||
| 33 | 8 files changed, 75 insertions(+), 45 deletions(-) | ||
| 34 | |||
| 35 | diff --git a/libarchive/archive_read.c b/libarchive/archive_read.c | ||
| 36 | index 822c534b..50db8701 100644 | ||
| 37 | --- a/libarchive/archive_read.c | ||
| 38 | +++ b/libarchive/archive_read.c | ||
| 39 | @@ -177,15 +177,9 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request) | ||
| 40 | return 0; | ||
| 41 | |||
| 42 | if (self->archive->client.skipper != NULL) { | ||
| 43 | - /* Seek requests over 1GiB are broken down into | ||
| 44 | - * multiple seeks. This avoids overflows when the | ||
| 45 | - * requests get passed through 32-bit arguments. */ | ||
| 46 | - int64_t skip_limit = (int64_t)1 << 30; | ||
| 47 | int64_t total = 0; | ||
| 48 | for (;;) { | ||
| 49 | int64_t get, ask = request; | ||
| 50 | - if (ask > skip_limit) | ||
| 51 | - ask = skip_limit; | ||
| 52 | get = (self->archive->client.skipper) | ||
| 53 | (&self->archive->archive, self->data, ask); | ||
| 54 | total += get; | ||
| 55 | diff --git a/libarchive/archive_read_disk_posix.c b/libarchive/archive_read_disk_posix.c | ||
| 56 | index 09965eb9..4839d62b 100644 | ||
| 57 | --- a/libarchive/archive_read_disk_posix.c | ||
| 58 | +++ b/libarchive/archive_read_disk_posix.c | ||
| 59 | @@ -779,7 +779,8 @@ _archive_read_data_block(struct archive *_a, const void **buff, | ||
| 60 | */ | ||
| 61 | if (t->current_sparse->offset > t->entry_total) { | ||
| 62 | if (lseek(t->entry_fd, | ||
| 63 | - (off_t)t->current_sparse->offset, SEEK_SET) < 0) { | ||
| 64 | + (off_t)t->current_sparse->offset, SEEK_SET) != | ||
| 65 | + t->current_sparse->offset) { | ||
| 66 | archive_set_error(&a->archive, errno, "Seek error"); | ||
| 67 | r = ARCHIVE_FATAL; | ||
| 68 | a->archive.state = ARCHIVE_STATE_FATAL; | ||
| 69 | diff --git a/libarchive/archive_read_open_fd.c b/libarchive/archive_read_open_fd.c | ||
| 70 | index debfde20..3fd536d5 100644 | ||
| 71 | --- a/libarchive/archive_read_open_fd.c | ||
| 72 | +++ b/libarchive/archive_read_open_fd.c | ||
| 73 | @@ -132,7 +132,7 @@ static int64_t | ||
| 74 | file_skip(struct archive *a, void *client_data, int64_t request) | ||
| 75 | { | ||
| 76 | struct read_fd_data *mine = (struct read_fd_data *)client_data; | ||
| 77 | - int64_t skip = request; | ||
| 78 | + off_t skip = (off_t)request; | ||
| 79 | int64_t old_offset, new_offset; | ||
| 80 | int skip_bits = sizeof(skip) * 8 - 1; /* off_t is a signed type. */ | ||
| 81 | |||
| 82 | @@ -141,15 +141,15 @@ file_skip(struct archive *a, void *client_data, int64_t request) | ||
| 83 | |||
| 84 | /* Reduce a request that would overflow the 'skip' variable. */ | ||
| 85 | if (sizeof(request) > sizeof(skip)) { | ||
| 86 | - int64_t max_skip = | ||
| 87 | + const int64_t max_skip = | ||
| 88 | (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1; | ||
| 89 | if (request > max_skip) | ||
| 90 | - skip = max_skip; | ||
| 91 | + skip = (off_t)max_skip; | ||
| 92 | } | ||
| 93 | |||
| 94 | - /* Reduce request to the next smallest multiple of block_size */ | ||
| 95 | - request = (request / mine->block_size) * mine->block_size; | ||
| 96 | - if (request == 0) | ||
| 97 | + /* Reduce 'skip' to the next smallest multiple of block_size */ | ||
| 98 | + skip = (off_t)(((int64_t)skip / mine->block_size) * mine->block_size); | ||
| 99 | + if (skip == 0) | ||
| 100 | return (0); | ||
| 101 | |||
| 102 | if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) && | ||
| 103 | @@ -179,11 +179,24 @@ static int64_t | ||
| 104 | file_seek(struct archive *a, void *client_data, int64_t request, int whence) | ||
| 105 | { | ||
| 106 | struct read_fd_data *mine = (struct read_fd_data *)client_data; | ||
| 107 | + off_t seek = (off_t)request; | ||
| 108 | int64_t r; | ||
| 109 | + int seek_bits = sizeof(seek) * 8 - 1; /* off_t is a signed type. */ | ||
| 110 | |||
| 111 | /* We use off_t here because lseek() is declared that way. */ | ||
| 112 | - /* See above for notes about when off_t is less than 64 bits. */ | ||
| 113 | - r = lseek(mine->fd, request, whence); | ||
| 114 | + | ||
| 115 | + /* Reduce a request that would overflow the 'seek' variable. */ | ||
| 116 | + if (sizeof(request) > sizeof(seek)) { | ||
| 117 | + const int64_t max_seek = | ||
| 118 | + (((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1; | ||
| 119 | + const int64_t min_seek = ~max_seek; | ||
| 120 | + if (request > max_seek) | ||
| 121 | + seek = (off_t)max_seek; | ||
| 122 | + else if (request < min_seek) | ||
| 123 | + seek = (off_t)min_seek; | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + r = lseek(mine->fd, seek, whence); | ||
| 127 | if (r >= 0) | ||
| 128 | return r; | ||
| 129 | |||
| 130 | diff --git a/libarchive/archive_read_open_file.c b/libarchive/archive_read_open_file.c | ||
| 131 | index ecd56dce..2829b9a5 100644 | ||
| 132 | --- a/libarchive/archive_read_open_file.c | ||
| 133 | +++ b/libarchive/archive_read_open_file.c | ||
| 134 | @@ -146,7 +146,7 @@ FILE_skip(struct archive *a, void *client_data, int64_t request) | ||
| 135 | |||
| 136 | /* If request is too big for a long or an off_t, reduce it. */ | ||
| 137 | if (sizeof(request) > sizeof(skip)) { | ||
| 138 | - int64_t max_skip = | ||
| 139 | + const int64_t max_skip = | ||
| 140 | (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1; | ||
| 141 | if (request > max_skip) | ||
| 142 | skip = max_skip; | ||
| 143 | @@ -177,39 +177,42 @@ FILE_seek(struct archive *a, void *client_data, int64_t request, int whence) | ||
| 144 | { | ||
| 145 | struct read_FILE_data *mine = (struct read_FILE_data *)client_data; | ||
| 146 | #if HAVE__FSEEKI64 | ||
| 147 | - int64_t skip = request; | ||
| 148 | + int64_t seek = request; | ||
| 149 | #elif HAVE_FSEEKO | ||
| 150 | - off_t skip = (off_t)request; | ||
| 151 | + off_t seek = (off_t)request; | ||
| 152 | #else | ||
| 153 | - long skip = (long)request; | ||
| 154 | + long seek = (long)request; | ||
| 155 | #endif | ||
| 156 | - int skip_bits = sizeof(skip) * 8 - 1; | ||
| 157 | + int seek_bits = sizeof(seek) * 8 - 1; | ||
| 158 | (void)a; /* UNUSED */ | ||
| 159 | |||
| 160 | - /* If request is too big for a long or an off_t, reduce it. */ | ||
| 161 | - if (sizeof(request) > sizeof(skip)) { | ||
| 162 | - int64_t max_skip = | ||
| 163 | - (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1; | ||
| 164 | - if (request > max_skip) | ||
| 165 | - skip = max_skip; | ||
| 166 | + /* Reduce a request that would overflow the 'seek' variable. */ | ||
| 167 | + if (sizeof(request) > sizeof(seek)) { | ||
| 168 | + const int64_t max_seek = | ||
| 169 | + (((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1; | ||
| 170 | + const int64_t min_seek = ~max_seek; | ||
| 171 | + if (request > max_seek) | ||
| 172 | + seek = max_seek; | ||
| 173 | + else if (request < min_seek) | ||
| 174 | + seek = min_seek; | ||
| 175 | } | ||
| 176 | |||
| 177 | #ifdef __ANDROID__ | ||
| 178 | /* Newer Android versions have fseeko...to meditate. */ | ||
| 179 | - int64_t ret = lseek(fileno(mine->f), skip, whence); | ||
| 180 | + int64_t ret = lseek(fileno(mine->f), seek, whence); | ||
| 181 | if (ret >= 0) { | ||
| 182 | return ret; | ||
| 183 | } | ||
| 184 | #elif HAVE__FSEEKI64 | ||
| 185 | - if (_fseeki64(mine->f, skip, whence) == 0) { | ||
| 186 | + if (_fseeki64(mine->f, seek, whence) == 0) { | ||
| 187 | return _ftelli64(mine->f); | ||
| 188 | } | ||
| 189 | #elif HAVE_FSEEKO | ||
| 190 | - if (fseeko(mine->f, skip, whence) == 0) { | ||
| 191 | + if (fseeko(mine->f, seek, whence) == 0) { | ||
| 192 | return ftello(mine->f); | ||
| 193 | } | ||
| 194 | #else | ||
| 195 | - if (fseek(mine->f, skip, whence) == 0) { | ||
| 196 | + if (fseek(mine->f, seek, whence) == 0) { | ||
| 197 | return ftell(mine->f); | ||
| 198 | } | ||
| 199 | #endif | ||
| 200 | @@ -227,4 +230,4 @@ FILE_close(struct archive *a, void *client_data) | ||
| 201 | free(mine->buffer); | ||
| 202 | free(mine); | ||
| 203 | return (ARCHIVE_OK); | ||
| 204 | -} | ||
| 205 | \ No newline at end of file | ||
| 206 | +} | ||
| 207 | diff --git a/libarchive/archive_read_open_filename.c b/libarchive/archive_read_open_filename.c | ||
| 208 | index 05f0ffbd..3894b15c 100644 | ||
| 209 | --- a/libarchive/archive_read_open_filename.c | ||
| 210 | +++ b/libarchive/archive_read_open_filename.c | ||
| 211 | @@ -449,20 +449,24 @@ file_skip_lseek(struct archive *a, void *client_data, int64_t request) | ||
| 212 | struct read_file_data *mine = (struct read_file_data *)client_data; | ||
| 213 | #if defined(_WIN32) && !defined(__CYGWIN__) | ||
| 214 | /* We use _lseeki64() on Windows. */ | ||
| 215 | - int64_t old_offset, new_offset; | ||
| 216 | + int64_t old_offset, new_offset, skip = request; | ||
| 217 | #else | ||
| 218 | - off_t old_offset, new_offset; | ||
| 219 | + off_t old_offset, new_offset, skip = (off_t)request; | ||
| 220 | #endif | ||
| 221 | + int skip_bits = sizeof(skip) * 8 - 1; | ||
| 222 | |||
| 223 | /* We use off_t here because lseek() is declared that way. */ | ||
| 224 | |||
| 225 | - /* TODO: Deal with case where off_t isn't 64 bits. | ||
| 226 | - * This shouldn't be a problem on Linux or other POSIX | ||
| 227 | - * systems, since the configuration logic for libarchive | ||
| 228 | - * tries to obtain a 64-bit off_t. | ||
| 229 | - */ | ||
| 230 | + /* Reduce a request that would overflow the 'skip' variable. */ | ||
| 231 | + if (sizeof(request) > sizeof(skip)) { | ||
| 232 | + const int64_t max_skip = | ||
| 233 | + (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1; | ||
| 234 | + if (request > max_skip) | ||
| 235 | + skip = max_skip; | ||
| 236 | + } | ||
| 237 | + | ||
| 238 | if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0 && | ||
| 239 | - (new_offset = lseek(mine->fd, request, SEEK_CUR)) >= 0) | ||
| 240 | + (new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0) | ||
| 241 | return (new_offset - old_offset); | ||
| 242 | |||
| 243 | /* If lseek() fails, don't bother trying again. */ | ||
| 244 | @@ -510,11 +514,24 @@ static int64_t | ||
| 245 | file_seek(struct archive *a, void *client_data, int64_t request, int whence) | ||
| 246 | { | ||
| 247 | struct read_file_data *mine = (struct read_file_data *)client_data; | ||
| 248 | + off_t seek = (off_t)request; | ||
| 249 | int64_t r; | ||
| 250 | + int seek_bits = sizeof(seek) * 8 - 1; | ||
| 251 | |||
| 252 | /* We use off_t here because lseek() is declared that way. */ | ||
| 253 | - /* See above for notes about when off_t is less than 64 bits. */ | ||
| 254 | - r = lseek(mine->fd, request, whence); | ||
| 255 | + | ||
| 256 | + /* Reduce a request that would overflow the 'seek' variable. */ | ||
| 257 | + if (sizeof(request) > sizeof(seek)) { | ||
| 258 | + const int64_t max_seek = | ||
| 259 | + (((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1; | ||
| 260 | + const int64_t min_seek = ~max_seek; | ||
| 261 | + if (request > max_seek) | ||
| 262 | + seek = (off_t)max_seek; | ||
| 263 | + else if (request < min_seek) | ||
| 264 | + seek = (off_t)min_seek; | ||
| 265 | + } | ||
| 266 | + | ||
| 267 | + r = lseek(mine->fd, seek, whence); | ||
| 268 | if (r >= 0) | ||
| 269 | return r; | ||
| 270 | |||
| 271 | diff --git a/libarchive/test/read_open_memory.c b/libarchive/test/read_open_memory.c | ||
| 272 | index 6d2468cd..9262ab9d 100644 | ||
| 273 | --- a/libarchive/test/read_open_memory.c | ||
| 274 | +++ b/libarchive/test/read_open_memory.c | ||
| 275 | @@ -168,7 +168,7 @@ memory_read_skip(struct archive *a, void *client_data, int64_t skip) | ||
| 276 | |||
| 277 | (void)a; /* UNUSED */ | ||
| 278 | /* We can't skip by more than is available. */ | ||
| 279 | - if ((off_t)skip > (off_t)(mine->end - mine->p)) | ||
| 280 | + if (skip > mine->end - mine->p) | ||
| 281 | skip = mine->end - mine->p; | ||
| 282 | /* Always do small skips by prime amounts. */ | ||
| 283 | if (skip > 71) | ||
| 284 | diff --git a/libarchive/test/test_sparse_basic.c b/libarchive/test/test_sparse_basic.c | ||
| 285 | index 23cde567..93710cb6 100644 | ||
| 286 | --- a/libarchive/test/test_sparse_basic.c | ||
| 287 | +++ b/libarchive/test/test_sparse_basic.c | ||
| 288 | @@ -606,7 +606,8 @@ DEFINE_TEST(test_sparse_basic) | ||
| 289 | verify_sparse_file(a, "file2", sparse_file2, 20); | ||
| 290 | /* Encoded non sparse; expect a data block but no sparse entries. */ | ||
| 291 | verify_sparse_file(a, "file3", sparse_file3, 0); | ||
| 292 | - verify_sparse_file(a, "file4", sparse_file4, 2); | ||
| 293 | + if (sizeof(off_t) > 4) | ||
| 294 | + verify_sparse_file(a, "file4", sparse_file4, 2); | ||
| 295 | |||
| 296 | assertEqualInt(ARCHIVE_OK, archive_read_free(a)); | ||
| 297 | |||
| 298 | @@ -633,7 +634,8 @@ DEFINE_TEST(test_sparse_basic) | ||
| 299 | verify_sparse_file(a, "file1", sparse_file1, 0); | ||
| 300 | verify_sparse_file(a, "file2", sparse_file2, 0); | ||
| 301 | verify_sparse_file(a, "file3", sparse_file3, 0); | ||
| 302 | - verify_sparse_file(a, "file4", sparse_file4, 0); | ||
| 303 | + if (sizeof(off_t) > 4) | ||
| 304 | + verify_sparse_file(a, "file4", sparse_file4, 0); | ||
| 305 | |||
| 306 | assertEqualInt(ARCHIVE_OK, archive_read_free(a)); | ||
| 307 | |||
| 308 | diff --git a/libarchive/test/test_tar_large.c b/libarchive/test/test_tar_large.c | ||
| 309 | index c1f37916..1cde3218 100644 | ||
| 310 | --- a/libarchive/test/test_tar_large.c | ||
| 311 | +++ b/libarchive/test/test_tar_large.c | ||
| 312 | @@ -176,7 +176,7 @@ memory_read_skip(struct archive *a, void *_private, int64_t skip) | ||
| 313 | } | ||
| 314 | if (private->filebytes > 0) { | ||
| 315 | if (private->filebytes < skip) | ||
| 316 | - skip = (off_t)private->filebytes; | ||
| 317 | + skip = private->filebytes; | ||
| 318 | private->filebytes -= skip; | ||
| 319 | } else { | ||
| 320 | skip = 0; | ||
diff --git a/meta/recipes-extended/libarchive/libarchive/CVE-2025-5918.patch b/meta/recipes-extended/libarchive/libarchive/CVE-2025-5918.patch new file mode 100644 index 0000000000..6ca6f6678c --- /dev/null +++ b/meta/recipes-extended/libarchive/libarchive/CVE-2025-5918.patch | |||
| @@ -0,0 +1,217 @@ | |||
| 1 | From dcbf1e0ededa95849f098d154a25876ed5754bcf Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Tobias Stoeckmann <stoeckmann@users.noreply.github.com> | ||
| 3 | Date: Tue, 15 Apr 2025 06:02:17 +0200 | ||
| 4 | Subject: [PATCH] Do not skip past EOF while reading (#2584) | ||
| 5 | |||
| 6 | Make sure to not skip past end of file for better error messages. One | ||
| 7 | such example is now visible with rar testsuite. You can see the | ||
| 8 | difference already by an actually not useless use of cat: | ||
| 9 | |||
| 10 | ``` | ||
| 11 | $ cat .../test_read_format_rar_ppmd_use_after_free.rar | bsdtar -t | ||
| 12 | bsdtar: Archive entry has empty or unreadable filename ... skipping. | ||
| 13 | bsdtar: Archive entry has empty or unreadable filename ... skipping. | ||
| 14 | bsdtar: Truncated input file (needed 119 bytes, only 0 available) | ||
| 15 | bsdtar: Error exit delayed from previous errors. | ||
| 16 | ``` | ||
| 17 | |||
| 18 | compared to | ||
| 19 | |||
| 20 | ``` | ||
| 21 | $ bsdtar -tf .../test_read_format_rar_ppmd_use_after_free.rar | ||
| 22 | bsdtar: Archive entry has empty or unreadable filename ... skipping. | ||
| 23 | bsdtar: Archive entry has empty or unreadable filename ... skipping. | ||
| 24 | bsdtar: Error exit delayed from previous errors. | ||
| 25 | ``` | ||
| 26 | |||
| 27 | Since the former cannot lseek, the error is a different one | ||
| 28 | (ARCHIVE_FATAL vs ARCHIVE_EOF). The piped version states explicitly that | ||
| 29 | truncation occurred, while the latter states EOF because the skip past | ||
| 30 | the end of file was successful. | ||
| 31 | |||
| 32 | Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org> | ||
| 33 | |||
| 34 | CVE: CVE-2025-5918 | ||
| 35 | Upstream-Status: Backport [https://github.com/libarchive/libarchive/commit/dcbf1e0ededa95849f098d154a25876ed5754bcf] | ||
| 36 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 37 | --- | ||
| 38 | libarchive/archive_read_open_fd.c | 13 +++++++--- | ||
| 39 | libarchive/archive_read_open_file.c | 33 +++++++++++++++++++------ | ||
| 40 | libarchive/archive_read_open_filename.c | 16 +++++++++--- | ||
| 41 | libarchive/test/test_read_format_rar.c | 6 ++--- | ||
| 42 | 4 files changed, 50 insertions(+), 18 deletions(-) | ||
| 43 | |||
| 44 | diff --git a/libarchive/archive_read_open_fd.c b/libarchive/archive_read_open_fd.c | ||
| 45 | index 3fd536d5..dc7c9e52 100644 | ||
| 46 | --- a/libarchive/archive_read_open_fd.c | ||
| 47 | +++ b/libarchive/archive_read_open_fd.c | ||
| 48 | @@ -53,6 +53,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_open_fd.c 201103 2009-12-28 | ||
| 49 | struct read_fd_data { | ||
| 50 | int fd; | ||
| 51 | size_t block_size; | ||
| 52 | + int64_t size; | ||
| 53 | char use_lseek; | ||
| 54 | void *buffer; | ||
| 55 | }; | ||
| 56 | @@ -96,6 +97,7 @@ archive_read_open_fd(struct archive *a, int fd, size_t block_size) | ||
| 57 | if (S_ISREG(st.st_mode)) { | ||
| 58 | archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); | ||
| 59 | mine->use_lseek = 1; | ||
| 60 | + mine->size = st.st_size; | ||
| 61 | } | ||
| 62 | #if defined(__CYGWIN__) || defined(_WIN32) | ||
| 63 | setmode(mine->fd, O_BINARY); | ||
| 64 | @@ -152,9 +154,14 @@ file_skip(struct archive *a, void *client_data, int64_t request) | ||
| 65 | if (skip == 0) | ||
| 66 | return (0); | ||
| 67 | |||
| 68 | - if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) && | ||
| 69 | - ((new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0)) | ||
| 70 | - return (new_offset - old_offset); | ||
| 71 | + if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) { | ||
| 72 | + if (old_offset >= mine->size || | ||
| 73 | + skip > mine->size - old_offset) { | ||
| 74 | + /* Do not seek past end of file. */ | ||
| 75 | + errno = ESPIPE; | ||
| 76 | + } else if ((new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0) | ||
| 77 | + return (new_offset - old_offset); | ||
| 78 | + } | ||
| 79 | |||
| 80 | /* If seek failed once, it will probably fail again. */ | ||
| 81 | mine->use_lseek = 0; | ||
| 82 | diff --git a/libarchive/archive_read_open_file.c b/libarchive/archive_read_open_file.c | ||
| 83 | index 2829b9a5..6ed18a0c 100644 | ||
| 84 | --- a/libarchive/archive_read_open_file.c | ||
| 85 | +++ b/libarchive/archive_read_open_file.c | ||
| 86 | @@ -53,6 +53,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_open_file.c 201093 2009-12- | ||
| 87 | struct read_FILE_data { | ||
| 88 | FILE *f; | ||
| 89 | size_t block_size; | ||
| 90 | + int64_t size; | ||
| 91 | void *buffer; | ||
| 92 | char can_skip; | ||
| 93 | }; | ||
| 94 | @@ -92,6 +93,7 @@ archive_read_open_FILE(struct archive *a, FILE *f) | ||
| 95 | archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino); | ||
| 96 | /* Enable the seek optimization only for regular files. */ | ||
| 97 | mine->can_skip = 1; | ||
| 98 | + mine->size = st.st_size; | ||
| 99 | } | ||
| 100 | |||
| 101 | #if defined(__CYGWIN__) || defined(_WIN32) | ||
| 102 | @@ -131,6 +133,7 @@ FILE_skip(struct archive *a, void *client_data, int64_t request) | ||
| 103 | #else | ||
| 104 | long skip = (long)request; | ||
| 105 | #endif | ||
| 106 | + int64_t old_offset, new_offset; | ||
| 107 | int skip_bits = sizeof(skip) * 8 - 1; | ||
| 108 | |||
| 109 | (void)a; /* UNUSED */ | ||
| 110 | @@ -154,19 +157,33 @@ FILE_skip(struct archive *a, void *client_data, int64_t request) | ||
| 111 | |||
| 112 | #ifdef __ANDROID__ | ||
| 113 | /* fileno() isn't safe on all platforms ... see above. */ | ||
| 114 | - if (lseek(fileno(mine->f), skip, SEEK_CUR) < 0) | ||
| 115 | + old_offset = lseek(fileno(mine->f), 0, SEEK_CUR); | ||
| 116 | #elif HAVE_FSEEKO | ||
| 117 | - if (fseeko(mine->f, skip, SEEK_CUR) != 0) | ||
| 118 | + old_offset = ftello(mine->f); | ||
| 119 | #elif HAVE__FSEEKI64 | ||
| 120 | - if (_fseeki64(mine->f, skip, SEEK_CUR) != 0) | ||
| 121 | + old_offset = _ftelli64(mine->f); | ||
| 122 | #else | ||
| 123 | - if (fseek(mine->f, skip, SEEK_CUR) != 0) | ||
| 124 | + old_offset = ftell(mine->f); | ||
| 125 | #endif | ||
| 126 | - { | ||
| 127 | - mine->can_skip = 0; | ||
| 128 | - return (0); | ||
| 129 | + if (old_offset >= 0) { | ||
| 130 | + if (old_offset < mine->size && | ||
| 131 | + skip <= mine->size - old_offset) { | ||
| 132 | +#ifdef __ANDROID__ | ||
| 133 | + new_offset = lseek(fileno(mine->f), skip, SEEK_CUR); | ||
| 134 | +#elif HAVE__FSEEKI64 | ||
| 135 | + new_offset = _fseeki64(mine->f, skip, SEEK_CUR); | ||
| 136 | +#elif HAVE_FSEEKO | ||
| 137 | + new_offset = fseeko(mine->f, skip, SEEK_CUR); | ||
| 138 | +#else | ||
| 139 | + new_offset = fseek(mine->f, skip, SEEK_CUR); | ||
| 140 | +#endif | ||
| 141 | + if (new_offset >= 0) | ||
| 142 | + return (new_offset - old_offset); | ||
| 143 | + } | ||
| 144 | } | ||
| 145 | - return (request); | ||
| 146 | + | ||
| 147 | + mine->can_skip = 0; | ||
| 148 | + return (0); | ||
| 149 | } | ||
| 150 | |||
| 151 | /* | ||
| 152 | diff --git a/libarchive/archive_read_open_filename.c b/libarchive/archive_read_open_filename.c | ||
| 153 | index 3894b15c..5f5b3f1f 100644 | ||
| 154 | --- a/libarchive/archive_read_open_filename.c | ||
| 155 | +++ b/libarchive/archive_read_open_filename.c | ||
| 156 | @@ -75,6 +75,7 @@ struct read_file_data { | ||
| 157 | size_t block_size; | ||
| 158 | void *buffer; | ||
| 159 | mode_t st_mode; /* Mode bits for opened file. */ | ||
| 160 | + int64_t size; | ||
| 161 | char use_lseek; | ||
| 162 | enum fnt_e { FNT_STDIN, FNT_MBS, FNT_WCS } filename_type; | ||
| 163 | union { | ||
| 164 | @@ -370,8 +371,10 @@ file_open(struct archive *a, void *client_data) | ||
| 165 | mine->st_mode = st.st_mode; | ||
| 166 | |||
| 167 | /* Disk-like inputs can use lseek(). */ | ||
| 168 | - if (is_disk_like) | ||
| 169 | + if (is_disk_like) { | ||
| 170 | mine->use_lseek = 1; | ||
| 171 | + mine->size = st.st_size; | ||
| 172 | + } | ||
| 173 | |||
| 174 | return (ARCHIVE_OK); | ||
| 175 | fail: | ||
| 176 | @@ -465,9 +468,14 @@ file_skip_lseek(struct archive *a, void *client_data, int64_t request) | ||
| 177 | skip = max_skip; | ||
| 178 | } | ||
| 179 | |||
| 180 | - if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0 && | ||
| 181 | - (new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0) | ||
| 182 | - return (new_offset - old_offset); | ||
| 183 | + if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) { | ||
| 184 | + if (old_offset >= mine->size || | ||
| 185 | + skip > mine->size - old_offset) { | ||
| 186 | + /* Do not seek past end of file. */ | ||
| 187 | + errno = ESPIPE; | ||
| 188 | + } else if ((new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0) | ||
| 189 | + return (new_offset - old_offset); | ||
| 190 | + } | ||
| 191 | |||
| 192 | /* If lseek() fails, don't bother trying again. */ | ||
| 193 | mine->use_lseek = 0; | ||
| 194 | diff --git a/libarchive/test/test_read_format_rar.c b/libarchive/test/test_read_format_rar.c | ||
| 195 | index dce567af..fce44a9d 100644 | ||
| 196 | --- a/libarchive/test/test_read_format_rar.c | ||
| 197 | +++ b/libarchive/test/test_read_format_rar.c | ||
| 198 | @@ -3776,8 +3776,8 @@ DEFINE_TEST(test_read_format_rar_ppmd_use_after_free) | ||
| 199 | assertA(ARCHIVE_OK == archive_read_next_header(a, &ae)); | ||
| 200 | assertA(archive_read_data(a, buf, sizeof(buf)) <= 0); | ||
| 201 | |||
| 202 | - /* Test EOF */ | ||
| 203 | - assertA(1 == archive_read_next_header(a, &ae)); | ||
| 204 | + /* Test for truncation */ | ||
| 205 | + assertA(ARCHIVE_FATAL == archive_read_next_header(a, &ae)); | ||
| 206 | |||
| 207 | assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); | ||
| 208 | assertEqualInt(ARCHIVE_OK, archive_read_free(a)); | ||
| 209 | @@ -3803,7 +3803,7 @@ DEFINE_TEST(test_read_format_rar_ppmd_use_after_free2) | ||
| 210 | assertA(archive_read_data(a, buf, sizeof(buf)) <= 0); | ||
| 211 | |||
| 212 | /* Test EOF */ | ||
| 213 | - assertA(1 == archive_read_next_header(a, &ae)); | ||
| 214 | + assertA(ARCHIVE_FATAL == archive_read_next_header(a, &ae)); | ||
| 215 | |||
| 216 | assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); | ||
| 217 | assertEqualInt(ARCHIVE_OK, archive_read_free(a)); | ||
diff --git a/meta/recipes-extended/libarchive/libarchive_3.6.2.bb b/meta/recipes-extended/libarchive/libarchive_3.6.2.bb index 3937bfb82d..bfd4df8ad1 100644 --- a/meta/recipes-extended/libarchive/libarchive_3.6.2.bb +++ b/meta/recipes-extended/libarchive/libarchive_3.6.2.bb | |||
| @@ -39,6 +39,9 @@ SRC_URI = "http://libarchive.org/downloads/libarchive-${PV}.tar.gz \ | |||
| 39 | file://CVE-2025-5915.patch \ | 39 | file://CVE-2025-5915.patch \ |
| 40 | file://CVE-2025-5916.patch \ | 40 | file://CVE-2025-5916.patch \ |
| 41 | file://CVE-2025-5917.patch \ | 41 | file://CVE-2025-5917.patch \ |
| 42 | file://0001-FILE-seeking-support-2539.patch \ | ||
| 43 | file://0001-Improve-lseek-handling-2564.patch \ | ||
| 44 | file://CVE-2025-5918.patch \ | ||
| 42 | " | 45 | " |
| 43 | UPSTREAM_CHECK_URI = "http://libarchive.org/" | 46 | UPSTREAM_CHECK_URI = "http://libarchive.org/" |
| 44 | 47 | ||
