Skip to content

Commit

Permalink
Fix potential double stream release
Browse files Browse the repository at this point in the history
This might result in the remainingStreams being incremented twice and then overflowing to a float, because they're initially PHP_INT_MAX.
  • Loading branch information
kelunik committed Jul 9, 2020
1 parent 7898365 commit 4cc8b27
Showing 1 changed file with 15 additions and 8 deletions.
23 changes: 15 additions & 8 deletions src/Connection/Internal/Http2ConnectionProcessor.php
Expand Up @@ -908,6 +908,8 @@ public function reserveStream(): void
public function unreserveStream(): void
{
++$this->remainingStreams;

\assert($this->remainingStreams <= $this->concurrentStreamLimit);
}

public function getRemainingStreams(): int
Expand Down Expand Up @@ -1189,7 +1191,7 @@ private function applySetting(int $setting, int $value): void
{
switch ($setting) {
case Http2Parser::INITIAL_WINDOW_SIZE:
if ($value > 2147483647) { // (1 << 31) - 1
if ($value < 0 || $value > 2147483647) { // (1 << 31) - 1
$this->handleConnectionException(new Http2ConnectionException(
"Invalid window size: {$value}",
Http2Parser::FLOW_CONTROL_ERROR
Expand Down Expand Up @@ -1239,7 +1241,7 @@ private function applySetting(int $setting, int $value): void
return;

case Http2Parser::MAX_CONCURRENT_STREAMS:
if ($value > 2147483647) { // (1 << 31) - 1
if ($value < 0 || $value > 2147483647) { // (1 << 31) - 1
$this->handleConnectionException(new Http2ConnectionException(
"Invalid concurrent streams value: {$value}",
Http2Parser::PROTOCOL_ERROR
Expand All @@ -1252,6 +1254,9 @@ private function applySetting(int $setting, int $value): void

$this->concurrentStreamLimit = $value;
$this->remainingStreams = $this->concurrentStreamLimit - $priorUsedStreams;

\assert($this->remainingStreams <= $this->concurrentStreamLimit);

return;

case Http2Parser::HEADER_TABLE_SIZE: // TODO Respect this setting from the server
Expand Down Expand Up @@ -1361,6 +1366,14 @@ private function releaseStream(int $streamId, ?\Throwable $exception = null): vo

$stream = $this->streams[$streamId];

unset($this->streams[$streamId]);

if ($streamId & 1) { // Client-initiated stream.
$this->remainingStreams++;

\assert($this->remainingStreams <= $this->concurrentStreamLimit);
}

if ($stream->responsePending || $stream->body || $stream->trailers) {
/**
* @psalm-suppress DeprecatedClass
Expand Down Expand Up @@ -1411,12 +1424,6 @@ private function releaseStream(int $streamId, ?\Throwable $exception = null): vo
});
}

unset($this->streams[$streamId]);

if ($streamId & 1) { // Client-initiated stream.
$this->remainingStreams++;
}

if (!$this->streams && !$this->socket->isClosed()) {
$this->socket->unreference();
}
Expand Down

0 comments on commit 4cc8b27

Please sign in to comment.