From c3dce46c5f7cad6bc3cc91cc2c711ac089f25923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Fri, 8 May 2026 11:53:45 +0200 Subject: New upstream version 1.0.1+dfsg --- test/CompareRangeLengthWrap.cpp | 97 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 test/CompareRangeLengthWrap.cpp (limited to 'test/CompareRangeLengthWrap.cpp') diff --git a/test/CompareRangeLengthWrap.cpp b/test/CompareRangeLengthWrap.cpp new file mode 100644 index 0000000..43215bf --- /dev/null +++ b/test/CompareRangeLengthWrap.cpp @@ -0,0 +1,97 @@ +/* + * uriparser - RFC 3986 URI parsing library + * + * Copyright (C) 2026, Joshua W. Windle + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include +#include + +#if !defined(_WIN32) +# include // mmap, mprotect, munmap +# include // sysconf +#endif + +extern "C" { +int uriCompareRangeA(const UriTextRangeA * a, const UriTextRangeA * b); +} + +#if !defined(_WIN32) && (UINTPTR_MAX > UINT32_MAX) +namespace { +static size_t roundUpToPageSize(size_t value, size_t pageSize) { + const size_t remainder = value % pageSize; + if (remainder == 0U) { + return value; + } + + const size_t padding = pageSize - remainder; + EXPECT_LE(padding, SIZE_MAX - value); + return value + padding; +} + +static size_t queryPageSize() { + const long pageSize = sysconf(_SC_PAGESIZE); + EXPECT_GT(pageSize, 0); + return static_cast(pageSize); +} +} // namespace + +TEST(UriSuite, TestRangeComparisonDoesNotWrapLengthChecksOn64Bit) { + const size_t hugeLen = (static_cast(1) << 32) + 10U; + const size_t shortLen = 10U; + const size_t pageSize = queryPageSize(); + const size_t hugeMapLen = roundUpToPageSize(hugeLen, pageSize); + const size_t shortMapLen = pageSize * 2U; + + // Reserve a huge virtual range, with access disabled by default. + char * const hugeBase = static_cast( + mmap(NULL, hugeMapLen, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); + ASSERT_NE(hugeBase, MAP_FAILED); + // Allow access to the first page (and that only). + ASSERT_EQ(0, mprotect(hugeBase, pageSize, PROT_READ | PROT_WRITE)); + // Fill the readable prefix so the vulnerable implementation reaches + // content comparison after truncating the large length. + memset(hugeBase, 'a', pageSize); + + char * const shortBase = static_cast(mmap( + NULL, shortMapLen, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); + ASSERT_NE(shortBase, MAP_FAILED); + // Guard the following page so any over-read beyond shortLen faults. + ASSERT_EQ(0, mprotect(shortBase + pageSize, pageSize, PROT_NONE)); + + char * const shortStart = shortBase + pageSize - shortLen; + memset(shortStart, 'a', shortLen); + + UriTextRangeA hugeRange; + hugeRange.first = hugeBase; + hugeRange.afterLast = hugeBase + hugeLen; + + UriTextRangeA shortRange; + shortRange.first = shortStart; + shortRange.afterLast = shortStart + shortLen; + + const int comparison = uriCompareRangeA(&hugeRange, &shortRange); + + EXPECT_EQ(1, comparison); + + EXPECT_EQ(0, munmap(hugeBase, hugeMapLen)); + EXPECT_EQ(0, munmap(shortBase, shortMapLen)); +} +#endif -- cgit v1.2.3