diff options
author | Peter Marko <peter.marko@siemens.com> | 2025-08-23 23:51:06 +0200 |
---|---|---|
committer | Steve Sakoman <steve@sakoman.com> | 2025-08-29 10:02:59 -0700 |
commit | 1828ecc19f426db84dcfc6254e33cab28a0889a4 (patch) | |
tree | a643a672051d0b48dc9cac75d04163f057d9e345 | |
parent | 3c89580ab00446b843e06dfd6fe898c1cd7c64a0 (diff) | |
download | poky-1828ecc19f426db84dcfc6254e33cab28a0889a4.tar.gz |
libarchive: patch CVE-2025-5918
Pick commits per [1]
Additionally pick a commit needed to apply these cleanly.
[1] https://security-tracker.debian.org/tracker/CVE-2025-5918
(From OE-Core rev: 20687d6eed86003eacd5c91ebfd1101f6413ee3f)
Signed-off-by: Peter Marko <peter.marko@siemens.com>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
4 files changed, 590 insertions, 0 deletions
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..484824659e --- /dev/null +++ b/meta/recipes-extended/libarchive/libarchive/0001-Improve-lseek-handling-2564.patch | |||
@@ -0,0 +1,319 @@ | |||
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 | Upstream-Status: Backport [https://github.com/libarchive/libarchive/commit/89b8c35ff4b5addc08a85bf5df02b407f8af1f6c] | ||
19 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
20 | --------- | ||
21 | |||
22 | Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org> | ||
23 | --- | ||
24 | libarchive/archive_read.c | 6 ---- | ||
25 | libarchive/archive_read_disk_posix.c | 3 +- | ||
26 | libarchive/archive_read_open_fd.c | 29 +++++++++++++------ | ||
27 | libarchive/archive_read_open_file.c | 35 ++++++++++++----------- | ||
28 | libarchive/archive_read_open_filename.c | 37 ++++++++++++++++++------- | ||
29 | libarchive/test/read_open_memory.c | 2 +- | ||
30 | libarchive/test/test_sparse_basic.c | 6 ++-- | ||
31 | libarchive/test/test_tar_large.c | 2 +- | ||
32 | 8 files changed, 75 insertions(+), 45 deletions(-) | ||
33 | |||
34 | diff --git a/libarchive/archive_read.c b/libarchive/archive_read.c | ||
35 | index 822c534b..50db8701 100644 | ||
36 | --- a/libarchive/archive_read.c | ||
37 | +++ b/libarchive/archive_read.c | ||
38 | @@ -176,15 +176,9 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request) | ||
39 | return 0; | ||
40 | |||
41 | if (self->archive->client.skipper != NULL) { | ||
42 | - /* Seek requests over 1GiB are broken down into | ||
43 | - * multiple seeks. This avoids overflows when the | ||
44 | - * requests get passed through 32-bit arguments. */ | ||
45 | - int64_t skip_limit = (int64_t)1 << 30; | ||
46 | int64_t total = 0; | ||
47 | for (;;) { | ||
48 | int64_t get, ask = request; | ||
49 | - if (ask > skip_limit) | ||
50 | - ask = skip_limit; | ||
51 | get = (self->archive->client.skipper) | ||
52 | (&self->archive->archive, self->data, ask); | ||
53 | total += get; | ||
54 | diff --git a/libarchive/archive_read_disk_posix.c b/libarchive/archive_read_disk_posix.c | ||
55 | index 09965eb9..4839d62b 100644 | ||
56 | --- a/libarchive/archive_read_disk_posix.c | ||
57 | +++ b/libarchive/archive_read_disk_posix.c | ||
58 | @@ -778,7 +778,8 @@ _archive_read_data_block(struct archive *_a, const void **buff, | ||
59 | */ | ||
60 | if (t->current_sparse->offset > t->entry_total) { | ||
61 | if (lseek(t->entry_fd, | ||
62 | - (off_t)t->current_sparse->offset, SEEK_SET) < 0) { | ||
63 | + (off_t)t->current_sparse->offset, SEEK_SET) != | ||
64 | + t->current_sparse->offset) { | ||
65 | archive_set_error(&a->archive, errno, "Seek error"); | ||
66 | r = ARCHIVE_FATAL; | ||
67 | a->archive.state = ARCHIVE_STATE_FATAL; | ||
68 | diff --git a/libarchive/archive_read_open_fd.c b/libarchive/archive_read_open_fd.c | ||
69 | index debfde20..3fd536d5 100644 | ||
70 | --- a/libarchive/archive_read_open_fd.c | ||
71 | +++ b/libarchive/archive_read_open_fd.c | ||
72 | @@ -131,7 +131,7 @@ static int64_t | ||
73 | file_skip(struct archive *a, void *client_data, int64_t request) | ||
74 | { | ||
75 | struct read_fd_data *mine = (struct read_fd_data *)client_data; | ||
76 | - int64_t skip = request; | ||
77 | + off_t skip = (off_t)request; | ||
78 | int64_t old_offset, new_offset; | ||
79 | int skip_bits = sizeof(skip) * 8 - 1; /* off_t is a signed type. */ | ||
80 | |||
81 | @@ -140,15 +140,15 @@ file_skip(struct archive *a, void *client_data, int64_t request) | ||
82 | |||
83 | /* Reduce a request that would overflow the 'skip' variable. */ | ||
84 | if (sizeof(request) > sizeof(skip)) { | ||
85 | - int64_t max_skip = | ||
86 | + const int64_t max_skip = | ||
87 | (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1; | ||
88 | if (request > max_skip) | ||
89 | - skip = max_skip; | ||
90 | + skip = (off_t)max_skip; | ||
91 | } | ||
92 | |||
93 | - /* Reduce request to the next smallest multiple of block_size */ | ||
94 | - request = (request / mine->block_size) * mine->block_size; | ||
95 | - if (request == 0) | ||
96 | + /* Reduce 'skip' to the next smallest multiple of block_size */ | ||
97 | + skip = (off_t)(((int64_t)skip / mine->block_size) * mine->block_size); | ||
98 | + if (skip == 0) | ||
99 | return (0); | ||
100 | |||
101 | if (((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0) && | ||
102 | @@ -178,11 +178,24 @@ static int64_t | ||
103 | file_seek(struct archive *a, void *client_data, int64_t request, int whence) | ||
104 | { | ||
105 | struct read_fd_data *mine = (struct read_fd_data *)client_data; | ||
106 | + off_t seek = (off_t)request; | ||
107 | int64_t r; | ||
108 | + int seek_bits = sizeof(seek) * 8 - 1; /* off_t is a signed type. */ | ||
109 | |||
110 | /* We use off_t here because lseek() is declared that way. */ | ||
111 | - /* See above for notes about when off_t is less than 64 bits. */ | ||
112 | - r = lseek(mine->fd, request, whence); | ||
113 | + | ||
114 | + /* Reduce a request that would overflow the 'seek' variable. */ | ||
115 | + if (sizeof(request) > sizeof(seek)) { | ||
116 | + const int64_t max_seek = | ||
117 | + (((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1; | ||
118 | + const int64_t min_seek = ~max_seek; | ||
119 | + if (request > max_seek) | ||
120 | + seek = (off_t)max_seek; | ||
121 | + else if (request < min_seek) | ||
122 | + seek = (off_t)min_seek; | ||
123 | + } | ||
124 | + | ||
125 | + r = lseek(mine->fd, seek, whence); | ||
126 | if (r >= 0) | ||
127 | return r; | ||
128 | |||
129 | diff --git a/libarchive/archive_read_open_file.c b/libarchive/archive_read_open_file.c | ||
130 | index ecd56dce..2829b9a5 100644 | ||
131 | --- a/libarchive/archive_read_open_file.c | ||
132 | +++ b/libarchive/archive_read_open_file.c | ||
133 | @@ -145,7 +145,7 @@ FILE_skip(struct archive *a, void *client_data, int64_t request) | ||
134 | |||
135 | /* If request is too big for a long or an off_t, reduce it. */ | ||
136 | if (sizeof(request) > sizeof(skip)) { | ||
137 | - int64_t max_skip = | ||
138 | + const int64_t max_skip = | ||
139 | (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1; | ||
140 | if (request > max_skip) | ||
141 | skip = max_skip; | ||
142 | @@ -176,39 +176,42 @@ FILE_seek(struct archive *a, void *client_data, int64_t request, int whence) | ||
143 | { | ||
144 | struct read_FILE_data *mine = (struct read_FILE_data *)client_data; | ||
145 | #if HAVE__FSEEKI64 | ||
146 | - int64_t skip = request; | ||
147 | + int64_t seek = request; | ||
148 | #elif HAVE_FSEEKO | ||
149 | - off_t skip = (off_t)request; | ||
150 | + off_t seek = (off_t)request; | ||
151 | #else | ||
152 | - long skip = (long)request; | ||
153 | + long seek = (long)request; | ||
154 | #endif | ||
155 | - int skip_bits = sizeof(skip) * 8 - 1; | ||
156 | + int seek_bits = sizeof(seek) * 8 - 1; | ||
157 | (void)a; /* UNUSED */ | ||
158 | |||
159 | - /* If request is too big for a long or an off_t, reduce it. */ | ||
160 | - if (sizeof(request) > sizeof(skip)) { | ||
161 | - int64_t max_skip = | ||
162 | - (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1; | ||
163 | - if (request > max_skip) | ||
164 | - skip = max_skip; | ||
165 | + /* Reduce a request that would overflow the 'seek' variable. */ | ||
166 | + if (sizeof(request) > sizeof(seek)) { | ||
167 | + const int64_t max_seek = | ||
168 | + (((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1; | ||
169 | + const int64_t min_seek = ~max_seek; | ||
170 | + if (request > max_seek) | ||
171 | + seek = max_seek; | ||
172 | + else if (request < min_seek) | ||
173 | + seek = min_seek; | ||
174 | } | ||
175 | |||
176 | #ifdef __ANDROID__ | ||
177 | /* Newer Android versions have fseeko...to meditate. */ | ||
178 | - int64_t ret = lseek(fileno(mine->f), skip, whence); | ||
179 | + int64_t ret = lseek(fileno(mine->f), seek, whence); | ||
180 | if (ret >= 0) { | ||
181 | return ret; | ||
182 | } | ||
183 | #elif HAVE__FSEEKI64 | ||
184 | - if (_fseeki64(mine->f, skip, whence) == 0) { | ||
185 | + if (_fseeki64(mine->f, seek, whence) == 0) { | ||
186 | return _ftelli64(mine->f); | ||
187 | } | ||
188 | #elif HAVE_FSEEKO | ||
189 | - if (fseeko(mine->f, skip, whence) == 0) { | ||
190 | + if (fseeko(mine->f, seek, whence) == 0) { | ||
191 | return ftello(mine->f); | ||
192 | } | ||
193 | #else | ||
194 | - if (fseek(mine->f, skip, whence) == 0) { | ||
195 | + if (fseek(mine->f, seek, whence) == 0) { | ||
196 | return ftell(mine->f); | ||
197 | } | ||
198 | #endif | ||
199 | @@ -226,4 +229,4 @@ FILE_close(struct archive *a, void *client_data) | ||
200 | free(mine->buffer); | ||
201 | free(mine); | ||
202 | return (ARCHIVE_OK); | ||
203 | -} | ||
204 | \ No newline at end of file | ||
205 | +} | ||
206 | diff --git a/libarchive/archive_read_open_filename.c b/libarchive/archive_read_open_filename.c | ||
207 | index 05f0ffbd..3894b15c 100644 | ||
208 | --- a/libarchive/archive_read_open_filename.c | ||
209 | +++ b/libarchive/archive_read_open_filename.c | ||
210 | @@ -479,20 +479,24 @@ file_skip_lseek(struct archive *a, void *client_data, int64_t request) | ||
211 | struct read_file_data *mine = (struct read_file_data *)client_data; | ||
212 | #if defined(_WIN32) && !defined(__CYGWIN__) | ||
213 | /* We use _lseeki64() on Windows. */ | ||
214 | - int64_t old_offset, new_offset; | ||
215 | + int64_t old_offset, new_offset, skip = request; | ||
216 | #else | ||
217 | - off_t old_offset, new_offset; | ||
218 | + off_t old_offset, new_offset, skip = (off_t)request; | ||
219 | #endif | ||
220 | + int skip_bits = sizeof(skip) * 8 - 1; | ||
221 | |||
222 | /* We use off_t here because lseek() is declared that way. */ | ||
223 | |||
224 | - /* TODO: Deal with case where off_t isn't 64 bits. | ||
225 | - * This shouldn't be a problem on Linux or other POSIX | ||
226 | - * systems, since the configuration logic for libarchive | ||
227 | - * tries to obtain a 64-bit off_t. | ||
228 | - */ | ||
229 | + /* Reduce a request that would overflow the 'skip' variable. */ | ||
230 | + if (sizeof(request) > sizeof(skip)) { | ||
231 | + const int64_t max_skip = | ||
232 | + (((int64_t)1 << (skip_bits - 1)) - 1) * 2 + 1; | ||
233 | + if (request > max_skip) | ||
234 | + skip = max_skip; | ||
235 | + } | ||
236 | + | ||
237 | if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0 && | ||
238 | - (new_offset = lseek(mine->fd, request, SEEK_CUR)) >= 0) | ||
239 | + (new_offset = lseek(mine->fd, skip, SEEK_CUR)) >= 0) | ||
240 | return (new_offset - old_offset); | ||
241 | |||
242 | /* If lseek() fails, don't bother trying again. */ | ||
243 | @@ -540,11 +544,24 @@ static int64_t | ||
244 | file_seek(struct archive *a, void *client_data, int64_t request, int whence) | ||
245 | { | ||
246 | struct read_file_data *mine = (struct read_file_data *)client_data; | ||
247 | + off_t seek = (off_t)request; | ||
248 | int64_t r; | ||
249 | + int seek_bits = sizeof(seek) * 8 - 1; | ||
250 | |||
251 | /* We use off_t here because lseek() is declared that way. */ | ||
252 | - /* See above for notes about when off_t is less than 64 bits. */ | ||
253 | - r = lseek(mine->fd, request, whence); | ||
254 | + | ||
255 | + /* Reduce a request that would overflow the 'seek' variable. */ | ||
256 | + if (sizeof(request) > sizeof(seek)) { | ||
257 | + const int64_t max_seek = | ||
258 | + (((int64_t)1 << (seek_bits - 1)) - 1) * 2 + 1; | ||
259 | + const int64_t min_seek = ~max_seek; | ||
260 | + if (request > max_seek) | ||
261 | + seek = (off_t)max_seek; | ||
262 | + else if (request < min_seek) | ||
263 | + seek = (off_t)min_seek; | ||
264 | + } | ||
265 | + | ||
266 | + r = lseek(mine->fd, seek, whence); | ||
267 | if (r >= 0) | ||
268 | return r; | ||
269 | |||
270 | diff --git a/libarchive/test/read_open_memory.c b/libarchive/test/read_open_memory.c | ||
271 | index 6d2468cd..9262ab9d 100644 | ||
272 | --- a/libarchive/test/read_open_memory.c | ||
273 | +++ b/libarchive/test/read_open_memory.c | ||
274 | @@ -167,7 +167,7 @@ memory_read_skip(struct archive *a, void *client_data, int64_t skip) | ||
275 | |||
276 | (void)a; /* UNUSED */ | ||
277 | /* We can't skip by more than is available. */ | ||
278 | - if ((off_t)skip > (off_t)(mine->end - mine->p)) | ||
279 | + if (skip > mine->end - mine->p) | ||
280 | skip = mine->end - mine->p; | ||
281 | /* Always do small skips by prime amounts. */ | ||
282 | if (skip > 71) | ||
283 | diff --git a/libarchive/test/test_sparse_basic.c b/libarchive/test/test_sparse_basic.c | ||
284 | index 23cde567..93710cb6 100644 | ||
285 | --- a/libarchive/test/test_sparse_basic.c | ||
286 | +++ b/libarchive/test/test_sparse_basic.c | ||
287 | @@ -608,7 +608,8 @@ DEFINE_TEST(test_sparse_basic) | ||
288 | verify_sparse_file(a, "file2", sparse_file2, 20); | ||
289 | /* Encoded non sparse; expect a data block but no sparse entries. */ | ||
290 | verify_sparse_file(a, "file3", sparse_file3, 0); | ||
291 | - verify_sparse_file(a, "file4", sparse_file4, 2); | ||
292 | + if (sizeof(off_t) > 4) | ||
293 | + verify_sparse_file(a, "file4", sparse_file4, 2); | ||
294 | |||
295 | assertEqualInt(ARCHIVE_OK, archive_read_free(a)); | ||
296 | |||
297 | @@ -635,7 +636,8 @@ DEFINE_TEST(test_sparse_basic) | ||
298 | verify_sparse_file(a, "file1", sparse_file1, 0); | ||
299 | verify_sparse_file(a, "file2", sparse_file2, 0); | ||
300 | verify_sparse_file(a, "file3", sparse_file3, 0); | ||
301 | - verify_sparse_file(a, "file4", sparse_file4, 0); | ||
302 | + if (sizeof(off_t) > 4) | ||
303 | + verify_sparse_file(a, "file4", sparse_file4, 0); | ||
304 | |||
305 | assertEqualInt(ARCHIVE_OK, archive_read_free(a)); | ||
306 | |||
307 | diff --git a/libarchive/test/test_tar_large.c b/libarchive/test/test_tar_large.c | ||
308 | index c1f37916..1cde3218 100644 | ||
309 | --- a/libarchive/test/test_tar_large.c | ||
310 | +++ b/libarchive/test/test_tar_large.c | ||
311 | @@ -175,7 +175,7 @@ memory_read_skip(struct archive *a, void *_private, int64_t skip) | ||
312 | } | ||
313 | if (private->filebytes > 0) { | ||
314 | if (private->filebytes < skip) | ||
315 | - skip = (off_t)private->filebytes; | ||
316 | + skip = private->filebytes; | ||
317 | private->filebytes -= skip; | ||
318 | } else { | ||
319 | skip = 0; | ||
diff --git a/meta/recipes-extended/libarchive/libarchive/CVE-2025-5918-01.patch b/meta/recipes-extended/libarchive/libarchive/CVE-2025-5918-01.patch new file mode 100644 index 0000000000..98472d9173 --- /dev/null +++ b/meta/recipes-extended/libarchive/libarchive/CVE-2025-5918-01.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 | @@ -52,6 +52,7 @@ | ||
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 | @@ -95,6 +96,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 | @@ -151,9 +153,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 | @@ -52,6 +52,7 @@ | ||
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 | @@ -91,6 +92,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 | @@ -130,6 +132,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 | @@ -153,19 +156,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__FSEEKI64 | ||
117 | - if (_fseeki64(mine->f, skip, SEEK_CUR) != 0) | ||
118 | + old_offset = _ftelli64(mine->f); | ||
119 | #elif HAVE_FSEEKO | ||
120 | - if (fseeko(mine->f, skip, SEEK_CUR) != 0) | ||
121 | + old_offset = ftello(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 | @@ -74,6 +74,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 | @@ -400,8 +401,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 | @@ -495,9 +498,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 | @@ -3829,8 +3829,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 | @@ -3856,7 +3856,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/CVE-2025-5918-02.patch b/meta/recipes-extended/libarchive/libarchive/CVE-2025-5918-02.patch new file mode 100644 index 0000000000..bc6903d41c --- /dev/null +++ b/meta/recipes-extended/libarchive/libarchive/CVE-2025-5918-02.patch | |||
@@ -0,0 +1,51 @@ | |||
1 | From 51b4c35bb38b7df4af24de7f103863dd79129b01 Mon Sep 17 00:00:00 2001 | ||
2 | From: Tobias Stoeckmann <tobias@stoeckmann.org> | ||
3 | Date: Tue, 27 May 2025 17:09:12 +0200 | ||
4 | Subject: [PATCH] Fix FILE_skip regression | ||
5 | |||
6 | The fseek* family of functions return 0 on success, not the new offset. | ||
7 | This is only true for lseek. | ||
8 | |||
9 | Fixes https://github.com/libarchive/libarchive/issues/2641 | ||
10 | Fixes dcbf1e0ededa95849f098d154a25876ed5754bcf | ||
11 | |||
12 | Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org> | ||
13 | |||
14 | CVE: CVE-2025-5918 | ||
15 | Upstream-Status: Backport [https://github.com/libarchive/libarchive/commit/51b4c35bb38b7df4af24de7f103863dd79129b01] | ||
16 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
17 | --- | ||
18 | libarchive/archive_read_open_file.c | 11 +++++++---- | ||
19 | 1 file changed, 7 insertions(+), 4 deletions(-) | ||
20 | |||
21 | diff --git a/libarchive/archive_read_open_file.c b/libarchive/archive_read_open_file.c | ||
22 | index 6ed18a0c..742923ab 100644 | ||
23 | --- a/libarchive/archive_read_open_file.c | ||
24 | +++ b/libarchive/archive_read_open_file.c | ||
25 | @@ -132,7 +132,7 @@ FILE_skip(struct archive *a, void *client_data, int64_t request) | ||
26 | #else | ||
27 | long skip = (long)request; | ||
28 | #endif | ||
29 | - int64_t old_offset, new_offset; | ||
30 | + int64_t old_offset, new_offset = -1; | ||
31 | int skip_bits = sizeof(skip) * 8 - 1; | ||
32 | |||
33 | (void)a; /* UNUSED */ | ||
34 | @@ -170,11 +170,14 @@ FILE_skip(struct archive *a, void *client_data, int64_t request) | ||
35 | #ifdef __ANDROID__ | ||
36 | new_offset = lseek(fileno(mine->f), skip, SEEK_CUR); | ||
37 | #elif HAVE__FSEEKI64 | ||
38 | - new_offset = _fseeki64(mine->f, skip, SEEK_CUR); | ||
39 | + if (_fseeki64(mine->f, skip, SEEK_CUR) == 0) | ||
40 | + new_offset = _ftelli64(mine->f); | ||
41 | #elif HAVE_FSEEKO | ||
42 | - new_offset = fseeko(mine->f, skip, SEEK_CUR); | ||
43 | + if (fseeko(mine->f, skip, SEEK_CUR) == 0) | ||
44 | + new_offset = ftello(mine->f); | ||
45 | #else | ||
46 | - new_offset = fseek(mine->f, skip, SEEK_CUR); | ||
47 | + if (fseek(mine->f, skip, SEEK_CUR) == 0) | ||
48 | + new_offset = ftell(mine->f); | ||
49 | #endif | ||
50 | if (new_offset >= 0) | ||
51 | return (new_offset - old_offset); | ||
diff --git a/meta/recipes-extended/libarchive/libarchive_3.7.9.bb b/meta/recipes-extended/libarchive/libarchive_3.7.9.bb index a0f5d67700..6a5b99ff7f 100644 --- a/meta/recipes-extended/libarchive/libarchive_3.7.9.bb +++ b/meta/recipes-extended/libarchive/libarchive_3.7.9.bb | |||
@@ -34,6 +34,9 @@ SRC_URI = "https://libarchive.org/downloads/libarchive-${PV}.tar.gz \ | |||
34 | file://CVE-2025-5915.patch \ | 34 | file://CVE-2025-5915.patch \ |
35 | file://CVE-2025-5916.patch \ | 35 | file://CVE-2025-5916.patch \ |
36 | file://CVE-2025-5917.patch \ | 36 | file://CVE-2025-5917.patch \ |
37 | file://0001-Improve-lseek-handling-2564.patch \ | ||
38 | file://CVE-2025-5918-01.patch \ | ||
39 | file://CVE-2025-5918-02.patch \ | ||
37 | " | 40 | " |
38 | 41 | ||
39 | UPSTREAM_CHECK_URI = "http://libarchive.org/" | 42 | UPSTREAM_CHECK_URI = "http://libarchive.org/" |