Bug #18351: socket_read() on closed sock crashed OS and forced instant warm boot of machine
| From: | administrator at zinious dot com | Date: | Mon, 15 Jul 2002 13:05:38 +0000 |
| Subject: | Bug #18351: socket_read() on closed sock crashed OS and forced instant warm boot of machine | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-14202@lists.php.net to get a copy of this message | ||
From: administrator@zinious.com
Operating system: Windows 2000 Server sp2, IIS 5.0
PHP version: 4.2.1
PHP Bug Type: Reproducible crash
Bug description: socket_read() on closed sock crashed OS and forced instant warm boot of machine
Used the standard W32 build of PHP.EXE (I did not compile it).
Wrote a PHP script that acts as a relay server (client connects to me, I
connect to the destination server and act as a proxy/gateway to that
server for the client).
The destination server had closed the connection and my script
socket_select()'ed on it. However, due to a bug in my script that
returned the wrong value, I proceeded to try and socket_read() from the
socket instead of closing the client connection and ending the script.
The result of a socket_read() after failing on a socket_select() caused
Windows 2000 Server s.p. 2 running IIS 5.0 to die immediately, forced a
warm boot of the machine (no GPF, just immediate warm boot).
I reproduced it 3 times, totalling 4 sucessful warm-boots before finding
my bug and fixing it. I have not encountered the problem since.
Incidently, my bug was returning "ZSC_LOSTCONNECTION" from a function that
polls the socket, but I was testing for "ZSC_CONNECTIONLOST" instead.
Here is my full relay script, the fixed version (it's very simple to
"unfix it" and modify it to act as a normal relay instead of the special
service requests that I wrote in).
Hope this helps guys,
Peter Souza IV
CEO/administrator
administrator@zinious.com
Zinious Software corporation
www.zinious.com
-----script here-----
#!/usr/bin/php -q
<?php
function SocketCheck($socket_to_check)
{
$readsocks = array($socket_to_check);
$readsocks = array($socket_to_check);
$num_changed_sockets = socket_select($readsocks, $writesocks = NULL,
$exceptsocks = NULL, 0);
if ($num_changed_sockets > 0)
{
if (($indata = socket_read($socket_to_check, 1024)) !== false)
{
if ($indata == "")
return "ZSC_LOSTCONNECTION";
return $indata;
}
else
{
return "ZSC_LOSTCONNECTION";
}
}
return "ZSC_NOCHANGE";
}
function DoServer( )
{
error_reporting (E_ALL);
set_time_limit (0);
ob_implicit_flush ();
$socket = socket_create( AF_INET , SOCK_STREAM , SOL_TCP);
$player_socket = socket_create( AF_INET , SOCK_STREAM , SOL_TCP);
$unused_socket = socket_create( AF_INET , SOCK_STREAM , SOL_TCP);
$isbind = socket_bind($socket, "192.168.0.2", 23);
if (!($isbind))
{
print "Error binding.\r\n";
return 0;
}
print "--- Z.S.C. Relay Server: port 23 ---\r\n\r\n";
socket_listen($socket);
while (true)
{
$newsock = socket_accept($socket);
if ($newsock)
{
socket_getpeername($newsock, $host_from);
$host_from = $host_from." (".gethostbyaddr($host_from).")";
print "[CONNECTION] connection from $host_from\r\n";
$xdata = "";
for ($indata = "ZSC_NOCHANGE"; ((!strstr($xdata,"\n"))&&($indata !=
"ZSC_LOSTCONNECTION")); $indata = SocketCheck($newsock))
if (($indata != "ZSC_LOSTCONNECTION") && ($indata !=
"ZSC_NOCHANGE"))
$xdata .= $indata;
if ($indata == "ZSC_LOSTCONNECTION")
{
print "[CONNECTION] lost connection to $host_from\r\n";
socket_close($newsock);
continue;
}
$indata = $xdata;
if (strstr($indata, "master end relay"))
{
socket_write($newsock, "\r\n--- Z.S.C. Relay Server: shutdown
---\r\n");
print "\r\n--- Z.S.C. Relay Server: shutdown ---\r\n";
socket_close($newsock);
socket_close($socket);
return 0;
}
$szCharacterKey = substr($indata, 0, 32);
$szGameServiceCode = substr($indata, 33, 3);
$szGamePort = substr($indata, 37, 5);
$szGameHost = substr($indata, 43);
while (strstr($szGameHost, "\r") || strstr($szGameHost, "\n"))
$szGameHost = substr($szGameHost, 0, strlen($szGameHost) - 1);
print "[CONNECTION] KEY=$indata";
if (!strstr($indata, "/FE:"))
{
$xdata = "";
for ($indata = "ZSC_NOCHANGE"; ((!strstr($xdata,"\n"))&&($indata !=
"ZSC_LOSTCONNECTION")); $indata = SocketCheck($newsock))
if (($indata != "ZSC_LOSTCONNECTION") && ($indata !=
"ZSC_NOCHANGE"))
$xdata .= $indata;
if ($indata == "ZSC_LOSTCONNECTION")
{
print "[CONNECTION] lost connection to $host_from\r\n";
print "[CONNECTION] had received >$xdata<\r\n";
socket_close($newsock);
continue;
}
$indata = $xdata;
}
$text_out =
sprintf("%cGSBZSC-Relay%cGSA0000000000ZSC-Relay\r\n%cGSD\r\n%c---%c
%cWelcome to Z.S.C. relay server%c %c---%c\r\n%cGSP\r\n\r\n%c---%c %cRelay
will begin momentarily%c %c---%c\r\n\r\n", 28, 28, 28, 139, 160, 143, 160,
139, 160, 28, 139, 160, 143, 160, 139, 160);
socket_write($newsock, $text_out);
$xdata = "";
for ($indata = "ZSC_NOCHANGE"; ((!strstr($xdata,"\n"))&&($indata !=
"ZSC_LOSTCONNECTION")); $indata = SocketCheck($newsock))
if (($indata != "ZSC_LOSTCONNECTION") && ($indata !=
"ZSC_NOCHANGE"))
$xdata .= $indata;
if ($indata == "ZSC_LOSTCONNECTION")
{
print "[CONNECTION] lost connection to $host_from\r\n";
socket_close($newsock);
continue;
}
$indata = $xdata;
///////////////
// LOG IN! //
///////////////
$r_ip = $szGameHost;
$r_hostname = $r_ip; // gethostbyaddr($r_ip);
if ($r_hostname == $r_ip)
{
$r_ip = gethostbyname($r_hostname);
$r_hostname2 = gethostbyaddr($r_ip);
}
else
$r_hostname2 = $r_hostname;
print "[CONNECTION] conecting to $r_hostname ($r_ip /
$r_hostname2)...\r\n";
if (!socket_connect($player_socket, $r_ip, $szGamePort))
{
print "[CONNECTION] Error: could not establish connection\r\n";
$text_out = sprintf("\r\n\r\n%c---%c %cRelay session is over.
Goodbye!%c %c---%c\r\n\r\n", 139, 160, 143, 160, 139, 160);
socket_write($newsock, $text_out);
print "[CONNECTION] closed connection with $host_from\r\n";
socket_close($newsock);
}
else
{
$text_out = sprintf("%s\n", $szCharacterKey);
socket_write($player_socket, $text_out);
socket_write($player_socket, "/FE:WIZARD /V:2.03 /P:WIN32\n");
$shutdown_version = 0;
$remote_shutdown_version = 0;
for (;;)
{
$indata = SocketCheck($player_socket);
if ($indata != "ZSC_NOCHANGE")
{
if ($indata == "ZSC_LOSTCONNECTION")
{
print "[CONNECTION] Connection to $r_hostname lost\r\n";
$remote_shutdown_version = 5;
break;
}
else
{
if ($shutdown_version == 0)
socket_write($newsock, $indata);
// print "[RELAY-GAME] $indata";
}
}
$indata = SocketCheck($newsock);
if ($indata != "ZSC_NOCHANGE")
{
if ($indata == "ZSC_LOSTCONNECTION")
{
print "[CONNECTION] Connection to $host_from lost\r\n";
$shutdown_version = 5;
break;
}
else
{
if ($remote_shutdown_version == 0)
socket_write($player_socket, $indata);
// print "[RELAY-PLAYER] $indata";
}
}
}
if ($remote_shutdown_version != 5)
{
socket_write($player_socket, "QUIT\n");
print "[CONNECTION] closing connection to $r_hostname...\r\n";
}
socket_close($player_socket);
$player_socket = socket_create( AF_INET , SOCK_STREAM , SOL_TCP);
if ($shutdown_version != 5)
{
$text_out = sprintf("\r\n\r\n%c---%c %cRelay session is over.
Goodbye!%c %c---%c\r\n\r\n", 139, 160, 143, 160, 139, 160);
socket_write($newsock, $text_out);
print "[CONNECTION] closing connection to $host_from...\r\n";
}
socket_close($newsock);
}
}
else
{
print "[SYSERR] Error on call to accept().\r\n";
return 0;
}
}
print "--- This line should never display ---\r\n";
}
DoServer( );
?>
-----script here-----
--
Edit bug report at http://bugs.php.net/?id=18351&edit=1
--
Fixed in CVS: http://bugs.php.net/fix.php?id=18351&r=fixedcvs
Fixed in release: http://bugs.php.net/fix.php?id=18351&r=alreadyfixed
Need backtrace: http://bugs.php.net/fix.php?id=18351&r=needtrace
Try newer version: http://bugs.php.net/fix.php?id=18351&r=oldversion
Not developer issue: http://bugs.php.net/fix.php?id=18351&r=support
Expected behavior: http://bugs.php.net/fix.php?id=18351&r=notwrong
Not enough info: http://bugs.php.net/fix.php?id=18351&r=notenoughinfo
Submitted twice: http://bugs.php.net/fix.php?id=18351&r=submittedtwice
register_globals: http://bugs.php.net/fix.php?id=18351&r=globals