Req #71966 [Com]: PHP Phar issue with leading ./ in tar archives

From: Date: Wed, 16 Jan 2019 13:08:17 +0000
Subject: Req #71966 [Com]: PHP Phar issue with leading ./ in tar archives
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-218991@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=71966&edit=1 ID: 71966 Comment by: someone dot who dot want dot to dot be dot unknown at gmail dot com Reported by: pandrade at redhat dot com Summary: PHP Phar issue with leading ./ in tar archives Status: Open Type: Feature/Change Request Package: PHAR related Operating System: Linux PHP Version: Irrelevant Block user comment: N Private report: N New Comment: 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. Previous Comments: ------------------------------------------------------------------------ [2017-02-22 02:59:03] 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 ------------------------------------------------------------------------ [2016-04-05 13:13:20] 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. ------------------------------------------------------------------------ [2016-04-05 13:09:54] 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. ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=71966&edit=1

« previous php.bugs (#218991) next »