Skip to content

Commit b921cf8

Browse files
committed
Harden integer parsing around headers
1 parent 4bb005a commit b921cf8

6 files changed

Lines changed: 33 additions & 0 deletions

File tree

lib/plug/debugger.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,7 @@ defmodule Plug.Debugger do
577577

578578
def get_mfa(capture) do
579579
[function_path, arity] = String.split(capture, "/")
580+
true = byte_size(arity) <= 3
580581
{arity, ""} = Integer.parse(arity)
581582
parts = String.split(function_path, ".")
582583
{function_str, parts} = List.pop_at(parts, -1)

lib/plug/rewrite_on.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ defmodule Plug.RewriteOn do
122122

123123
defp put_port(conn, headers) do
124124
with [header] <- headers,
125+
true <- byte_size(header) <= 5,
125126
{port, ""} <- Integer.parse(header) do
126127
%{conn | port: port}
127128
else

lib/plug/static.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,8 @@ defmodule Plug.Static do
286286
file_info(size: file_size) = file_info
287287

288288
with %{"bytes" => bytes} <- Plug.Conn.Utils.params(range),
289+
# 41 bytes covers two 64 bit byte offsets, enough to address files up to 16 EiB.
290+
true <- byte_size(bytes) <= 41,
289291
{range_start, range_end} <- start_and_end(bytes, file_size) do
290292
send_range(conn, path, range_start, range_end, file_size, options)
291293
else

test/plug/debugger_test.exs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,13 @@ defmodule Plug.DebuggerTest do
606606
~r(<a href="https://hexdocs.pm/plug/.*/Plug.Conn.html#send_resp/3" target="_blank">`Plug.Conn.send_resp/3`</a>)
607607
end
608608

609+
test "does not parse function references with arities longer than 3 bytes" do
610+
assert Plug.Debugger.get_mfa("Plug.Conn.send_resp/333") ==
611+
{:ok, Plug.Conn, :send_resp, 333}
612+
613+
assert Plug.Debugger.get_mfa("Plug.Conn.send_resp/3333") == :error
614+
end
615+
609616
test "does not create new atoms" do
610617
conn =
611618
conn(:get, "/foo/bar")

test/plug/rewrite_on_test.exs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ defmodule Plug.RewriteOnTest do
8484
assert conn.port == 3030
8585
end
8686

87+
test "does not rewrite port with more than 5 bytes" do
88+
conn =
89+
conn(:get, "http://example.com/")
90+
|> put_req_header("x-forwarded-port", "303030")
91+
|> call(:x_forwarded_port)
92+
93+
assert conn.port == 80
94+
end
95+
8796
test "rewrites port with a custom header" do
8897
conn =
8998
conn(:get, "http://example.com/")

test/plug/static_test.exs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,19 @@ defmodule Plug.StaticTest do
422422
assert get_resp_header(conn, "content-range") == ["bytes 4-4/5"]
423423
end
424424

425+
test "returns entire file if range is longer than 41 bytes" do
426+
too_large = String.duplicate("1", 42)
427+
428+
conn =
429+
conn(:get, "/public/fixtures/static.txt", [])
430+
|> put_req_header("range", "bytes=#{too_large}")
431+
|> call()
432+
433+
assert conn.status == 200
434+
assert conn.resp_body == "HELLO"
435+
assert get_resp_header(conn, "content-type") == ["text/plain"]
436+
end
437+
425438
test "returns entire file if range does not contain either start or end" do
426439
conn =
427440
conn(:get, "/public/fixtures/static.txt", [])

0 commit comments

Comments
 (0)