php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #78231 Segmentation fault upon stream_socket_accept of exported socket-to-stream
Submitted: 2019-06-29 06:05 UTC Modified: 2019-07-03 10:38 UTC
From: asmqb7 at gmail dot com Assigned: nikic (profile)
Status: Closed Package: Sockets related
PHP Version: 7.2.20, 7.3.6 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 you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: asmqb7 at gmail dot com
New email:
PHP Version: OS:

 

 [2019-06-29 06:05 UTC] asmqb7 at gmail dot com
Description:
------------
Due to lack of documentation about the fact that SO_REUSEADDR is unconditionally set when stream_socket_server() is used, I thought I would need to use the socket_* functions to set the option on a stream I'd already created.

I figured I could then export the newly-bound socket to a stream, and proceed from there without needing to use any other socket_* functions, which I try to avoid using as I've been bitten by the sockets extension in the past (other bugs etc).

Well, I'm not quite sure what I broke this time, but the attached test script segfaults on my system with 100% consistency. I suspect the code path that handles "stream bound by the sockets library, exported, then selected on by the streams subsystem" is probably un[der?]implemented.

It's not visible yet, but I added some info to the notes section at http://php.net/socket_set_option, which is what shows up most prominently when googling SO_REUSEADDR in the context of PHP.

Test script:
---------------
<?php
$port = 55555;

$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
print '$socket: '; var_dump($socket);

print 'socket_bind(): ';
var_dump(socket_bind($socket, '127.0.0.1', $port));

$listening_fd = socket_export_stream($socket);
print 'socket_export_stream(): ';
var_dump($listening_fd);

for (;;) {
  $read = $write = $except = [];
  $read[] = $listening_fd;
  
  stream_select($read, $write, $except, null);
  
  foreach ($read as $fd) {
    switch ($fd) {
      case $listening_fd:
        print "stream_socket_accept() on: "; var_dump($fd);
        $new_fd = stream_socket_accept($fd);
    }
  }
}


Expected result:
----------------
For a stream exported from a socket to behave identically to a stream created by the streams functionality, and particularly for untested codepaths to not cause runtime segfaults.

Actual result:
--------------
$socket: resource(4) of type (Socket)
socket_bind(): bool(true)
socket_export_stream(): resource(5) of type (stream)
stream_socket_accept() on: resource(5) of type (stream)

Program received signal SIGSEGV, Segmentation fault.
0x00005555558ce3b6 in php_stream_context_get_option ()
(gdb) bt
#0  0x00005555558ce3b6 in php_stream_context_get_option ()
#1  0x00005555556df1bc in ?? ()
#2  0x00005555558cc72d in _php_stream_set_option ()
#3  0x00005555558d6560 in php_stream_xport_accept ()
#4  0x0000555555884378 in ?? ()
#5  0x0000555555994a85 in execute_ex ()
#6  0x000055555599aaf6 in zend_execute ()
#7  0x00005555559136aa in zend_execute_scripts ()
#8  0x00005555558b35c9 in php_execute_script ()
#9  0x000055555599d0f6 in ?? ()
#10 0x000055555569e0a7 in ?? ()
#11 0x00007ffff72abce3 in __libc_start_

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-07-03 09:58 UTC] nikic@php.net
-Status: Open +Status: Verified -PHP Version: 7.3.6 +PHP Version: 7.2.20, 7.3.6
 [2019-07-03 09:58 UTC] nikic@php.net
Confirming segfault, also on 7.2.
 [2019-07-03 10:37 UTC] nikic@php.net
Automatic comment on behalf of nikita.ppv@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=0e48e35e0485bc6d6458a45ecab5b19a0c2ec001
Log: Fixed bug #78231
 [2019-07-03 10:37 UTC] nikic@php.net
-Status: Verified +Status: Closed
 [2019-07-03 10:38 UTC] nikic@php.net
-Assigned To: +Assigned To: nikic
 [2019-07-03 10:38 UTC] nikic@php.net
Segfault fixed... Note that the script is missing the listen step, so the accept will still fail.
 [2019-07-05 10:41 UTC] asmqb7 at gmail dot com
Wow - that was a very quick fix!

(Could not possibly have expected it was from the openssl extension checking if tcp_nodelay was enabled :) interesting.)

Good catch about the missing `socket_listen($socket)`, which should have gone immediately after the `socket_bind()`. Didn't realize this because the segfault got in the way.

Also, my apologies for the unneeded edges in my initial bug report - my feathers were ruffled, but not to the extent I let on.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Nov 23 08:01:28 2024 UTC