cmcfarlen commented on PR #13517:
URL: https://github.com/apache/trafficserver/pull/13517#issuecomment-5242858316

   The diagnosis is right and the fix is in the correct place. A few things I 
verified that seem worth recording, including one that makes this more than a 
contract cleanup.
   
   **The bound really was wrong.** Master checks `index >= 
pcre2_get_ovector_count(...)`, which is the *allocated* pair count — 
`DEFAULT_MATCHES` is 10 and the storage is a raw `char _buffer[24 + 96 + 28 * 
DEFAULT_MATCHES]` member with no initializer. So an index between the highest 
participating group and 10 passes the check and builds a view from whatever was 
in that buffer. Bounding by `_size` is the right fix because `_size` is what 
`pcre2_match()` reported it populated.
   
   **The `rc == 0` case is why `_size <= 0` is safe, and it is worth being 
explicit about.** My first concern was that PCRE2 returns 0 for "match 
succeeded but the ovector was too small", with group 0 still valid — a naive 
`_size <= 0` guard would then return `""` for `matches[0]` on any pattern with 
more than 10 groups, which master handles correctly. That does not happen here, 
because `Regex::exec()` normalizes it first:
   
   ```cpp
   if (rc == 0) {
     matches._size = 
pcre2_get_ovector_count(RegexMatches::_MatchData::get(matches._match_data));
   }
   ```
   
   and in that case PCRE2 has filled every pair, so the allocated count *is* 
the populated count. After normalization `_size <= 0` can only mean a genuine 
error. Correct, but it depends on a normalization several dozen lines away in 
another function — a sentence in the comment pointing at it would save the next 
reader the same detour.
   
   **A second improvement the description doesn't claim.** When `RE_FULL_MATCH` 
is requested and the match does not consume the whole subject, `exec()` sets 
`matches._size = PCRE2_ERROR_NOMATCH`. Under the new bound that makes a 
subsequent `matches[0]` return `""`; on master it still returns a live view 
over a match the caller was told to reject. Worth mentioning, since it is a 
behavior change beyond the stale-memory case.
   
   **The `""`-instead-of-default-constructed part fixes something live, not 
just theoretical.** The description says this is a contract fix with nothing in 
tree able to reach it. That is true of the out-of-range read, but the null 
`data()` is reachable today via #13441. `plugins/prefetch/pattern.cc` guards up 
front with `if (_tokens[i] >= matchCount)`, so `replIndex < matchCount` holds — 
and #13441 returns a default-constructed `std::string_view` for a group 
*inside* that range that did not participate, whose `data()` is null (its own 
unit test asserts `matches[1].data() == nullptr`). `replace()` then does:
   
   ```cpp
   PrefetchDebug("replacing '%s' with '%.*s'", src.c_str(), 
static_cast<int>(dst.length()), dst.data());
   result.append(dst.data(), dst.length());
   ```
   
   so a pattern with an optional group preceding a participating one — 
`/(v\d+/)?(.*-)(\d+)$/$1$2{$3+1}/` against a request without the prefix — 
passes a null pointer to `%.*s` and to `append(const char *, size_t)`. Benign 
on our libcs, undefined either way.
   
   I raised exactly this on #13352 and suggested that PR normalize the view 
locally. Fixing it here instead is clearly the better place, since it covers 
all four call sites at once rather than one plugin. Worth a note on #13352 so 
the local guard isn't added redundantly — I'll leave that there.
   
   **The no-end-offset-check rationale holds.** I checked that neither 
`PCRE2_EXTRA_ALLOW_LOOKAROUND_BSK` nor `pcre2_set_compile_extra_options` 
appears anywhere in the tree, so the `\K`-in-lookaround escape hatch is 
genuinely unreachable here rather than merely unlikely.
   
   One nit: the cachekey citation is off by a line. 
`plugins/cachekey/pattern.cc:271` is `String src(_replacement, _tokenOffset[i], 
2);`, which does not involve `matches`; the `std::string` construction from a 
possibly-null pointer is the next line, `String dst(capture.data(), 
capture.length());`. The other three citations land exactly.
   
   Nothing blocking.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to