From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: X-Spam-Status: No, score=-2.9 required=3.0 tests=ALL_TRUSTED,AWL,BAYES_00 shortcircuit=no autolearn=unavailable version=3.3.2 X-Original-To: meta@public-inbox.org Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 9C279633829; Sun, 6 Mar 2016 02:09:29 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Cc: Eric Wong Subject: [PATCH 3/3] http: reject excessively large HTTP request bodies Date: Sun, 6 Mar 2016 02:09:22 +0000 Message-Id: <1457230162-10960-4-git-send-email-e@80x24.org> In-Reply-To: <1457230162-10960-1-git-send-email-e@80x24.org> References: <1457230162-10960-1-git-send-email-e@80x24.org> List-Id: We cannot risk using all of a users' disk space buffering gigantic requests. Use the defaults git gives us since we primarily host git repositories. --- lib/PublicInbox/HTTP.pm | 13 +++++++++++++ t/httpd-corner.t | 21 +++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/lib/PublicInbox/HTTP.pm b/lib/PublicInbox/HTTP.pm index 15db139..0675f6a 100644 --- a/lib/PublicInbox/HTTP.pm +++ b/lib/PublicInbox/HTTP.pm @@ -24,6 +24,12 @@ use constant { CHUNK_MAX_HDR => 256, }; +# Use the same configuration parameter as git since this is primarily +# a slow-client sponge for git-http-backend +# TODO: support per-respository http.maxRequestBuffer somehow... +our $MAX_REQUEST_BUFFER = $ENV{GIT_HTTP_MAX_REQUEST_BUFFER} || + (10 * 1024 * 1024); + my $null_io = IO::File->new('/dev/null', '<'); my $http_date; my $prev = 0; @@ -232,6 +238,10 @@ sub input_prepare { my $input = $null_io; my $len = $env->{CONTENT_LENGTH}; if ($len) { + if ($len > $MAX_REQUEST_BUFFER) { + quit($self, 413); + return; + } $input = IO::File->new_tmpfile; } elsif (env_chunked($env)) { $len = CHUNK_START; @@ -306,6 +316,9 @@ sub event_read_input_chunked { # unlikely... if ($len == CHUNK_START) { if ($$rbuf =~ s/\A([a-f0-9]+).*?\r\n//i) { $len = hex $1; + if (($len + -s $input) > $MAX_REQUEST_BUFFER) { + return quit($self, 413); + } } elsif (length($$rbuf) > CHUNK_MAX_HDR) { return quit($self, 400); } diff --git a/t/httpd-corner.t b/t/httpd-corner.t index 8670846..59f37aa 100644 --- a/t/httpd-corner.t +++ b/t/httpd-corner.t @@ -97,6 +97,27 @@ my $spawn_httpd = sub { like($head, qr/\b400\b/, 'got 400 response'); } +{ + my $conn = conn_for($sock, 'excessive body Content-Length'); + $SIG{PIPE} = 'IGNORE'; + my $n = (10 * 1024 * 1024) + 1; + $conn->write("PUT /sha1 HTTP/1.0\r\nContent-Length: $n\r\n\r\n"); + ok($conn->read(my $buf, 8192), 'read response'); + my ($head, $body) = split(/\r\n\r\n/, $buf); + like($head, qr/\b413\b/, 'got 413 response'); +} + +{ + my $conn = conn_for($sock, 'excessive body chunked'); + $SIG{PIPE} = 'IGNORE'; + my $n = (10 * 1024 * 1024) + 1; + $conn->write("PUT /sha1 HTTP/1.1\r\nTransfer-Encoding: chunked\r\n"); + $conn->write("\r\n".sprintf("%x\r\n", $n)); + ok($conn->read(my $buf, 8192), 'read response'); + my ($head, $body) = split(/\r\n\r\n/, $buf); + like($head, qr/\b413\b/, 'got 413 response'); +} + # Unix domain sockets { my $u = IO::Socket::UNIX->new(Type => SOCK_STREAM, Peer => $upath); -- EW