This is an automated email from the ASF dual-hosted git repository. cmcfarlen pushed a commit to branch 10.2.x in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit f4d07fe0806c01f0f041c872b09d95c652db2334 Author: Brian Neradt <[email protected]> AuthorDate: Fri May 8 15:56:56 2026 -0500 Fix XPACK relative index underflow (#13144) XPACK dynamic table lookups convert absolute matches into HPACK relative indexes. If an impossible future absolute index reached that conversion path, unsigned subtraction could wrap and report a bogus relative index. This guards the conversion by preserving unmatched lookup results and rejecting absolute indexes beyond the current dynamic-table head before subtracting. This also adds XPACK unit coverage for empty, missing, and normal relative lookup results. (cherry picked from commit e698e468fb2d6f9300c18fb86763177d73e49264) --- src/proxy/hdrs/XPACK.cc | 11 ++++++++++- src/proxy/hdrs/unit_tests/test_XPACK.cc | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/proxy/hdrs/XPACK.cc b/src/proxy/hdrs/XPACK.cc index 388618a14d..78acdf056d 100644 --- a/src/proxy/hdrs/XPACK.cc +++ b/src/proxy/hdrs/XPACK.cc @@ -328,7 +328,16 @@ const XpackLookupResult XpackDynamicTable::lookup_relative(const char *name, size_t name_len, const char *value, size_t value_len) const { XpackLookupResult result = this->lookup(name, name_len, value, value_len); - result.index = this->_entries[this->_entries_head].index - result.index; + if (result.match_type == XpackLookupResult::MatchType::NONE) { + return result; + } + + uint32_t const head_index = this->_entries[this->_entries_head].index; + if (result.index > head_index) { + return {0, XpackLookupResult::MatchType::NONE}; + } + + result.index = head_index - result.index; return result; } diff --git a/src/proxy/hdrs/unit_tests/test_XPACK.cc b/src/proxy/hdrs/unit_tests/test_XPACK.cc index 4869509218..c0f9a40d63 100644 --- a/src/proxy/hdrs/unit_tests/test_XPACK.cc +++ b/src/proxy/hdrs/unit_tests/test_XPACK.cc @@ -146,6 +146,10 @@ TEST_CASE("XPACK_String", "[xpack]") REQUIRE(dt.count() == 0); result = dt.lookup("", ""); REQUIRE(result.match_type == XpackLookupResult::MatchType::NONE); + REQUIRE(result.index == 0); + result = dt.lookup_relative("", ""); + REQUIRE(result.match_type == XpackLookupResult::MatchType::NONE); + REQUIRE(result.index == 0); } SECTION("Dynamic Table") @@ -173,6 +177,9 @@ TEST_CASE("XPACK_String", "[xpack]") REQUIRE(result.match_type == XpackLookupResult::MatchType::NONE); result = dt.lookup(MAX_SIZE + 1, &name, &name_len, &value, &value_len); REQUIRE(result.match_type == XpackLookupResult::MatchType::NONE); + result = dt.lookup_relative("missing", "value"); + REQUIRE(result.match_type == XpackLookupResult::MatchType::NONE); + REQUIRE(result.index == 0); // Insert one entry dt.insert_entry("name1", "value1"); @@ -188,6 +195,9 @@ TEST_CASE("XPACK_String", "[xpack]") REQUIRE(memcmp(value, "value1", value_len) == 0); result = dt.lookup(dt.largest_index() + 1, &name, &name_len, &value, &value_len); REQUIRE(result.match_type == XpackLookupResult::MatchType::NONE); + result = dt.lookup_relative("missing", "value1"); + REQUIRE(result.match_type == XpackLookupResult::MatchType::NONE); + REQUIRE(result.index == 0); result = dt.lookup(MAX_SIZE - 1, &name, &name_len, &value, &value_len); REQUIRE(result.match_type == XpackLookupResult::MatchType::NONE); @@ -228,6 +238,15 @@ TEST_CASE("XPACK_String", "[xpack]") REQUIRE(memcmp(name, "name1", name_len) == 0); REQUIRE(value_len == strlen("value1")); REQUIRE(memcmp(value, "value1", value_len) == 0); + result = dt.lookup_relative("name2", "value2"); + REQUIRE(result.match_type == XpackLookupResult::MatchType::EXACT); + REQUIRE(result.index == 0); + result = dt.lookup_relative("name1", "value1"); + REQUIRE(result.match_type == XpackLookupResult::MatchType::EXACT); + REQUIRE(result.index == 1); + result = dt.lookup_relative("missing", "value2"); + REQUIRE(result.match_type == XpackLookupResult::MatchType::NONE); + REQUIRE(result.index == 0); result = dt.lookup(MAX_SIZE - 1, &name, &name_len, &value, &value_len); REQUIRE(result.match_type == XpackLookupResult::MatchType::NONE); result = dt.lookup(MAX_SIZE, &name, &name_len, &value, &value_len);
