You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

163 lines
6.0 KiB

From bcb7ffdec8f941563df71ab890b7b6b76cae2120 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rapha=C3=ABl=20Hertzog?= <hertzog@debian.org>
Date: Fri, 23 Dec 2016 12:16:33 +0100
Subject: [PATCH] CVE-2016-2554
Fixed bug #71488: Stack overflow when decompressing tar archives
[hertzog@debian.org: backported to 5.4.45]
Bug: https://bugs.php.net/bug.php?id=71488
Origin: backport, https://git.php.net/?p=php-src.git;a=commitdiff;h=07c7df68bd68bbe706371fccc77c814ebb335d9e https://git.php.net/?p=php-src.git;a=commitdiff;h=f4264ebc6499b82f892cefb54c0e4a0e9642e1d9
---
ext/phar/tar.c | 21 ++++++++++++++++-----
ext/phar/tests/bug71488.phpt | 16 ++++++++++++++++
2 files changed, 32 insertions(+), 5 deletions(-)
create mode 100644 ext/phar/tests/bug71488.phpt
Index: php5-5.4.45/ext/phar/tar.c
===================================================================
--- php5-5.4.45.orig/ext/phar/tar.c 2017-01-24 17:17:12.000000000 +0000
+++ php5-5.4.45/ext/phar/tar.c 2017-01-24 17:20:45.649688314 +0000
@@ -192,6 +192,13 @@
}
/* }}} */
+#if !HAVE_STRNLEN
+static size_t strnlen(const char *s, size_t maxlen) {
+ char *r = (char *)memchr(s, '\0', maxlen);
+ return r ? r-s : maxlen;
+}
+#endif
+
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) /* {{{ */
{
char buf[512], *actual_alias = NULL, *p;
@@ -201,6 +208,7 @@
php_uint32 sum1, sum2, size, old;
phar_archive_data *myphar, **actual;
int last_was_longlink = 0;
+ int linkname_len;
if (error) {
*error = NULL;
@@ -255,7 +263,13 @@
size = entry.uncompressed_filesize = entry.compressed_filesize =
phar_tar_number(hdr->size, sizeof(hdr->size));
- 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)) {
+ /* skip global/file headers (pax) */
+ if (!old && (hdr->typeflag == TAR_GLOBAL_HDR || hdr->typeflag == TAR_FILE_HDR)) {
+ size = (size+511)&~511;
+ goto next;
+ }
+
+ 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)) {
off_t curloc;
if (size > 511) {
@@ -466,19 +480,22 @@
entry.link = NULL;
+ /* link field is null-terminated unless it has 100 non-null chars.
+ * Thus we can not use strlen. */
+ linkname_len = strnlen(hdr->linkname, 100);
if (entry.tar_type == TAR_LINK) {
- if (!zend_hash_exists(&myphar->manifest, hdr->linkname, strlen(hdr->linkname))) {
+ if (!zend_hash_exists(&myphar->manifest, hdr->linkname, linkname_len)) {
if (error) {
- spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file - hard link to non-existent file \"%s\"", fname, hdr->linkname);
+ spprintf(error, 4096, "phar error: \"%s\" is a corrupted tar file - hard link to non-existent file \"%.*s\"", fname, linkname_len, hdr->linkname);
}
pefree(entry.filename, entry.is_persistent);
php_stream_close(fp);
phar_destroy_phar_data(myphar TSRMLS_CC);
return FAILURE;
}
- entry.link = estrdup(hdr->linkname);
+ entry.link = estrndup(hdr->linkname, linkname_len);
} else if (entry.tar_type == TAR_SYMLINK) {
- entry.link = estrdup(hdr->linkname);
+ entry.link = estrndup(hdr->linkname, linkname_len);
}
phar_set_inode(&entry TSRMLS_CC);
zend_hash_add(&myphar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), (void **) &newentry);
@@ -548,6 +565,7 @@
size = (size+511)&~511;
if (((hdr->typeflag == '\0') || (hdr->typeflag == TAR_FILE)) && size > 0) {
+next:
/* this is not good enough - seek succeeds even on truncated tars */
php_stream_seek(fp, size, SEEK_CUR);
if ((uint)php_stream_tell(fp) > totalsize) {
Index: php5-5.4.45/ext/phar/tests/bug71488.phpt
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ php5-5.4.45/ext/phar/tests/bug71488.phpt 2017-01-24 17:17:12.000000000 +0000
@@ -0,0 +1,16 @@
+--TEST--
+Phar: bug #71488: Stack overflow when decompressing tar archives
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+$p = new PharData(__DIR__."/bug71488.tar");
+$newp = $p->decompress("test");
+?>
+DONE
+--CLEAN--
+<?php
+@unlink(__DIR__."/bug71488.test");
+?>
+--EXPECT--
+DONE
Index: php5-5.4.45/NEWS
===================================================================
--- php5-5.4.45.orig/NEWS 2015-09-01 20:09:37.000000000 +0000
+++ php5-5.4.45/NEWS 2017-01-24 17:19:49.408772817 +0000
@@ -102,6 +102,10 @@
. Fixed bug #68776 (mail() does not have mail header injection prevention for
additional headers). (Yasuo)
+- Phar:
+ . Fixed bug 64343 (PharData::extractTo fails for tarball created by BSD tar).
+ (Mike)
+
- Postgres:
. Fixed bug #69667 (segfault in php_pgsql_meta_data). (CVE-2015-4644) (Remi)
Index: php5-5.4.45/ext/phar/phar_internal.h
===================================================================
--- php5-5.4.45.orig/ext/phar/phar_internal.h 2015-09-01 20:09:37.000000000 +0000
+++ php5-5.4.45/ext/phar/phar_internal.h 2017-01-24 17:19:49.412772882 +0000
@@ -140,6 +140,8 @@
#define TAR_SYMLINK '2'
#define TAR_DIR '5'
#define TAR_NEW '8'
+#define TAR_GLOBAL_HDR 'g'
+#define TAR_FILE_HDR 'x'
#define PHAR_MUNG_PHP_SELF (1<<0)
#define PHAR_MUNG_REQUEST_URI (1<<1)
Index: php5-5.4.45/ext/phar/tests/tar/bug64343.phpt
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ php5-5.4.45/ext/phar/tests/tar/bug64343.phpt 2017-01-24 17:19:49.452773534 +0000
@@ -0,0 +1,16 @@
+--TEST--
+Bug #64343 (phar cannot open tars with pax headers)
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+
+echo "Test\n";
+
+$phar = new PharData(__DIR__."/files/bug64343.tar");
+
+?>
+===DONE===
+--EXPECT--
+Test
+===DONE===