Commit 2235723
committed
fix(config): bound option-line parsing
`GitConfigParser.OPTCRE` matched an option line with
`(?P<option>[^:=#;]*)` immediately followed by `\s*(?P<vi>[:=])`. The
option name class and that `\s*` both match spaces, so a line that never
reaches a `:` or `=` separator (a key followed by a long run of
whitespace) makes the regex engine retry every space position, taking
`O(n^2)` time in the length of the run.
Config files are parsed straight from repository content. `.gitmodules`
in particular is read whenever submodules of an inspected or cloned
repository are enumerated, so the line is fully attacker-controlled. A
crafted key line costs about `0.25s` of CPU at 8,000 spaces and roughly
`160s` at 200,000, stalling any caller that reads the config.
The trailing `\s*` is redundant: `[^:=#;]*` already consumes any spaces
up to the indicator, and the captured name is right-stripped after
parsing. Dropping it leaves a single quantifier over the whitespace run,
so matching is linear. The collapsed pattern accepts exactly the same
lines and yields the same groups as the previous one, checked over
200,000 fuzzed inputs with zero differences.
Add `test_option_line_with_long_whitespace_run_is_not_quadratic`, a
CPU-time regression that fails on the previous pattern and passes here,
and that confirms a valid key before the malformed line still parses.1 parent f8776ee commit 2235723
2 files changed
Lines changed: 25 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
334 | 334 | | |
335 | 335 | | |
336 | 336 | | |
337 | | - | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
338 | 342 | | |
339 | 343 | | |
340 | 344 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| 12 | + | |
12 | 13 | | |
13 | 14 | | |
14 | 15 | | |
| |||
262 | 263 | | |
263 | 264 | | |
264 | 265 | | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
265 | 285 | | |
266 | 286 | | |
267 | 287 | | |
| |||
0 commit comments