Skip to content

mod_sed: fix out-of-bounds read in ycomp on mismatched y/// strings#678

Open
OffByQuant wants to merge 1 commit into
apache:trunkfrom
OffByQuant:mod_sed-ycomp-oob-read
Open

mod_sed: fix out-of-bounds read in ycomp on mismatched y/// strings#678
OffByQuant wants to merge 1 commit into
apache:trunkfrom
OffByQuant:mod_sed-ycomp-oob-read

Conversation

@OffByQuant

Copy link
Copy Markdown

Summary

ycomp() (modules/filters/sed0.c) compiles the sed y/source/dest/ transliterate command by walking the source and destination strings in lock-step. The first scan loop guards *tsp against '\0'/'\n', but the second loop reads the destination via *tsp++ with no such guard — it stops only when the source pointer reaches the delimiter. When the destination string is shorter than the source, tsp runs past the destination's closing delimiter and the NUL terminator, reading past the end of the LBSIZE + 1 line buffer (commands->linebuf) into adjacent memory until it happens to hit a matching byte.

The existing size-mismatch check (SEDERR_TSNTSS) already detects this case — it fires as soon as a destination byte reads back as the delimiter or NUL — but it only logs via command_errf() (which does not abort) and continues, so the over-read proceeds. This change makes that check return NULL, as every other error path in ycomp already does (the caller handles NULL by returning -1). That both fixes the over-read and rejects the malformed command, matching standard sed (strings for 'y' command are different lengths).

Scope

The sed program is supplied via the OutputSed/InputSed configuration directives (ACCESS_CONF), so this is a robustness fix for malformed configuration, not a remotely triggerable issue — the HTTP request is only the data the compiled program is applied to and never re-enters ycomp.

Testing

Built sed0.c + sed1.c + regexp.c with a small harness driving the real public API (sed_init_commands + sed_compile_string):

  • Before: a y command with a 900-char source and 1-char destination read to offset 1802 of the 1001-byte line buffer (802 out-of-bounds reads, shown via instrumentation — plain ASan does not flag it because APR pools sub-allocate linebuf from a larger block).
  • After: 0 out-of-bounds reads; malformed y commands (shorter dest, longer dest, missing delimiter) are rejected cleanly with a single SEDERR_TSNTSS.
  • No regression: valid y/s/chained-command output is byte-identical to the pristine build across a differential battery.

ycomp() compiles the sed "y/source/dest/" transliterate command by walking
the source and destination strings in lock-step. The first scan loop guards
*tsp against '\0'/'\n', but the second loop reads the destination via *tsp++
with no such guard: it stops only when the source pointer reaches the
delimiter. When the destination string is shorter than the source, tsp runs
past the destination's closing delimiter and the NUL terminator, reading
past the end of the LBSIZE+1 line buffer (commands->linebuf) into adjacent
memory until it happens to hit a matching byte.

The existing size-mismatch check (SEDERR_TSNTSS) already detects this case --
it fires as soon as a destination byte reads back as the delimiter or NUL --
but it only logs and continues, so the over-read proceeds. Make that check
abort compilation (return NULL, as every other error path in ycomp does),
which both fixes the over-read and rejects the malformed command, matching
the behaviour of standard sed ("strings for `y' command are different
lengths").

The sed program is supplied via the OutputSed/InputSed configuration
directives (ACCESS_CONF), so this is a robustness fix for malformed
configuration, not a remotely triggerable issue.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant