>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