diff --git a/src/HttpHdrContRange.cc b/src/HttpHdrContRange.cc index ebfd03fcaba..536fee9ff22 100644 --- a/src/HttpHdrContRange.cc +++ b/src/HttpHdrContRange.cc @@ -15,6 +15,8 @@ #include "HttpHdrContRange.h" #include "HttpHeaderTools.h" +#include + /* * Currently only byte ranges are supported * @@ -86,6 +88,11 @@ httpHdrRangeRespSpecParseInit(HttpHdrRangeSpec * spec, const char *field, int fl return 0; } + if (last_pos == std::numeric_limits::max()) { + debugs(68, 2, "unsupported huge last-byte-pos resp-range-spec near: '" << field << "'"); + return 0; + } + spec->length = size_diff(last_pos + 1, spec->offset); /* we managed to parse, check if the result makes sense */ @@ -173,9 +180,6 @@ httpHdrContRangeParseInit(HttpHdrContRange * range, const char *str) /* Additional paranoidal check for BUG2155 - entity-length MUST be > 0 */ debugs(68, 2, "invalid (entity-length is negative) content-range-spec near: '" << str << "'"); return 0; - } else if (known_spec(range->spec.length) && range->elength < (range->spec.offset + range->spec.length)) { - debugs(68, 2, "invalid (range is outside entity-length) content-range-spec near: '" << str << "'"); - return 0; } // reject unsatisfied-range and such; we only use well-defined ranges today @@ -184,6 +188,24 @@ httpHdrContRangeParseInit(HttpHdrContRange * range, const char *str) return 0; } + // Store I/O adds partial content offsets to the size of various objects and + // buffers (e.g., Store metadata, serialized HTTP headers, mem_node::data, + // and Store I/O buffer). Most such sums do not check for overflows, so we + // check here while assuming that those sizes cannot exceed maximumSize. We + // further assume that most offsets use int64_t or a larger integer type. + static_assert(std::numeric_limitsspec.offset)>::max() >= std::numeric_limits::max()); + const auto maximumSize = int64_t(1024)*1024*1024*1024; // no in-memory Squid object/buffer size can exceed 1 TiB + const auto maximumOffset = std::numeric_limits::max() - maximumSize; + if (range->spec.length > maximumOffset || range->spec.offset > maximumOffset - range->spec.length) { + debugs(68, 2, "huge content-range-spec near: '" << str << "'"); + return 0; + } + + if (known_spec(range->elength) && range->elength < (range->spec.offset + range->spec.length)) { + debugs(68, 2, "invalid (range is outside entity-length) content-range-spec near: '" << str << "'"); + return 0; + } + debugs(68, 8, "parsed content-range field: " << (long int) range->spec.offset << "-" << (long int) range->spec.offset + range->spec.length - 1 << " / " << diff --git a/src/HttpHdrRange.cc b/src/HttpHdrRange.cc index c8be30f6287..e80f8001ac2 100644 --- a/src/HttpHdrRange.cc +++ b/src/HttpHdrRange.cc @@ -96,6 +96,11 @@ HttpHdrRangeSpec::parseInit(const char *field, int flen) return false; } + if (last_pos == std::numeric_limits::max()) { + debugs(64, 2, "unsupported huge last-byte-pos range-spec near: " << field); + return false; + } + HttpHdrRangeSpec::HttpRange aSpec (offset, last_pos + 1); length = aSpec.size(); diff --git a/src/stmem.cc b/src/stmem.cc index a7ea833e9ed..5923665ed9e 100644 --- a/src/stmem.cc +++ b/src/stmem.cc @@ -13,6 +13,7 @@ #include "HttpReply.h" #include "mem_node.h" #include "MemObject.h" +#include "SquidMath.h" #include "stmem.h" /* @@ -311,7 +312,7 @@ mem_hdr::write (StoreIOBuffer const &writeBuffer) return false; } - assert (writeBuffer.offset >= 0); + Assure(IncreaseSum(writeBuffer.offset, writeBuffer.length)); mem_node *target; int64_t currentOffset = writeBuffer.offset; @@ -321,6 +322,7 @@ mem_hdr::write (StoreIOBuffer const &writeBuffer) while (len && (target = nodeToRecieve(currentOffset))) { size_t wrote = writeAvailable(target, currentOffset, len, currentSource); assert (wrote); + Assure(len >= wrote); len -= wrote; currentOffset += wrote; currentSource += wrote;