Req->Bug #71966 [Opn->Ver]: PHP Phar issue with leading ./ in tar archives

From: Date: Fri, 29 Jan 2021 15:51:55 +0000
Subject: Req->Bug #71966 [Opn->Ver]: PHP Phar issue with leading ./ in tar archives
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-231830@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 Updated by: cmb@php.net Reported by: pandrade at redhat dot com Summary: PHP Phar issue with leading ./ in tar archives -Status: Open +Status: Verified -Type: Feature/Change Request +Type: Bug Package: PHAR related Operating System: Linux PHP Version: Irrelevant Block user comment: N Private report: N New Comment: Indeed, the handling of the current (.) and parent (..) directory is very inconsistent in Phar. The basic problem is that the dotslash.tar entries are stored in the manifest as is (i.e. as ./file1 etc.), but the lookup normalizes the paths (i.e. to file1 etc.), so the entries cannot be found. A solution as suggested would solve the problem, but would yield exactly the same structure for dotslash.tar as for nodotslash.tar, although popular tools such as GNU tar and 7-zip would show a different representation. The same applies for ext/zip which basically makes the same distinction. And further fixes would be required to the Phar routines which allow to add entries to the tarball. The alternative solution, namely to not normalize the path on lookup would yield yet other strange results wrt. phar wrapper URLs. Only slightly related, but still interesting in this context, is that the dotslash.tar could have been created by Phar, but trying to add a entry like dir/./file would be rejected with the error message 'invalid path "dir/./local" contains current directory reference'. Previous Comments: ------------------------------------------------------------------------ [2019-01-16 13:08:17] 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. ------------------------------------------------------------------------ [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 (#231830) next »