Skip to content

Commit 555bd2f

Browse files
committed
Merge branch 'PHP-8.0'
* PHP-8.0: Fix #77565: Incorrect locator detection in ZIP-based phars
2 parents 3d0c905 + 66a74f2 commit 555bd2f

File tree

5 files changed

+69
-35
lines changed

5 files changed

+69
-35
lines changed

ext/phar/tests/bug69441.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ $r = new Phar($fname, 0);
1212
}
1313
?>
1414
--EXPECTF--
15-
UnexpectedValueException: phar error: corrupted central directory entry, no magic signature in zip-based phar "%sbug69441.phar" in %sbug69441.php:%d
15+
UnexpectedValueException: phar error: end of central directory not found in zip-based phar "%sbug69441.phar" in %sbug69441.php:%d
1616
Stack trace:
1717
#0 %s%ebug69441.php(%d): Phar->__construct('%s', 0)
1818
#1 {main}

ext/phar/tests/bug77565.phpt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--TEST--
2+
Bug #77565 (Incorrect locator detection in ZIP-based phars)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('phar')) die('skip phar extension not available');
6+
?>
7+
--FILE--
8+
<?php
9+
$phar = new PharData(__DIR__ . '/bug77565.zip');
10+
var_dump($phar['1.zip']->getFilename());
11+
?>
12+
--EXPECT--
13+
string(5) "1.zip"

ext/phar/tests/bug77565.zip

318 Bytes
Binary file not shown.

ext/phar/tests/zip/corrupt_003.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ try {
1111
}
1212
?>
1313
--EXPECTF--
14-
phar error: corrupt zip archive, zip file comment truncated in zip-based phar "%sfilecomment.zip"
14+
phar error: end of central directory not found in zip-based phar "%sfilecomment.zip"

ext/phar/zip.c

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,29 @@ static void phar_zip_u2d_time(time_t time, char *dtime, char *ddate) /* {{{ */
161161
}
162162
/* }}} */
163163

164+
static char *phar_find_eocd(const char *s, size_t n)
165+
{
166+
const char *end = s + n + sizeof("PK\5\6") - 1 - sizeof(phar_zip_dir_end);
167+
168+
/* search backwards for end of central directory signatures */
169+
do {
170+
uint16_t comment_len;
171+
const char *eocd_start = zend_memnrstr(s, "PK\5\6", sizeof("PK\5\6") - 1, end);
172+
173+
if (eocd_start == NULL) {
174+
return NULL;
175+
}
176+
ZEND_ASSERT(eocd_start + sizeof(phar_zip_dir_end) <= s + n);
177+
comment_len = PHAR_GET_16(((phar_zip_dir_end *) eocd_start)->comment_len);
178+
if (eocd_start + sizeof(phar_zip_dir_end) + comment_len == s + n) {
179+
/* we can't be sure, but this looks like the proper EOCD signature */
180+
return (char *) eocd_start;
181+
}
182+
end = eocd_start;
183+
} while (end > s);
184+
return NULL;
185+
}
186+
164187
/**
165188
* Does not check for a previously opened phar in the cache.
166189
*
@@ -205,50 +228,48 @@ int phar_parse_zipfile(php_stream *fp, char *fname, size_t fname_len, char *alia
205228
return FAILURE;
206229
}
207230

208-
while ((p=(char *) memchr(p + 1, 'P', (size_t) (size - (p + 1 - buf)))) != NULL) {
209-
if ((p - buf) + sizeof(locator) <= (size_t)size && !memcmp(p + 1, "K\5\6", 3)) {
210-
memcpy((void *)&locator, (void *) p, sizeof(locator));
211-
if (PHAR_GET_16(locator.centraldisk) != 0 || PHAR_GET_16(locator.disknumber) != 0) {
212-
/* split archives not handled */
213-
php_stream_close(fp);
214-
if (error) {
215-
spprintf(error, 4096, "phar error: split archives spanning multiple zips cannot be processed in zip-based phar \"%s\"", fname);
216-
}
217-
return FAILURE;
231+
if ((p = phar_find_eocd(buf, size)) != NULL) {
232+
memcpy((void *)&locator, (void *) p, sizeof(locator));
233+
if (PHAR_GET_16(locator.centraldisk) != 0 || PHAR_GET_16(locator.disknumber) != 0) {
234+
/* split archives not handled */
235+
php_stream_close(fp);
236+
if (error) {
237+
spprintf(error, 4096, "phar error: split archives spanning multiple zips cannot be processed in zip-based phar \"%s\"", fname);
218238
}
239+
return FAILURE;
240+
}
219241

220-
if (PHAR_GET_16(locator.counthere) != PHAR_GET_16(locator.count)) {
221-
if (error) {
222-
spprintf(error, 4096, "phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar \"%s\"", fname);
223-
}
224-
php_stream_close(fp);
225-
return FAILURE;
242+
if (PHAR_GET_16(locator.counthere) != PHAR_GET_16(locator.count)) {
243+
if (error) {
244+
spprintf(error, 4096, "phar error: corrupt zip archive, conflicting file count in end of central directory record in zip-based phar \"%s\"", fname);
226245
}
246+
php_stream_close(fp);
247+
return FAILURE;
248+
}
227249

228-
mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
229-
mydata->is_persistent = PHAR_G(persist);
250+
mydata = pecalloc(1, sizeof(phar_archive_data), PHAR_G(persist));
251+
mydata->is_persistent = PHAR_G(persist);
230252

231-
/* read in archive comment, if any */
232-
if (PHAR_GET_16(locator.comment_len)) {
253+
/* read in archive comment, if any */
254+
if (PHAR_GET_16(locator.comment_len)) {
233255

234-
metadata = p + sizeof(locator);
256+
metadata = p + sizeof(locator);
235257

236-
if (PHAR_GET_16(locator.comment_len) != size - (metadata - buf)) {
237-
if (error) {
238-
spprintf(error, 4096, "phar error: corrupt zip archive, zip file comment truncated in zip-based phar \"%s\"", fname);
239-
}
240-
php_stream_close(fp);
241-
pefree(mydata, mydata->is_persistent);
242-
return FAILURE;
258+
if (PHAR_GET_16(locator.comment_len) != size - (metadata - buf)) {
259+
if (error) {
260+
spprintf(error, 4096, "phar error: corrupt zip archive, zip file comment truncated in zip-based phar \"%s\"", fname);
243261
}
244-
245-
phar_parse_metadata_lazy(metadata, &mydata->metadata_tracker, PHAR_GET_16(locator.comment_len), mydata->is_persistent);
246-
} else {
247-
ZVAL_UNDEF(&mydata->metadata_tracker.val);
262+
php_stream_close(fp);
263+
pefree(mydata, mydata->is_persistent);
264+
return FAILURE;
248265
}
249266

250-
goto foundit;
267+
phar_parse_metadata_lazy(metadata, &mydata->metadata_tracker, PHAR_GET_16(locator.comment_len), mydata->is_persistent);
268+
} else {
269+
ZVAL_UNDEF(&mydata->metadata_tracker.val);
251270
}
271+
272+
goto foundit;
252273
}
253274

254275
php_stream_close(fp);

0 commit comments

Comments
 (0)