summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Marko <peter.marko@siemens.com>2025-08-10 12:51:09 +0200
committerSteve Sakoman <steve@sakoman.com>2025-08-18 13:18:01 -0700
commit8f356f507e2863e7ffd13294a4bd82e88af6f469 (patch)
treed55cbee25779291ec5ee0f53c68adb45701665cb
parentaa3783670835e35390a275750333a5827ac1e171 (diff)
downloadpoky-8f356f507e2863e7ffd13294a4bd82e88af6f469.tar.gz
libarchive: patch CVE-2025-5918
Pick 2 commits as in scarthgap branch plus one additional precondition to apply those. (From OE-Core rev: e43507dad134c5036be1c79a37f73c34f4fb6292) Signed-off-by: Peter Marko <peter.marko@siemens.com> Signed-off-by: Steve Sakoman <steve@sakoman.com>
-rw-r--r--meta/recipes-extended/libarchive/libarchive/0001-FILE-seeking-support-2539.patch190
-rw-r--r--meta/recipes-extended/libarchive/libarchive/0001-Improve-lseek-handling-2564.patch320
-rw-r--r--meta/recipes-extended/libarchive/libarchive/CVE-2025-5918.patch217
-rw-r--r--meta/recipes-extended/libarchive/libarchive_3.6.2.bb3
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 @@
1From 09a2ed4853cd177264076a88c98e525e892a0d0b Mon Sep 17 00:00:00 2001
2From: ljdarj <ljd@luigiscorner.mu>
3Date: Sat, 15 Mar 2025 19:17:27 +0100
4Subject: [PATCH] FILE* seeking support (#2539)
5
6Adding a seeker function to archive_read_open_FILE().
7
8Fixes #437.
9
10Upstream-Status: Backport [https://github.com/libarchive/libarchive/commit/09a2ed4853cd177264076a88c98e525e892a0d0b]
11Signed-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
17diff --git a/libarchive/archive_read_open_file.c b/libarchive/archive_read_open_file.c
18index 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
157diff --git a/libarchive/test/test_open_file.c b/libarchive/test/test_open_file.c
158index 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 @@
1From 89b8c35ff4b5addc08a85bf5df02b407f8af1f6c Mon Sep 17 00:00:00 2001
2From: Tobias Stoeckmann <stoeckmann@users.noreply.github.com>
3Date: Sun, 6 Apr 2025 22:34:37 +0200
4Subject: [PATCH] Improve lseek handling (#2564)
5
6The skip functions are limited to 1 GB for cases in which libarchive
7runs on a system with an off_t or long with 32 bits. This has negative
8impact on 64 bit systems.
9
10Instead, make sure that _all_ subsequent functions truncate properly.
11Some of them already did and some had regressions for over 10 years.
12
13Tests pass on Debian 12 i686 configured with --disable-largefile, i.e.
14running with an off_t with 32 bits.
15
16Casts added where needed to still pass MSVC builds.
17
18---------
19
20Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
21
22Upstream-Status: Backport [https://github.com/libarchive/libarchive/commit/89b8c35ff4b5addc08a85bf5df02b407f8af1f6c]
23Signed-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
35diff --git a/libarchive/archive_read.c b/libarchive/archive_read.c
36index 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;
55diff --git a/libarchive/archive_read_disk_posix.c b/libarchive/archive_read_disk_posix.c
56index 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;
69diff --git a/libarchive/archive_read_open_fd.c b/libarchive/archive_read_open_fd.c
70index 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
130diff --git a/libarchive/archive_read_open_file.c b/libarchive/archive_read_open_file.c
131index 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+}
207diff --git a/libarchive/archive_read_open_filename.c b/libarchive/archive_read_open_filename.c
208index 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
271diff --git a/libarchive/test/read_open_memory.c b/libarchive/test/read_open_memory.c
272index 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)
284diff --git a/libarchive/test/test_sparse_basic.c b/libarchive/test/test_sparse_basic.c
285index 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
308diff --git a/libarchive/test/test_tar_large.c b/libarchive/test/test_tar_large.c
309index 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 @@
1From dcbf1e0ededa95849f098d154a25876ed5754bcf Mon Sep 17 00:00:00 2001
2From: Tobias Stoeckmann <stoeckmann@users.noreply.github.com>
3Date: Tue, 15 Apr 2025 06:02:17 +0200
4Subject: [PATCH] Do not skip past EOF while reading (#2584)
5
6Make sure to not skip past end of file for better error messages. One
7such example is now visible with rar testsuite. You can see the
8difference already by an actually not useless use of cat:
9
10```
11$ cat .../test_read_format_rar_ppmd_use_after_free.rar | bsdtar -t
12bsdtar: Archive entry has empty or unreadable filename ... skipping.
13bsdtar: Archive entry has empty or unreadable filename ... skipping.
14bsdtar: Truncated input file (needed 119 bytes, only 0 available)
15bsdtar: Error exit delayed from previous errors.
16```
17
18compared to
19
20```
21$ bsdtar -tf .../test_read_format_rar_ppmd_use_after_free.rar
22bsdtar: Archive entry has empty or unreadable filename ... skipping.
23bsdtar: Archive entry has empty or unreadable filename ... skipping.
24bsdtar: Error exit delayed from previous errors.
25```
26
27Since the former cannot lseek, the error is a different one
28(ARCHIVE_FATAL vs ARCHIVE_EOF). The piped version states explicitly that
29truncation occurred, while the latter states EOF because the skip past
30the end of file was successful.
31
32Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
33
34CVE: CVE-2025-5918
35Upstream-Status: Backport [https://github.com/libarchive/libarchive/commit/dcbf1e0ededa95849f098d154a25876ed5754bcf]
36Signed-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
44diff --git a/libarchive/archive_read_open_fd.c b/libarchive/archive_read_open_fd.c
45index 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;
82diff --git a/libarchive/archive_read_open_file.c b/libarchive/archive_read_open_file.c
83index 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 /*
152diff --git a/libarchive/archive_read_open_filename.c b/libarchive/archive_read_open_filename.c
153index 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;
194diff --git a/libarchive/test/test_read_format_rar.c b/libarchive/test/test_read_format_rar.c
195index 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 "
43UPSTREAM_CHECK_URI = "http://libarchive.org/" 46UPSTREAM_CHECK_URI = "http://libarchive.org/"
44 47