php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #78066 PHP eats the first byte of a program that comes from process substitution
Submitted: 2019-05-25 16:52 UTC Modified: 2019-07-15 14:30 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: octalbugsphp at alvarezp dot org Assigned: nikic (profile)
Status: Closed Package: *General Issues
PHP Version: 7.3.5 OS: Linux
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If this is not your bug, you can add a comment by following this link.
If this is your bug, but you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: octalbugsphp at alvarezp dot org
New email:
PHP Version: OS:

 

 [2019-05-25 16:52 UTC] octalbugsphp at alvarezp dot org
Description:
------------
PHP eats the first byte of a program that comes from process substitution

After discussion in ##php at Freenode this was found (see the third line, lseek)

$ strace php -f <(echo -- '<?php print("hello\n"); ?>') 2>&1 | grep -A 5 'openat.*/dev/fd/63'
openat(AT_FDCWD, "/dev/fd/63", O_RDONLY) = 3
fstat(3, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
read(3, "-- <?php print(\"hello\\n\"); ?>\n", 4096) = 30
lseek(3, 0, SEEK_SET)                   = -1 ESPIPE (Illegal seek)
lstat("/dev/fd/63", {st_mode=S_IFLNK|0500, st_size=64, ...}) = 0
readlink("/dev/fd/63", "pipe:[6195898]", 4096) = 14


Test script:
---------------
[  0][Sat May 25 11:05:07 -0500 -- alvarezp@alvarezp-samsung:~]
$ php -f <(echo '<?php print("hello\n"); ?>')
?php print("hello\n"); ?>

[  0][Sat May 25 11:05:11 -0500 -- alvarezp@alvarezp-samsung:~]
$ php -f <(echo ' <?php print("hello\n"); ?>')
hello

[  0][Sat May 25 11:05:19 -0500 -- alvarezp@alvarezp-samsung:~]
$ php -f <(echo -- '<?php print("hello\n"); ?>')
- hello

Expected result:
----------------
The script should run as expected. The first byte should prevail as part of the script.

Actual result:
--------------
The first byte is eaten and not interpreted at all.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-05-25 16:53 UTC] simon at ikanobori dot jp
Being part of that discussion, it is important to note that process substitution returns the path to an anonymous pipe which stops existing after the process finishes.
 [2019-05-25 20:03 UTC] xatenev@php.net
Hi,

I was able to reproduce the problem with a small test C snippet that mimics what php-src is doing:

-------------------------------------

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]) {
    FILE *fp;

    fp = fopen(argv[1], "rb");
    char a = fgetc(fp);
    rewind(fp);
    char ch;
    while(1) {
        ch = fgetc(fp);
        if(feof(fp)) {
            break;
        }
        printf("%c", ch);
    }

    return 0;
}

-------------------------------------

`rewind()` fills `errno` with the value `29` which means `Illegal seek`.


The lines

char a = fgetc(fp);
rewind(fp);

mimic what php-src is doing here on line 606 and 620:

https://github.com/php/php-src/blob/e6f86fb17cd3a2dfe94ca1a0113a23194cb1915a/sapi/cli/php_cli.c#L606-L620

It calls fgetc() to find out if shebang exists on the file pointer but rewind() doesn't work correctly.
 [2019-05-25 20:07 UTC] xatenev@php.net
... Call the above snippet as specified in the bug report:

gcc test.c

./a.out <(echo '<?php print("hello"); ?>')

-----------------------------

Output:

?php print("hello"); ?>
 [2019-05-25 20:23 UTC] xatenev@php.net
As pipes are simply not seekable a possible fix could be implemented by checking errno for ESPIPE as described here http://man7.org/linux/man-pages/man3/errno.3.html and either let it fail or do some /tmp redirect magic.
 [2019-05-25 20:31 UTC] nikic@php.net
We should probably move handling of shebang lines into the lexer.
 [2019-05-25 20:40 UTC] octalbugsphp at alvarezp dot org
It should break all instances where the script file is a fifo.

Blame shows commit 71ea95354b [1]:

    MFH: Corrected fix for bug #46844 to only trigger on the 1st line of CLI

    opened files.

Which in turn references bug #46844:

    First line of included files not output if they begin with #


[1] https://github.com/php/php-src/commit/71ea95354b4133f12dcf8207bc7b36e1562bdd65

[2] https://bugs.php.net/bug.php?id=46844
 [2019-07-15 14:30 UTC] nikic@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: nikic
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Apr 16 07:01:29 2024 UTC