php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #71966 PHP Phar issue with leading ./ in tar archives
Submitted: 2016-04-05 13:09 UTC Modified: -
Votes:3
Avg. Score:3.7 ± 0.9
Reproduced:2 of 2 (100.0%)
Same Version:0 (0.0%)
Same OS:1 (50.0%)
From: pandrade at redhat dot com Assigned:
Status: Open Package: PHAR related
PHP Version: Irrelevant OS: Linux
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2016-04-05 13:09 UTC] pandrade at redhat dot com
Description:
------------
To test the below script, run first:

$ touch file1 file2 file3
$ tar zcf dotslash.tar.gz ./file1 ./file2 ./file3
$ tar zcf nodotslash.tar.gz file1 file2 file3

I made an initial experiment, that "almost" works,
will work for "./file" but fail for "./dir/file".

---8<---
diff -up php-5.4.16/ext/phar/tar.c.orig php-5.4.16/ext/phar/tar.c
--- php-5.4.16/ext/phar/tar.c.orig	2016-03-29 11:39:57.020599910 -0300
+++ php-5.4.16/ext/phar/tar.c	2016-03-29 11:42:25.582624697 -0300
@@ -481,6 +481,9 @@ bail:
 			entry.link = estrdup(hdr->linkname);
 		}
 		phar_set_inode(&entry TSRMLS_CC);
+		if (entry.filename_len > 2 && entry.filename[0] == '.' && entry.filename[1] == '/')
+			/* Also copy trailing nul */
+			memmove(entry.filename, entry.filename + 2, (entry.filename_len -= 2) + 1);
 		zend_hash_add(&myphar->manifest, entry.filename, entry.filename_len, (void*)&entry, sizeof(phar_entry_info), (void **) &newentry);
 
 		if (entry.is_persistent) {
---8<---

If erroring out on "." or ".." on tar pathnames is the
expected result, please let me know.


Test script:
---------------
#!/usr/bin/php
<?php
echo "\nRunning for the broken file\n";
$path = realpath('./dotslash.tar.gz');
$pharpath = "phar://" . $path;
$phardata = new PharData($path);
$phariter = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($pharpath));

echo "The phar has " . $phardata->count() . " entries\n";
$i = 0;
foreach($phariter as $file){
    echo $file . "\n";
    $i++;
}
echo "There were $i entries listed.\n";


echo "\nNow running for the working file\n";
$path = realpath('./nodotslash.tar.gz');
$pharpath = "phar://" . $path;
$phardata = new PharData($path);
$phariter = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($pharpath));

echo "The phar has " . $phardata->count() . " entries\n";
$i = 0;
foreach($phariter as $file){
    echo $file . "\n";
    $i++;
}
echo "There were $i entries listed.\n";

?>

Expected result:
----------------
$ ./pharbug.php 

Running for the broken file
The phar has 3 entries
phar:///home/testuser/dotslash.tar.gz/file1
phar:///home/testuser/dotslash.tar.gz/file2
phar:///home/testuser/dotslash.tar.gz/file3
There were 3 entries listed.

Now running for the working file
The phar has 3 entries
phar:///home/testuser/nodotslash.tar.gz/file1
phar:///home/testuser/nodotslash.tar.gz/file2
phar:///home/testuser/nodotslash.tar.gz/file3
There were 3 entries listed.


Actual result:
--------------
$ ./pharbug.php 

Running for the broken file
The phar has 3 entries
phar:///home/testuser/dotslash.tar.gz/.
There were 1 entries listed.

Now running for the working file
The phar has 3 entries
phar:///home/testuser/nodotslash.tar.gz/file1
phar:///home/testuser/nodotslash.tar.gz/file2
phar:///home/testuser/nodotslash.tar.gz/file3
There were 3 entries listed.


Patches

php-dotslash.patch (last revision 2016-04-05 13:10 UTC by pandrade at redhat dot com)

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-04-05 13:13 UTC] pandrade at redhat dot com
Note that the attached patch is not fully functional,
It works for the described problem: "./file", but
fails for "./dir/file".
I added it to manage to get the bug reported.
 [2017-02-22 02:59 UTC] mike at mbaynton dot com
In addition to iteration of the archive contents not occurring, accessing files with through the offsetGet() array-index interface is also broken, and certain flags to the PharData constructor result in attempts to iterate the contents failing with a RuntimeException.

Here's a fully self-sustaining bash script (nothing to manually run first) that shows all the issues I've found when the archive's files lead with ./:
http://pastebin.com/Neu0cWTx
 [2019-01-16 13:08 UTC] someone dot who dot want dot to dot be dot unknown at gmail dot com
I'm experiencing this problem too (linux, php 7.2.10, but this is not relevant really).

How to reproduce:
1. Create archive with paths starting with "./": 
> $ tar -cvf myfile.tar .
2. Check that files paths start with "./":
> $ tar -tvf myfile.tar
3. Try to iterate over archive:

> $this->tar = new PharData('myfile.tar', FilesystemIterator::UNIX_PATHS);
> foreach (new RecursiveIteratorIterator($this->tar) as $i => $file) {
>     // ...
> }

Got an exception:
PHP Fatal error:  Uncaught RuntimeException: Cannot access phar file entry '/' in archive '...' in ...
Stack trace:
#0 [internal function]: PharFileInfo->__construct('phar:///home/wa...')
#1 ...(...): FilesystemIterator->current()

---
This problem is really annoying, making impossible work with these types of achives.
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Fri Aug 23 21:01:28 2019 UTC