Skip to content

Commit c3e8485

Browse files
author
Greg Beaver
committed
fix bug #45792: bz2 compressed files in zip failure
1 parent 5006647 commit c3e8485

File tree

9 files changed

+123
-7
lines changed

9 files changed

+123
-7
lines changed

ext/phar/phar.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2383,7 +2383,7 @@ int phar_open_executed_filename(char *alias, int alias_len, char **error TSRMLS_
23832383
/**
23842384
* Validate the CRC32 of a file opened from within the phar
23852385
*/
2386-
int phar_postprocess_file(php_stream_wrapper *wrapper, int options, phar_entry_data *idata, php_uint32 crc32, char **error TSRMLS_DC) /* {{{ */
2386+
int phar_postprocess_file(phar_entry_data *idata, php_uint32 crc32, char **error, int process_zip TSRMLS_DC) /* {{{ */
23872387
{
23882388
php_uint32 crc = ~0;
23892389
int len = idata->internal_file->uncompressed_filesize;
@@ -2394,7 +2394,7 @@ int phar_postprocess_file(php_stream_wrapper *wrapper, int options, phar_entry_d
23942394
*error = NULL;
23952395
}
23962396

2397-
if (entry->is_zip) {
2397+
if (entry->is_zip && process_zip > 0) {
23982398
/* verify local file header */
23992399
phar_zip_file_header local;
24002400

@@ -2424,6 +2424,7 @@ int phar_postprocess_file(php_stream_wrapper *wrapper, int options, phar_entry_d
24242424
idata->zero = entry->offset_abs;
24252425
}
24262426
}
2427+
if (process_zip == 1) return SUCCESS;
24272428

24282429
php_stream_seek(fp, idata->zero, SEEK_SET);
24292430

@@ -2437,7 +2438,7 @@ int phar_postprocess_file(php_stream_wrapper *wrapper, int options, phar_entry_d
24372438
entry->is_crc_checked = 1;
24382439
return SUCCESS;
24392440
} else {
2440-
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "phar error: internal corruption of phar \"%s\" (crc32 mismatch on file \"%s\")", idata->phar->fname, entry->filename);
2441+
spprintf(error, 0, "phar error: internal corruption of phar \"%s\" (crc32 mismatch on file \"%s\")", idata->phar->fname, entry->filename);
24412442
return FAILURE;
24422443
}
24432444
}

ext/phar/phar.phar

-48.2 KB
Binary file not shown.

ext/phar/phar_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,7 @@ void phar_object_init(TSRMLS_D);
576576
void phar_destroy_phar_data(phar_archive_data *phar TSRMLS_DC);
577577

578578
int phar_open_entry_file(phar_archive_data *phar, phar_entry_info *entry, char **error TSRMLS_DC);
579+
int phar_postprocess_file(phar_entry_data *idata, php_uint32 crc32, char **error, int process_zip TSRMLS_DC);
579580
int phar_open_from_filename(char *fname, int fname_len, char *alias, int alias_len, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
580581
int phar_open_or_create_filename(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC);
581582
int phar_create_or_parse_filename(char *fname, int fname_len, char *alias, int alias_len, int is_data, int options, phar_archive_data** pphar, char **error TSRMLS_DC);

ext/phar/stream.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,9 @@ static php_stream * phar_wrapper_open_url(php_stream_wrapper *wrapper, char *pat
307307
#endif
308308

309309
/* check length, crc32 */
310-
if (!idata->internal_file->is_crc_checked && phar_postprocess_file(wrapper, options, idata, idata->internal_file->crc32, &error TSRMLS_CC) != SUCCESS) {
311-
/* already issued the error */
310+
if (!idata->internal_file->is_crc_checked && phar_postprocess_file(idata, idata->internal_file->crc32, &error, 2 TSRMLS_CC) != SUCCESS) {
311+
php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, error);
312+
efree(error);
312313
phar_entry_delref(idata TSRMLS_CC);
313314
efree(internal_file);
314315
return NULL;

ext/phar/stream.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
/* $Id$ */
2121

2222
BEGIN_EXTERN_C()
23-
int phar_postprocess_file(php_stream_wrapper *wrapper, int options, phar_entry_data *idata, php_uint32 crc32, char **error TSRMLS_DC);
2423

2524
php_url* phar_parse_url(php_stream_wrapper *wrapper, char *filename, char *mode, int options TSRMLS_DC);
2625
void phar_entry_remove(phar_entry_data *idata, char **error TSRMLS_DC);

ext/phar/tests/zip/bzip2.phpt

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
--TEST--
2+
Phar: process bzip2-compressed zip entry
3+
--SKIPIF--
4+
<?php if (!extension_loaded("phar")) die("skip"); ?>
5+
<?php if (!extension_loaded("spl")) die("skip SPL not available"); ?>
6+
<?php if (!extension_loaded("bz2")) die("skip bz2 not available"); ?>
7+
--FILE--
8+
<?php
9+
try {
10+
$a = new PharData(dirname(__FILE__) . '/files/bzip2.zip');
11+
foreach ($a as $entry => $file) {
12+
echo $file->getContent();
13+
}
14+
} catch (Exception $e) {
15+
echo $e->getMessage() . "\n";
16+
}
17+
?>
18+
===DONE===
19+
--EXPECT--
20+
<?php
21+
include dirname(__FILE__) . '/corrupt_zipmaker.php.inc';
22+
$a = new corrupt_zipmaker;
23+
$a->addFile('hi', null, 'hii');
24+
$a->addFile('hi2', null, 'hii2', null, null, 'encrypt', 'encrypt');
25+
$a->writeZip(dirname(__FILE__) . '/encrypted.zip');
26+
$a = new corrupt_zipmaker;
27+
$a->addFile('hi', null, 'hii');
28+
$a->addFile('', null, 'stdin');
29+
$a->writeZip(dirname(__FILE__) . '/stdin.zip');
30+
$a = new corrupt_zipmaker;
31+
$a->addFile('hii', null, 'hii', null, null, 'filename_len', 'filename_len');
32+
$a->addFile('hi', null, 'hii');
33+
$a->writeZip(dirname(__FILE__) . '/truncfilename.zip');
34+
$a = new corrupt_zipmaker;
35+
$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress');
36+
$a->writeZip(dirname(__FILE__) . '/compress_unsup1.zip');
37+
$a = new corrupt_zipmaker;
38+
$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 2);
39+
$a->writeZip(dirname(__FILE__) . '/compress_unsup2.zip');
40+
$a = new corrupt_zipmaker;
41+
$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 3);
42+
$a->writeZip(dirname(__FILE__) . '/compress_unsup3.zip');
43+
$a = new corrupt_zipmaker;
44+
$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 4);
45+
$a->writeZip(dirname(__FILE__) . '/compress_unsup4.zip');
46+
$a = new corrupt_zipmaker;
47+
$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 5);
48+
$a->writeZip(dirname(__FILE__) . '/compress_unsup5.zip');
49+
$a = new corrupt_zipmaker;
50+
$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 6);
51+
$a->writeZip(dirname(__FILE__) . '/compress_unsup6.zip');
52+
$a = new corrupt_zipmaker;
53+
$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 7);
54+
$a->writeZip(dirname(__FILE__) . '/compress_unsup7.zip');
55+
$a = new corrupt_zipmaker;
56+
$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 9);
57+
$a->writeZip(dirname(__FILE__) . '/compress_unsup9.zip');
58+
$a = new corrupt_zipmaker;
59+
$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 10);
60+
$a->writeZip(dirname(__FILE__) . '/compress_unsup10.zip');
61+
$a = new corrupt_zipmaker;
62+
$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 14);
63+
$a->writeZip(dirname(__FILE__) . '/compress_unsup14.zip');
64+
$a = new corrupt_zipmaker;
65+
$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 18);
66+
$a->writeZip(dirname(__FILE__) . '/compress_unsup18.zip');
67+
$a = new corrupt_zipmaker;
68+
$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 19);
69+
$a->writeZip(dirname(__FILE__) . '/compress_unsup19.zip');
70+
$a = new corrupt_zipmaker;
71+
$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 97);
72+
$a->writeZip(dirname(__FILE__) . '/compress_unsup97.zip');
73+
$a = new corrupt_zipmaker;
74+
$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 98);
75+
$a->writeZip(dirname(__FILE__) . '/compress_unsup98.zip');
76+
$a = new corrupt_zipmaker;
77+
$a->addFile('hi', null, 'hii', null, null, 'compress', 'compress', 11);
78+
$a->writeZip(dirname(__FILE__) . '/compress_unsupunknown.zip');
79+
?>
80+
===DONE===

ext/phar/tests/zip/files/bzip2.zip

603 Bytes
Binary file not shown.

ext/phar/util.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,7 @@ int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TS
913913
char *filtername;
914914
off_t loc;
915915
php_stream *ufp;
916+
phar_entry_data dummy;
916917

917918
if (follow_links && entry->link) {
918919
phar_entry_info *link_entry = phar_get_link_source(entry TSRMLS_CC);
@@ -921,6 +922,10 @@ int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TS
921922
}
922923
}
923924

925+
if (entry->is_modified) {
926+
return SUCCESS;
927+
}
928+
924929
if (entry->fp_type == PHAR_TMP) {
925930
if (!entry->fp) {
926931
entry->fp = php_stream_open_wrapper(entry->tmp, "rb", STREAM_MUST_SEEK|0, NULL);
@@ -941,6 +946,13 @@ int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TS
941946
}
942947

943948
if ((entry->old_flags && !(entry->old_flags & PHAR_ENT_COMPRESSION_MASK)) || !(entry->flags & PHAR_ENT_COMPRESSION_MASK)) {
949+
dummy.internal_file = entry;
950+
dummy.phar = phar;
951+
dummy.zero = entry->offset;
952+
dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
953+
if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
954+
return FAILURE;
955+
}
944956
return SUCCESS;
945957
}
946958

@@ -952,6 +964,14 @@ int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TS
952964
}
953965
}
954966

967+
dummy.internal_file = entry;
968+
dummy.phar = phar;
969+
dummy.zero = entry->offset;
970+
dummy.fp = phar_get_pharfp(phar TSRMLS_CC);
971+
if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 1 TSRMLS_CC)) {
972+
return FAILURE;
973+
}
974+
955975
ufp = phar_get_entrypufp(entry TSRMLS_CC);
956976

957977
if ((filtername = phar_decompress_filter(entry, 0)) != NULL) {
@@ -991,6 +1011,11 @@ int phar_open_entry_fp(phar_entry_info *entry, char **error, int follow_links TS
9911011

9921012
/* this is now the new location of the file contents within this fp */
9931013
phar_set_fp_type(entry, PHAR_UFP, loc TSRMLS_CC);
1014+
dummy.zero = entry->offset;
1015+
dummy.fp = ufp;
1016+
if (FAILURE == phar_postprocess_file(&dummy, entry->crc32, error, 0 TSRMLS_CC)) {
1017+
return FAILURE;
1018+
}
9941019
return SUCCESS;
9951020
}
9961021
/* }}} */

ext/phar/zip.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,7 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
655655
struct _phar_zip_pass *p;
656656
php_uint32 newcrc32;
657657
off_t offset;
658+
int not_really_modified = 0;
658659

659660
entry = (phar_entry_info *)data;
660661
p = (struct _phar_zip_pass*) arg;
@@ -723,6 +724,12 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
723724
return ZEND_HASH_APPLY_STOP;
724725
}
725726

727+
/* we can be modified and already be compressed, such as when chmod() is executed */
728+
if (entry->flags & PHAR_ENT_COMPRESSION_MASK && (entry->old_flags == entry->flags || !entry->old_flags)) {
729+
not_really_modified = 1;
730+
goto is_compressed;
731+
}
732+
726733
if (-1 == phar_seek_efp(entry, 0, SEEK_SET, 0, 0 TSRMLS_CC)) {
727734
spprintf(p->error, 0, "unable to seek to start of file \"%s\" to zip-based phar \"%s\"", entry->filename, entry->phar->fname);
728735
return ZEND_HASH_APPLY_STOP;
@@ -791,6 +798,7 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
791798
entry->old_flags = entry->flags;
792799
entry->is_modified = 1;
793800
} else {
801+
is_compressed:
794802
central.uncompsize = local.uncompsize = PHAR_SET_32(entry->uncompressed_filesize);
795803
central.compsize = local.compsize = PHAR_SET_32(entry->compressed_filesize);
796804

@@ -872,7 +880,7 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
872880
return ZEND_HASH_APPLY_STOP;
873881
}
874882

875-
if (entry->is_modified) {
883+
if (!not_really_modified && entry->is_modified) {
876884
if (entry->cfp) {
877885
if (entry->compressed_filesize != php_stream_copy_to_stream(entry->cfp, p->filefp, entry->compressed_filesize)) {
878886
spprintf(p->error, 0, "unable to write compressed contents of file \"%s\" in zip-based phar \"%s\"", entry->filename, entry->phar->fname);
@@ -900,6 +908,7 @@ static int phar_zip_changed_apply(void *data, void *arg TSRMLS_DC) /* {{{ */
900908

901909
entry->is_modified = 0;
902910
} else {
911+
entry->is_modified = 0;
903912
if (entry->fp_refcount) {
904913
/* open file pointers refer to this fp, do not free the stream */
905914
switch (entry->fp_type) {

0 commit comments

Comments
 (0)