Skip to content

Commit

Permalink
=htc fix memory leak when connection is closed before request entity …
Browse files Browse the repository at this point in the history
…is consumed

Previously stages on top of RequestParsing would stay alive because connection
completion would be stuck in the request parsing queue and connection
cancellation did not propagate across the controller stage.

The fix ensures that the controller will shutdown completely once cancellation
was received from the network (connection abortion by the client or idle-timeout
triggered). This makes sure that all connected stages will also receive
cancellation and will shutdown themselves.
  • Loading branch information
jrudolph authored and ktoso committed Jan 23, 2017
1 parent 8c76653 commit 7917cf9
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -442,16 +442,11 @@ private[http] object HttpServerBluePrint {
}
})

class ResponseCtxOutHandler extends OutHandler {
override def onPull() = {}
override def onDownstreamFinish() =
cancel(httpResponseIn) // we cannot fully completeState() here as the websocket pipeline would not complete properly
}
setHandler(responseCtxOut, new ResponseCtxOutHandler {
setHandler(responseCtxOut, new OutHandler {
override def onPull() = {
pull(httpResponseIn)
// after the initial pull here we only ever pull after having emitted in `onPush` of `httpResponseIn`
setHandler(responseCtxOut, new ResponseCtxOutHandler)
setHandler(responseCtxOut, GraphStageLogic.EagerTerminateOutput)
}
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,70 @@ class HttpServerSpec extends AkkaSpec(
shutdownBlueprint()
})

"don't leak stages when connection is closed for request" which {
"uses GET method with an unread empty chunked entity" in assertAllStagesStopped(new TestSetup {
send("""GET / HTTP/1.1
|Host: example.com
|Connection: close
|Transfer-Encoding: chunked
|
|0
|
|""")

val req = expectRequest()
// entity was not read

// send out an 200 OK response
responses.sendNext(HttpResponse())

netIn.sendComplete()
netOut.cancel()

requests.expectComplete()
})

"uses GET request with an unread truncated chunked entity" in assertAllStagesStopped(new TestSetup {
send("""GET / HTTP/1.1
|Host: example.com
|Connection: close
|Transfer-Encoding: chunked
|
|0
|""")

val req = expectRequest()
// entity was not read

// send out an 200 OK response
responses.sendNext(HttpResponse())

netIn.sendComplete()
netOut.cancel()

requests.expectComplete()
})

"uses GET request with a truncated default entity" in assertAllStagesStopped(new TestSetup {
send("""GET / HTTP/1.1
|Host: example.com
|Content-Length: 1
|
|""")

val req = expectRequest()
// entity was not read

// send out an 200 OK response
responses.sendNext(HttpResponse())

netIn.sendComplete()
netOut.cancel()

requests.expectComplete()
})
}

"support request timeouts" which {

"are defined via the config" in assertAllStagesStopped(new RequestTimeoutTestSetup(10.millis) {
Expand Down
4 changes: 4 additions & 0 deletions docs/src/main/paradox/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@ to ensure that a fix can be provided without delay.
### Fixed in Akka HTTP 2.4.11

* @ref:[Directory Traversal Vulnerability Announcement](security/2016-09-30-windows-directory-traversal.md)

### Fixed in Akka HTTP 10.0.2 & 2.4.11.1

* @ref:[Denial-of-Service by stream leak on unconsumed closed connections](security/2017-01-23-denial-of-service-via-leak-on-unconsumed-closed-connections.md)
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<a id="directory-traversal-in-filedirectives"></a>
# Directory Traversal in FileDirectives

## Date
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<a id="denial-of-service-stream-unconsumed-closed-connections"></a>
# Denial-of-Service by stream leak on unconsumed closed connections

## Date

23 January 2017

## Description of Vulnerability

For requests containing request bodies (including request methods which would normally include entities like GET requests),
a mistake in completion handling of a connection could lead to memory leaking after the connection had been closed before the
entity was consumed. This may eventually lead to a failure of the system due to being out of memory.

Please subscribe to the [akka-security](https://groups.google.com/forum/#!forum/akka-security) mailing list to be notified promptly about future security issues.

## Severity

The [CVSS](https://en.wikipedia.org/wiki/CVSS) score of this vulnerability is 6.4 (Medium), based on vector [AV:N/AC:L/Au:N/C:N/I:N/A:C/E:F/RL:OF/RC:C](https://nvd.nist.gov/cvss.cfm?calculator&version=2&vector=%28AV:N/AC:L/Au:N/C:N/I:N/A:C/E:F/RL:OF/RC:C%29).

## Affected Versions

- (experimental) Akka HTTP `2.4.11` and prior,
- (stable) Akka HTTP `10.0.1` and prior.

## Fixed Versions

We have prepared patches for the affected versions, and have released the following versions which resolve the issue:

- Akka HTTP `2.4.11.1` (Scala 2.11)
- Akka HTTP `10.0.2` (Scala 2.11, 2.12)

The patched releases contain no other changes except the single patch that addresses the memory leak vulnerability.
*Binary and source compatibility has been maintained so the upgrade procedure is as simple as changing the library dependency.*

## Additional Important Information

Note that Play and Lagom applications are not impacted by this vulnerability, regardless of whether they are using the Akka HTTP backend or the Netty backend.

If you have any questions or need any help, please contact [support@lightbend.com](mailto:support@lightbend.com).

## Acknowledgements

We would like to thank Dmitry Kolesnikov & Lari Hotari for their thorough investigation and bringing this issue to our attention.

0 comments on commit 7917cf9

Please sign in to comment.