Skip to content

Commit 57eb399

Browse files
committed
Merge branch 'PHP-8.3' into PHP-8.4
* PHP-8.3: Fix GH-17137: Segmentation fault ext/phar/phar.c
2 parents fd25b79 + 142f85e commit 57eb399

File tree

4 files changed

+72
-22
lines changed

4 files changed

+72
-22
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ PHP NEWS
4040
. Fixed bug GH-17158 (pg_fetch_result Shows Incorrect ArgumentCountError
4141
Message when Called With 1 Argument). (nielsdos)
4242

43+
- Phar:
44+
. Fixed bug GH-17137 (Segmentation fault ext/phar/phar.c). (nielsdos)
45+
4346
- SimpleXML:
4447
. Fixed bug GH-17040 (SimpleXML's unset can break DOM objects). (nielsdos)
4548
. Fixed bug GH-17153 (SimpleXML crash when using autovivification on

ext/phar/phar.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,7 @@ zend_result phar_create_or_parse_filename(char *fname, size_t fname_len, char *a
15061506
}
15071507
}
15081508

1509+
ZEND_ASSERT(!mydata->is_persistent);
15091510
mydata->alias = alias ? estrndup(alias, alias_len) : estrndup(mydata->fname, fname_len);
15101511
mydata->alias_len = alias ? alias_len : fname_len;
15111512
}

ext/phar/phar_object.c

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2120,9 +2120,8 @@ static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext) /*
21202120
efree(newname);
21212121

21222122
if (PHAR_G(manifest_cached) && NULL != (pphar = zend_hash_str_find_ptr(&cached_phars, newpath, phar->fname_len))) {
2123-
efree(oldpath);
21242123
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Unable to add newly converted phar \"%s\" to the list of phars, new phar name is in phar.cache_list", phar->fname);
2125-
return NULL;
2124+
goto err_oldpath;
21262125
}
21272126

21282127
if (NULL != (pphar = zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), newpath, phar->fname_len))) {
@@ -2134,41 +2133,42 @@ static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext) /*
21342133
pphar->flags = phar->flags;
21352134
pphar->fp = phar->fp;
21362135
phar->fp = NULL;
2137-
/* FIX: GH-10755 Double-free issue caught by ASAN check */
2138-
pphar->alias = phar->alias; /* Transfer alias to pphar to */
2139-
phar->alias = NULL; /* avoid being free'd twice */
2136+
/* The alias is not owned by the phar, so set it to NULL to avoid freeing it. */
2137+
phar->alias = NULL;
21402138
phar_destroy_phar_data(phar);
21412139
*sphar = NULL;
21422140
phar = pphar;
2141+
/* NOTE: this phar is now reused, so the refcount must be increased. */
2142+
phar->refcount++;
21432143
newpath = oldpath;
21442144
goto its_ok;
21452145
}
21462146
}
21472147

2148-
efree(oldpath);
21492148
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Unable to add newly converted phar \"%s\" to the list of phars, a phar with that name already exists", phar->fname);
2150-
return NULL;
2149+
goto err_oldpath;
21512150
}
21522151
its_ok:
21532152
if (SUCCESS == php_stream_stat_path(newpath, &ssb)) {
21542153
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "phar \"%s\" exists and must be unlinked prior to conversion", newpath);
2155-
efree(oldpath);
2156-
return NULL;
2154+
goto err_reused_oldpath;
21572155
}
21582156
if (!phar->is_data) {
21592157
if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &(phar->ext), &ext_len, 1, 1, 1)) {
2160-
efree(oldpath);
21612158
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "phar \"%s\" has invalid extension %s", phar->fname, ext);
2162-
return NULL;
2159+
goto err_reused_oldpath;
21632160
}
21642161
phar->ext_len = ext_len;
21652162

2166-
if (phar->alias) {
2163+
/* If we are reusing a phar, then the aliases should be already set up correctly,
2164+
* and so we should not clear out the alias information.
2165+
* This would also leak memory because, unlike the non-reuse path, we actually own the alias memory. */
2166+
if (phar->alias && phar != pphar) {
21672167
if (phar->is_temporary_alias) {
21682168
phar->alias = NULL;
21692169
phar->alias_len = 0;
21702170
} else {
2171-
phar->alias = estrndup(newpath, strlen(newpath));
2171+
phar->alias = pestrndup(newpath, strlen(newpath), phar->is_persistent);
21722172
phar->alias_len = strlen(newpath);
21732173
phar->is_temporary_alias = 1;
21742174
zend_hash_str_update_ptr(&(PHAR_G(phar_alias_map)), newpath, phar->fname_len, phar);
@@ -2178,20 +2178,21 @@ static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext) /*
21782178
} else {
21792179

21802180
if (SUCCESS != phar_detect_phar_fname_ext(newpath, phar->fname_len, (const char **) &(phar->ext), &ext_len, 0, 1, 1)) {
2181-
efree(oldpath);
21822181
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "data phar \"%s\" has invalid extension %s", phar->fname, ext);
2183-
return NULL;
2182+
goto err_reused_oldpath;
21842183
}
21852184
phar->ext_len = ext_len;
21862185

2187-
phar->alias = NULL;
2188-
phar->alias_len = 0;
2186+
/* See comment in other branch. */
2187+
if (phar != pphar) {
2188+
phar->alias = NULL;
2189+
phar->alias_len = 0;
2190+
}
21892191
}
21902192

21912193
if ((!pphar || phar == pphar) && NULL == zend_hash_str_update_ptr(&(PHAR_G(phar_fname_map)), newpath, phar->fname_len, phar)) {
2192-
efree(oldpath);
21932194
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Unable to add newly converted phar \"%s\" to the list of phars", phar->fname);
2194-
return NULL;
2195+
goto err_oldpath;
21952196
}
21962197

21972198
phar_flush_ex(phar, NULL, 1, &error);
@@ -2201,8 +2202,7 @@ static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext) /*
22012202
*sphar = NULL;
22022203
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "%s", error);
22032204
efree(error);
2204-
efree(oldpath);
2205-
return NULL;
2205+
goto err_oldpath;
22062206
}
22072207

22082208
efree(oldpath);
@@ -2225,6 +2225,16 @@ static zend_object *phar_rename_archive(phar_archive_data **sphar, char *ext) /*
22252225
zend_call_known_instance_method_with_1_params(ce->constructor, Z_OBJ(ret), NULL, &arg1);
22262226
zval_ptr_dtor(&arg1);
22272227
return Z_OBJ(ret);
2228+
2229+
err_reused_oldpath:
2230+
if (pphar == phar) {
2231+
/* NOTE: we know it's not the last reference because the phar is reused. */
2232+
phar->refcount--;
2233+
}
2234+
/* fallthrough */
2235+
err_oldpath:
2236+
efree(oldpath);
2237+
return NULL;
22282238
}
22292239
/* }}} */
22302240

@@ -2754,8 +2764,13 @@ PHP_METHOD(Phar, setAlias)
27542764
oldalias_len = phar_obj->archive->alias_len;
27552765
old_temp = phar_obj->archive->is_temporary_alias;
27562766

2757-
phar_obj->archive->alias = estrndup(ZSTR_VAL(new_alias), ZSTR_LEN(new_alias));
27582767
phar_obj->archive->alias_len = ZSTR_LEN(new_alias);
2768+
if (phar_obj->archive->alias_len) {
2769+
phar_obj->archive->alias = pestrndup(ZSTR_VAL(new_alias), ZSTR_LEN(new_alias), phar_obj->archive->is_persistent);
2770+
} else {
2771+
phar_obj->archive->alias = NULL;
2772+
}
2773+
27592774
phar_obj->archive->is_temporary_alias = 0;
27602775
phar_flush(phar_obj->archive, &error);
27612776

ext/phar/tests/gh17137.phpt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
--TEST--
2+
GH-17137 (Segmentation fault ext/phar/phar.c)
3+
--EXTENSIONS--
4+
phar
5+
--INI--
6+
phar.readonly=0
7+
--FILE--
8+
<?php
9+
$file = __DIR__ . DIRECTORY_SEPARATOR . 'gh17137.phar';
10+
$phar = new Phar($file);
11+
var_dump($phar, $phar->decompress());
12+
echo "OK\n";
13+
?>
14+
--EXPECTF--
15+
object(Phar)#%d (3) {
16+
["pathName":"SplFileInfo":private]=>
17+
string(0) ""
18+
["glob":"DirectoryIterator":private]=>
19+
bool(false)
20+
["subPathName":"RecursiveDirectoryIterator":private]=>
21+
string(0) ""
22+
}
23+
object(Phar)#%d (3) {
24+
["pathName":"SplFileInfo":private]=>
25+
string(0) ""
26+
["glob":"DirectoryIterator":private]=>
27+
bool(false)
28+
["subPathName":"RecursiveDirectoryIterator":private]=>
29+
string(0) ""
30+
}
31+
OK

0 commit comments

Comments
 (0)