Skip to content

mod_sed: Fix handling of malformed scripts and of InputSed request bodies - #791

Open
notroj wants to merge 5 commits into
apache:trunkfrom
notroj:mod_sed-fixes
Open

notroj wants to merge 5 commits into
apache:trunkfrom
notroj:mod_sed-fixes

Conversation

@notroj

@notroj notroj commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator

Fixes a number of bugs in mod_sed, each with a test in test/modules/filters/test_003_sed.py.

Scripts which were accepted and then mishandled are now rejected when the configuration is loaded: \{m,n\} after a group, backreference or another interval; a backreference to a group which is still open; { nested more than 20 deep; a regular expression or bracket expression missing its end; s or y with no delimiter; and interval counts or line numbers too large to store. A backreference to any closed group, previously rejected in some nestings, is now accepted, and delimiters and y characters with the high bit set now work.

InputSed now filters a request body read with AP_MODE_GETLINE, which was previously passed through unchanged, and removes the request Content-Length header once the body is filtered. It does so after its first read from HTTP_IN, not before, since HTTP_IN takes the body length from that header on its first call. The test module mod_aptest gains an aptest-getline-echo handler to exercise this.

🤖 Generated with Claude Code

notroj and others added 5 commits October 9, 2026 08:14
* modules/filters/regexp.c (sed_compile): Reject \{m,n\} following
  anything but a character, "." or a bracket expression, or following
  another \{m,n\}.  Track which groups have been closed rather than how
  many, and check \N against that.  Reject a bracket expression which
  ends after a range's "-".  Treat a NUL as a missing delimiter.
  Compare the delimiter as an unsigned char.  Check the \{m,n\} count
  limit as each digit is read.
  (regerr): Add error 47.

* test/modules/filters/test_003_sed.py (TestSed.configure): Add fails
  argument.  Write directives given as bytes to a file of their own and
  Include it.
  (test_filters_003_31, test_filters_003_32, test_filters_003_35,
  test_filters_003_36, test_filters_003_39, test_filters_003_40,
  test_filters_003_41, test_filters_003_45): New tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
  AP_MODE_GETLINE reads, returning a line of the filtered body; fail
  other modes besides AP_MODE_READBYTES with APR_ENOTIMPL.  Always
  read with AP_MODE_READBYTES from the next filter.

* test/pyhttpd/mod_aptest/mod_aptest.c (aptest_getline_echo): New
  handler.
  (aptest_hooks): Register it.

* test/modules/filters/test_003_sed.py (test_filters_003_33): New test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
  Content-Length request header; unset it after reading from the next
  filter.

* test/pyhttpd/mod_aptest/mod_aptest.c (aptest_getline_echo): Buffer
  the body, and return the Content-Length request header left after
  reading it in an AP-Test-Content-Length response header.

* test/modules/filters/test_003_sed.py (test_filters_003_34): New test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* modules/filters/sed0.c (fcomp): Reject { nested more than SED_DEPTH
  deep, and an s or y command with no delimiter.
  (ycomp): Index the translation table by the unsigned value of each
  byte.
  (comple): Return NULL from a failed compile without storing circf.
  (address): Reject a line number too large for apr_int64_t.

* test/modules/filters/test_003_sed.py (test_filters_003_37,
  test_filters_003_38, test_filters_003_42, test_filters_003_43,
  test_filters_003_44, test_filters_003_46, test_filters_003_47): New
  tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
  failing configuration with httpd -t, and return its stderr;
  apachectl_stderr is not set on Windows.
  (test_filters_003_32, test_filters_003_35, test_filters_003_38,
  test_filters_003_39, test_filters_003_40, test_filters_003_42,
  test_filters_003_44, test_filters_003_45, test_filters_003_46): Use it.

* changes-entries/sed-fixes.txt: Add entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
asf-gitbox-commits pushed a commit that referenced this pull request Oct 9, 2026
* modules/filters/regexp.c (sed_compile): Reject \{m,n\} following
  anything but a character, "." or a bracket expression, or following
  another \{m,n\}.  Track which groups have been closed rather than how
  many, and check \N against that.  Reject a bracket expression which
  ends after a range's "-".  Treat a NUL as a missing delimiter.
  Compare the delimiter as an unsigned char.  Check the \{m,n\} count
  limit as each digit is read.
  (regerr): Add error 47.

* test/modules/filters/test_003_sed.py (TestSed.configure): Add fails
  argument.  Write directives given as bytes to a file of their own and
  Include it.
  (test_filters_003_31, test_filters_003_32, test_filters_003_35,
  test_filters_003_36, test_filters_003_39, test_filters_003_40,
  test_filters_003_41, test_filters_003_45): New tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GitHub: PR #791


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1938962 13f79535-47bb-0310-9956-ffa450edef68
asf-gitbox-commits pushed a commit that referenced this pull request Oct 9, 2026
  AP_MODE_GETLINE reads, returning a line of the filtered body; fail
  other modes besides AP_MODE_READBYTES with APR_ENOTIMPL.  Always
  read with AP_MODE_READBYTES from the next filter.

* test/pyhttpd/mod_aptest/mod_aptest.c (aptest_getline_echo): New
  handler.
  (aptest_hooks): Register it.

* test/modules/filters/test_003_sed.py (test_filters_003_33): New test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GitHub: PR #791


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1938963 13f79535-47bb-0310-9956-ffa450edef68
asf-gitbox-commits pushed a commit that referenced this pull request Oct 9, 2026
  Content-Length request header; unset it after reading from the next
  filter.

* test/pyhttpd/mod_aptest/mod_aptest.c (aptest_getline_echo): Buffer
  the body, and return the Content-Length request header left after
  reading it in an AP-Test-Content-Length response header.

* test/modules/filters/test_003_sed.py (test_filters_003_34): New test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GitHub: PR #791


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1938964 13f79535-47bb-0310-9956-ffa450edef68
asf-gitbox-commits pushed a commit that referenced this pull request Oct 9, 2026
* modules/filters/sed0.c (fcomp): Reject { nested more than SED_DEPTH
  deep, and an s or y command with no delimiter.
  (ycomp): Index the translation table by the unsigned value of each
  byte.
  (comple): Return NULL from a failed compile without storing circf.
  (address): Reject a line number too large for apr_int64_t.

* test/modules/filters/test_003_sed.py (test_filters_003_37,
  test_filters_003_38, test_filters_003_42, test_filters_003_43,
  test_filters_003_44, test_filters_003_46, test_filters_003_47): New
  tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GitHub: PR #791


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1938965 13f79535-47bb-0310-9956-ffa450edef68
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