>From be1255098e21b45015da9483c566cf9127074fe5 Mon Sep 17 00:00:00 2001 From: Assaf Gordon Date: Thu, 22 Mar 2018 18:40:12 -0600 Subject: [PATCH] sed: reject RE searches on buffers larger than INT_MAX Sed uses 'size_t' internally, but gnulib's re_search uses 'signed int'. If the buffer is larger than INT_MAX, reject it (panic, exit code 4). The test is marked 'very expensive' and skipped by default (due to creating a 2GB input file). To run it, use: make check SUBDIRS=. RUN_VERY_EXPENSIVE_TESTS=yes \ TESTS=testsuite/regex-max-int.sh Reported by YushiOMOTE in https://bugs.gnu.org/30520 . * NEWS: Mention this. * init.cfg (expensive_, very_expensive_): Copied from coreutils. * sed/regexp.c (match_regex): Check buffer length and panic if too large. * testsuite/regex-max-int.sh: New test. * testsuite/local.mk (T): Add new test. --- NEWS | 4 ++++ init.cfg | 34 +++++++++++++++++++++++++++++++ sed/regexp.c | 5 +++++ testsuite/local.mk | 1 + testsuite/regex-max-int.sh | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 95 insertions(+) create mode 100755 testsuite/regex-max-int.sh diff --git a/NEWS b/NEWS index e218a72..d1366f4 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,10 @@ GNU sed NEWS -*- outline -*- ** Bug fixes + sed now detects and terminate when running regex on very long lines (>2GB). + Previously sed would silently ignore the regex without indicating an + error. [Bug existed at least since sed-3.02] + sed no longer rejects comments and closing braces after y/// commands. [Bug existed at least since sed-3.02] diff --git a/init.cfg b/init.cfg index bd3db79..0d5e3a3 100644 --- a/init.cfg +++ b/init.cfg @@ -152,3 +152,37 @@ require_selinux_() ;; esac } + +very_expensive_() +{ + if test "$RUN_VERY_EXPENSIVE_TESTS" != yes; then + skip_ 'very expensive: disabled by default +This test is very expensive, so it is disabled by default. +To run it anyway, rerun make check with the RUN_VERY_EXPENSIVE_TESTS +environment variable set to yes. E.g., + + env RUN_VERY_EXPENSIVE_TESTS=yes make check + +or use the shortcut target of the toplevel Makefile, + + make check-very-expensive +' + fi +} + +expensive_() +{ + if test "$RUN_EXPENSIVE_TESTS" != yes; then + skip_ 'expensive: disabled by default +This test is relatively expensive, so it is disabled by default. +To run it anyway, rerun make check with the RUN_EXPENSIVE_TESTS +environment variable set to yes. E.g., + + env RUN_EXPENSIVE_TESTS=yes make check + +or use the shortcut target of the toplevel Makefile, + + make check-expensive +' + fi +} diff --git a/sed/regexp.c b/sed/regexp.c index 422e89f..f7c2851 100644 --- a/sed/regexp.c +++ b/sed/regexp.c @@ -18,6 +18,7 @@ #include "sed.h" #include +#include #include #include #include @@ -253,6 +254,10 @@ match_regex(struct regex *regex, char *buf, size_t buflen, else regex_last = regex; + /* gnulib's re_search uses signed-int as length */ + if (buflen >= INT_MAX) + panic (_("regex input buffer length larger than INT_MAX")); + #ifdef REG_PERL regmatch[0].rm_so = (int)buf_start_offset; regmatch[0].rm_eo = (int)buflen; diff --git a/testsuite/local.mk b/testsuite/local.mk index 1415f20..eb535c9 100644 --- a/testsuite/local.mk +++ b/testsuite/local.mk @@ -71,6 +71,7 @@ T = \ testsuite/range-overlap.sh \ testsuite/recursive-escape-c.sh \ testsuite/regex-errors.sh \ + testsuite/regex-max-int.sh \ testsuite/sandbox.sh \ testsuite/stdin-prog.sh \ testsuite/subst-options.sh \ diff --git a/testsuite/regex-max-int.sh b/testsuite/regex-max-int.sh new file mode 100755 index 0000000..1118645 --- /dev/null +++ b/testsuite/regex-max-int.sh @@ -0,0 +1,51 @@ +#!/bin/sh +# Test regex on input buffers larger than 2GB + +# Copyright (C) 2016-2018 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +. "${srcdir=.}/testsuite/init.sh"; path_prepend_ ./sed +very_expensive_ +print_ver_ sed + +fail=0 + + +# Create a file larger than 2GB and containing a single line +# (resulting in a regex match against the entire file) +# +# This is a "very expensive" test, we can assume it is only run by +# developers or advanced users, and we can assume truncate(1) exists. +# +# On most modern file-systems, the file will be sparse and would not +# consume 2GB of physical storage. + +truncate -s 1G input || framework_failure_ +printf aaaa >> input || framework_failure_ +truncate -s +1G input || framework_failure_ +printf 'a\n' >> input || framework_failure_ + +# The expected error message +cat <<\EOF > exp-err1 || framework_failure_ +sed: regex input buffer length larger than INT_MAX +EOF + + +# Before sed-4.5, this was silently a no-op: would not perform the subsitution +# but would not indicate any error either (https://bugs.gnu.org/30520). +# Exit code 4 is "panic". +returns_ 4 sed 's/a/b/g' input < /dev/null >/dev/null 2>err1 || fail=1 +compare_ exp-err1 err1 || fail=1 + +Exit $fail -- 2.7.4