Skip to content

Commit 614afe7

Browse files
committed
ext/zip: php_zip_ops_stat() succeeds when the archive cannot be opened.
When zip_open() failed the whole stat block was skipped, yet the function still returned 0. fstat() on a zip:// stream therefore succeeded with the zeroed statbuf it was given, reporting a zero size and no file type bits, instead of failing. Return -1 on that path. Close GH-23511
1 parent 473a7e0 commit 614afe7

3 files changed

Lines changed: 43 additions & 0 deletions

File tree

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ PHP NEWS
8282
on corrupted entries. (David Carlier)
8383
. Fixed ZipArchive::getNameIndex() truncating the entry index to int.
8484
(David Carlier)
85+
. Fixed fstat() on a zip:// stream reporting success when the archive cannot
86+
be opened. (David Carlier)
8587

8688
- SAPI:
8789
. Fixed fuzzer targets failing to build in isolation. (Mrmaxmeier)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
fstat() on a zip:// stream whose archive can no longer be opened
3+
--EXTENSIONS--
4+
zip
5+
--SKIPIF--
6+
<?php
7+
if (PHP_OS_FAMILY === 'Windows') die('skip the archive cannot be rewritten while it is open');
8+
?>
9+
--FILE--
10+
<?php
11+
$file = __DIR__ . '/stream_fstat_unreadable_archive.zip';
12+
13+
@unlink($file);
14+
15+
$zip = new ZipArchive;
16+
if (!$zip->open($file, ZipArchive::CREATE)) {
17+
exit('failed');
18+
}
19+
20+
$zip->addFromString('entry.txt', 'entry');
21+
$zip->close();
22+
23+
$fp = fopen('zip://' . $file . '#entry.txt', 'rb');
24+
var_dump($fp !== false);
25+
26+
file_put_contents($file, 'this is not a zip archive');
27+
28+
var_dump(fstat($fp));
29+
30+
fclose($fp);
31+
?>
32+
--EXPECT--
33+
bool(true)
34+
bool(false)
35+
--CLEAN--
36+
<?php
37+
unlink(__DIR__ . '/stream_fstat_unreadable_archive.zip');
38+
?>

ext/zip/zip_stream.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,9 @@ static int php_zip_ops_stat(php_stream *stream, php_stream_statbuf *ssb) /* {{{
195195
ssb->sb.st_blocks = -1;
196196
#endif
197197
ssb->sb.st_ino = -1;
198+
} else {
199+
zend_string_release_ex(file_basename, 0);
200+
return -1;
198201
}
199202
zend_string_release_ex(file_basename, 0);
200203
return 0;

0 commit comments

Comments
 (0)