From ed8864968f14b8ec60f6e97db3ecb03f605ea0ae Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Oct 09 2017 16:30:30 +0000 Subject: add new content-length filter (upstream PR 61222) --- diff --git a/.gitignore b/.gitignore index 19a3666..e364382 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,7 @@ x86_64 /httpd-2.2.21.tar.bz2 /clog /httpd-2.2.22.tar.bz2 -/httpd-2.4.? +/httpd-2.4.??/ /httpd-2.4.2.tar.bz2 /httpd-2.4.3.tar.bz2 /httpd-2.4.4.tar.bz2 diff --git a/httpd-2.4.27-r1808230.patch b/httpd-2.4.27-r1808230.patch new file mode 100644 index 0000000..e4062ea --- /dev/null +++ b/httpd-2.4.27-r1808230.patch @@ -0,0 +1,131 @@ +# ./pullrev.sh 1808230 +http://svn.apache.org/viewvc?view=revision&revision=1808230 + +--- httpd-2.4.27/server/protocol.c ++++ httpd-2.4.27/server/protocol.c +@@ -1708,62 +1708,88 @@ + ctx->tmpbb = apr_brigade_create(r->pool, r->connection->bucket_alloc); + } + +- /* Loop through this set of buckets to compute their length +- */ ++ /* Loop through the brigade to count the length. To avoid ++ * arbitrary memory consumption with morphing bucket types, this ++ * loop will stop and pass on the brigade when necessary. */ + e = APR_BRIGADE_FIRST(b); + while (e != APR_BRIGADE_SENTINEL(b)) { ++ apr_status_t rv; ++ + if (APR_BUCKET_IS_EOS(e)) { + eos = 1; + break; + } +- if (e->length == (apr_size_t)-1) { ++ /* For a flush bucket, fall through to pass the brigade and ++ * flush now. */ ++ else if (APR_BUCKET_IS_FLUSH(e)) { ++ e = APR_BUCKET_NEXT(e); ++ } ++ /* For metadata bucket types other than FLUSH, loop. */ ++ else if (APR_BUCKET_IS_METADATA(e)) { ++ e = APR_BUCKET_NEXT(e); ++ continue; ++ } ++ /* For determinate length data buckets, count the length and ++ * continue. */ ++ else if (e->length != (apr_size_t)-1) { ++ r->bytes_sent += e->length; ++ e = APR_BUCKET_NEXT(e); ++ continue; ++ } ++ /* For indeterminate length data buckets, perform one read. */ ++ else /* e->length == (apr_size_t)-1 */ { + apr_size_t len; + const char *ignored; +- apr_status_t rv; +- +- /* This is probably a pipe bucket. Send everything +- * prior to this, and then read the data for this bucket. +- */ ++ + rv = apr_bucket_read(e, &ignored, &len, eblock); ++ if ((rv != APR_SUCCESS) && !APR_STATUS_IS_EAGAIN(rv)) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00574) ++ "ap_content_length_filter: " ++ "apr_bucket_read() failed"); ++ return rv; ++ } + if (rv == APR_SUCCESS) { +- /* Attempt a nonblocking read next time through */ + eblock = APR_NONBLOCK_READ; ++ e = APR_BUCKET_NEXT(e); + r->bytes_sent += len; + } + else if (APR_STATUS_IS_EAGAIN(rv)) { +- /* Output everything prior to this bucket, and then +- * do a blocking read on the next batch. +- */ +- if (e != APR_BRIGADE_FIRST(b)) { +- apr_bucket *flush; +- apr_brigade_split_ex(b, e, ctx->tmpbb); +- flush = apr_bucket_flush_create(r->connection->bucket_alloc); ++ apr_bucket *flush; + +- APR_BRIGADE_INSERT_TAIL(b, flush); +- rv = ap_pass_brigade(f->next, b); +- if (rv != APR_SUCCESS || f->c->aborted) { +- return rv; +- } +- apr_brigade_cleanup(b); +- APR_BRIGADE_CONCAT(b, ctx->tmpbb); +- e = APR_BRIGADE_FIRST(b); ++ /* Next read must block. */ ++ eblock = APR_BLOCK_READ; + +- ctx->data_sent = 1; +- } +- eblock = APR_BLOCK_READ; +- continue; ++ /* Ensure the last bucket to pass down is a flush if ++ * the next read will block. */ ++ flush = apr_bucket_flush_create(f->c->bucket_alloc); ++ APR_BUCKET_INSERT_BEFORE(e, flush); + } +- else { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00574) +- "ap_content_length_filter: " +- "apr_bucket_read() failed"); +- return rv; +- } + } +- else { +- r->bytes_sent += e->length; ++ ++ /* Optimization: if the next bucket is EOS (directly after a ++ * bucket morphed to the heap, or a flush), short-cut to ++ * handle EOS straight away - allowing C-L to be determined ++ * for content which is already entirely in memory. */ ++ if (e != APR_BRIGADE_SENTINEL(b) && APR_BUCKET_IS_EOS(e)) { ++ continue; + } +- e = APR_BUCKET_NEXT(e); ++ ++ /* On reaching here, pass on everything in the brigade up to ++ * this point. */ ++ apr_brigade_split_ex(b, e, ctx->tmpbb); ++ ++ rv = ap_pass_brigade(f->next, b); ++ if (rv != APR_SUCCESS) { ++ return rv; ++ } ++ else if (f->c->aborted) { ++ return APR_ECONNABORTED; ++ } ++ apr_brigade_cleanup(b); ++ APR_BRIGADE_CONCAT(b, ctx->tmpbb); ++ e = APR_BRIGADE_FIRST(b); ++ ++ ctx->data_sent = 1; + } + + /* If we've now seen the entire response and it's otherwise diff --git a/httpd.spec b/httpd.spec index f3c95f0..86bad76 100644 --- a/httpd.spec +++ b/httpd.spec @@ -8,7 +8,7 @@ Summary: Apache HTTP Server Name: httpd Version: 2.4.27 -Release: 6%{?dist} +Release: 7%{?dist} URL: https://httpd.apache.org/ Source0: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2 Source1: index.html @@ -68,6 +68,7 @@ Patch57: httpd-2.4.10-sigint.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1397243 Patch58: httpd-2.4.25-r1738878.patch Patch59: httpd-2.4.27-CVE-2017-9798.patch +Patch60: httpd-2.4.27-r1808230.patch # Security fixes License: ASL 2.0 @@ -215,6 +216,7 @@ interface for storing and accessing per-user session data. %patch57 -p1 -b .sigint %patch58 -p1 -b .r1738878 %patch59 -p4 -b .cve-2017-9798 +%patch60 -p1 -b .r1808230 # Patch in the vendor string sed -i '/^#define PLATFORM/s/Unix/%{vstring}/' os/unix/os.h @@ -694,8 +696,9 @@ rm -rf $RPM_BUILD_ROOT %{_rpmconfigdir}/macros.d/macros.httpd %changelog -* Tue Sep 19 2017 Joe Orton - 2.4.27-8.1 +* Tue Sep 19 2017 Joe Orton - 2.4.27-3.1 - move httpd.service.d, httpd.socket.d dirs to -filesystem +- add new content-length filter (upstream PR 61222) * Thu Sep 21 2017 Jeroen van Meeuwen - 2.4.27-3 - Address CVE-2017-9798 by applying patch from upstream (#1490344) diff --git a/pullrev.sh b/pullrev.sh index d106968..c366613 100755 --- a/pullrev.sh +++ b/pullrev.sh @@ -6,8 +6,8 @@ if [ $# -lt 1 ]; then fi repo="https://svn.apache.org/repos/asf/httpd/httpd/trunk" -repo="https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x" -ver=2.4.26 +#repo="https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x" +ver=2.4.27 prefix="httpd-${ver}" suffix="r$1${2:++}" fn="${prefix}-${suffix}.patch"