Skip to content

Commit 07c7df6

Browse files
committed
Fixed bug #71488: Stack overflow when decompressing tar archives
1 parent a1c675e commit 07c7df6

File tree

3 files changed

+32
-6
lines changed

3 files changed

+32
-6
lines changed

ext/phar/tar.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,13 @@ static int phar_tar_process_metadata(phar_entry_info *entry, php_stream *fp TSRM
195195
}
196196
/* }}} */
197197

198+
#if !HAVE_STRNLEN
199+
static size_t strnlen(const char *s, size_t maxlen) {
200+
char *r = (char *)memchr(s, '\0', maxlen);
201+
return r ? r-s : maxlen;
202+
}
203+
#endif
204+
198205
int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias, int alias_len, phar_archive_data** pphar, int is_data, php_uint32 compression, char **error TSRMLS_DC) /* {{{ */
199206
{
200207
char buf[512], *actual_alias = NULL, *p;
@@ -204,6 +211,7 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
204211
php_uint32 sum1, sum2, size, old;
205212
phar_archive_data *myphar, **actual;
206213
int last_was_longlink = 0;
214+
int linkname_len;
207215

208216
if (error) {
209217
*error = NULL;
@@ -264,7 +272,7 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
264272
goto next;
265273
}
266274

267-
if (((!old && hdr->prefix[0] == 0) || old) && strlen(hdr->name) == sizeof(".phar/signature.bin")-1 && !strncmp(hdr->name, ".phar/signature.bin", sizeof(".phar/signature.bin")-1)) {
275+
if (((!old && hdr->prefix[0] == 0) || old) && strnlen(hdr->name, 100) == sizeof(".phar/signature.bin")-1 && !strncmp(hdr->name, ".phar/signature.bin", sizeof(".phar/signature.bin")-1)) {
268276
off_t curloc;
269277

270278
if (size > 511) {
@@ -474,20 +482,22 @@ int phar_parse_tarfile(php_stream* fp, char *fname, int fname_len, char *alias,
474482
}
475483

476484
entry.link = NULL;
477-
485+
/* link field is null-terminated unless it has 100 non-null chars.
486+
* Thus we can not use strlen. */
487+
linkname_len = strnlen(hdr->linkname, 100);
478488
if (entry.tar_type == TAR_LINK) {
479-
if (!zend_hash_exists(&myphar->manifest, hdr->linkname, strlen(hdr->linkname))) {
489+
if (!zend_hash_exists(&myphar->manifest, hdr->linkname, linkname_len)) {
480490
if (error) {
481-
spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file - hard link to non-existent file \"%s\"", fname, hdr->linkname);
491+
spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file - hard link to non-existent file \"%.*s\"", fname, linkname_len, hdr->linkname);
482492
}
483493
pefree(entry.filename, entry.is_persistent);
484494
php_stream_close(fp);
485495
phar_destroy_phar_data(myphar TSRMLS_CC);
486496
return FAILURE;
487497
}
488-
entry.link = estrdup(hdr->linkname);
498+
entry.link = estrndup(hdr->linkname, linkname_len);
489499
} else if (entry.tar_type == TAR_SYMLINK) {
490-
entry.link = estrdup(hdr->linkname);
500+
entry.link = estrndup(hdr->linkname, linkname_len);
491501
}
492502
phar_set_inode(&entry TSRMLS_CC);
493503
zend_hash_add(&myphar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), (void **) &newentry);

ext/phar/tests/bug71488.phpt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
Phar: bug #71488: Stack overflow when decompressing tar archives
3+
--SKIPIF--
4+
<?php if (!extension_loaded("phar")) die("skip"); ?>
5+
--FILE--
6+
<?php
7+
$p = new PharData(__DIR__."/bug71488.tar");
8+
$newp = $p->decompress("test");
9+
?>
10+
DONE
11+
--CLEAN--
12+
<?php
13+
@unlink(__DIR__."/bug71488.test");
14+
?>
15+
--EXPECT--
16+
DONE

ext/phar/tests/bug71488.tar

10 KB
Binary file not shown.

0 commit comments

Comments
 (0)