nitrogen / simple_bridge

A simple, standardized interface library to Erlang HTTP Servers.
MIT License
112 stars 76 forks source link

Incorrect processing of incorrect multipart/form-data requests #67

Open sigsergv opened 5 years ago

sigsergv commented 5 years ago

simple_bridge hangs when processing incorrectly passed muiltipart/form-data POST body.

How to reproduce:

  1. start using standard make run_inets
  2. execute command curl -X POST -H 'Content-Type: multipart/form-data; boundary=12345' --data-binary "@test-data-bad" "http://localhost:8000/"

Expected result: Error 4xx or 5xx.

Actual result: request never ends (or stop after some timeout).

On large amount of such requests code consumes all CPU resources very quickly.

I've attached test data and sample code in test.sh simple_bridge_post_form.tar.gz

In "bad" payload I use \n instead of \r\n.

As a dirty workaround I use this code in simple_bridge_multipart:

--- a/simple_bridge/src/simple_bridge_multipart.erl
+++ b/simple_bridge/src/simple_bridge_multipart.erl
@@ -230,6 +230,13 @@ get_next_line(Data, Acc, Part, State) when Data == undefined orelse Data == <<>>

 read_chunk(State = #state { req=Req, length=Length, bytes_read=BytesRead }) ->
     BytesToRead = lists:min([Length - BytesRead, ?CHUNKSIZE]),
+    if
+        BytesToRead==0 ->
+            error_logger:error_msg("LineEnding failed, state: ~p~n", [State]),
+            erlang:throw({unexpected, line_end, 0});
+        true ->
+            ok
+    end,
     Data = sbw:recv_from_socket(BytesToRead, ?IDLE_TIMEOUT, Req),
     NewBytesRead = BytesRead + size(Data),
     ok=crash_if_too_big(NewBytesRead, State),
choptastic commented 5 years ago

Thank you so much, Sergey!

I'll experiment with this today.

-Jesse

On Fri, Feb 15, 2019, 1:56 AM Sergey Stolyarov notifications@github.com wrote:

simple_bridge hangs when processing incorrectly passed muiltipart/form-data POST body.

How to reproduce:

  1. start using standard make run_inets
  2. execute command curl -X POST -H 'Content-Type: multipart/form-data; boundary=12345' --data-binary "@test-data-bad" "http://localhost:8000/"

Expected result: Error 4xx or 5xx.

Actual result: request never ends (or stop after some timeout).

On large amount of such requests code consumes all CPU resources very quickly.

I've attached test data and sample code in test.sh simple_bridge_post_form.tar.gz https://github.com/nitrogen/simple_bridge/files/2868183/simple_bridge_post_form.tar.gz

In "bad" payload I use \n instead of \r\n.

As a dirty workaround I use this code in simple_bridge_multipart:

--- a/simple_bridge/src/simple_bridge_multipart.erl +++ b/simple_bridge/src/simple_bridge_multipart.erl @@ -230,6 +230,13 @@ get_next_line(Data, Acc, Part, State) when Data == undefined orelse Data == <<>>

read_chunk(State = #state { req=Req, length=Length, bytes_read=BytesRead }) -> BytesToRead = lists:min([Length - BytesRead, ?CHUNKSIZE]),

  • if
  • BytesToRead==0 ->
  • error_logger:error_msg("LineEnding failed, state: ~p~n", [State]),
  • erlang:throw({unexpected, line_end, 0});
  • true ->
  • ok
  • end, Data = sbw:recv_from_socket(BytesToRead, ?IDLE_TIMEOUT, Req), NewBytesRead = BytesRead + size(Data), ok=crash_if_too_big(NewBytesRead, State),

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/nitrogen/simple_bridge/issues/67, or mute the thread https://github.com/notifications/unsubscribe-auth/AALYnDtL2nW1PIwMoF91okTa9MFcjU58ks5vNmg8gaJpZM4a9IEQ .