* NEWS: Mention this.
* src/stty.c (strtoul_tcflag_t, strtoul_cc_t): New functions.
(recover_mode): Use those functions (not sscanf), to parse the
string robustly.
* tests/stty/invalid: New file. Test for the above.
* tests/stty/Makefile.am (TESTS): Add invalid.
* .x-sc_prohibit_atoi_atof: Don't exempt stty.c from this check.
Add tests/stty/invalid so we don't have to obfuscate the comment
about sscanf therein.
* Makefile.maint (sc_prohibit_atoi_atof): Mention sscanf in the
diagnostic, too.
^lib/group-member\.c$
^Makefile\.maint$
^doc/coreutils.texi$
-^src/stty.c$
+^tests/stty/invalid$
2007-05-20 Jim Meyering <jim@meyering.net>
+ stty: diagnose an invalid hex value in 35-colon commmand-line argument
+ * NEWS: Mention this.
+ * src/stty.c (strtoul_tcflag_t, strtoul_cc_t): New functions.
+ (recover_mode): Use those functions (not sscanf), to parse the
+ string robustly.
+ * tests/stty/invalid: New file. Test for the above.
+ * tests/stty/Makefile.am (TESTS): Add invalid.
+ * .x-sc_prohibit_atoi_atof: Don't exempt stty.c from this check.
+ Add tests/stty/invalid so we don't have to obfuscate the comment
+ about sscanf therein.
+ * Makefile.maint (sc_prohibit_atoi_atof): Mention sscanf in the
+ diagnostic, too.
+
* TODO: Remove some now-completed or no longer relevant items.
2007-05-19 Jim Meyering <jim@meyering.net>
# Instead, use strto* functions.
sc_prohibit_atoi_atof:
@grep -nE '\<([fs]?scanf|ato([filq]|ll))\>' $$($(CVS_LIST_EXCEPT)) && \
- { echo '$(ME): do not use *scan''f, ato''f, ato''i, ato''l, ato''ll, or ato''q' \
+ { echo '$(ME): do not use *scan''f, ato''f, ato''i, ato''l, ato''ll, ato''q, or ss''canf' \
1>&2; exit 1; } || :
# Using EXIT_SUCCESS as the first argument to error is misleading,
tr -c no longer aborts when translating with Set2 larger than the
complement of Set1. [introduced with the original version, in 1992]
+** Improved robustness
+
+ stty no longer silently accepts certain invalid hex values
+ in its 35-colon commmand-line argument
+
* Noteworthy changes in release 6.9 (2007-03-22) [stable]
putchar ('\n');
}
+/* NOTE: identical to below, modulo use of tcflag_t */
+static int
+strtoul_tcflag_t (char const *s, int base, char **p, tcflag_t *result,
+ char delim)
+{
+ unsigned long ul;
+ errno = 0;
+ ul = strtoul (s, p, base);
+ if (errno || **p != delim || *p == s || (tcflag_t) ul != ul)
+ return -1;
+ *result = ul;
+ return 0;
+}
+
+/* NOTE: identical to above, modulo use of cc_t */
+static int
+strtoul_cc_t (char const *s, int base, char **p, cc_t *result, char delim)
+{
+ unsigned long ul;
+ errno = 0;
+ ul = strtoul (s, p, base);
+ if (errno || **p != delim || *p == s || (cc_t) ul != ul)
+ return -1;
+ *result = ul;
+ return 0;
+}
+
+/* Parse the output of display_recoverable.
+ Return false if any part of it is invalid. */
static bool
recover_mode (char const *arg, struct termios *mode)
{
+ tcflag_t flag[4];
+ char const *s = arg;
size_t i;
- int n;
- unsigned long int chr;
- unsigned long int iflag, oflag, cflag, lflag;
-
- /* Scan into temporaries since it is too much trouble to figure out
- the right format for `tcflag_t'. */
- if (sscanf (arg, "%lx:%lx:%lx:%lx%n",
- &iflag, &oflag, &cflag, &lflag, &n) != 4)
- return false;
- mode->c_iflag = iflag;
- mode->c_oflag = oflag;
- mode->c_cflag = cflag;
- mode->c_lflag = lflag;
- if (mode->c_iflag != iflag
- || mode->c_oflag != oflag
- || mode->c_cflag != cflag
- || mode->c_lflag != lflag)
- return false;
- arg += n;
- for (i = 0; i < NCCS; ++i)
+ for (i = 0; i < 4; i++)
{
- if (sscanf (arg, ":%lx%n", &chr, &n) != 1)
+ char *p;
+ if (strtoul_tcflag_t (s, 16, &p, flag + i, ':') != 0)
return false;
- mode->c_cc[i] = chr;
- if (mode->c_cc[i] != chr)
- return false;
- arg += n;
+ s = p + 1;
}
+ mode->c_iflag = flag[0];
+ mode->c_oflag = flag[1];
+ mode->c_cflag = flag[2];
+ mode->c_lflag = flag[3];
- /* Fail if there are too many fields. */
- if (*arg != '\0')
- return false;
+ for (i = 0; i < NCCS; ++i)
+ {
+ char *p;
+ char delim = i < NCCS - 1 ? ':' : '\0';
+ if (strtoul_cc_t (s, 16, &p, mode->c_cc + i, delim) != 0)
+ return false;
+ s = p + 1;
+ }
return true;
}
## Process this file with automake to produce Makefile.in -*-Makefile-*-.
-TESTS = row-col-1 basic-1
+TESTS = invalid row-col-1 basic-1
EXTRA_DIST = $(TESTS)
TESTS_ENVIRONMENT = \
CU_TEST_NAME=`basename $(abs_srcdir)`,$$tst \
--- /dev/null
+#!/bin/sh
+# Ensure that stty diagnoses invalid inputs, rather than silently misbehaving.
+
+# Copyright (C) 2007 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 2 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+if test "$VERBOSE" = yes; then
+ set -x
+ stty --version
+fi
+
+# Make sure there's a tty on stdin.
+. $srcdir/../input-tty
+
+pwd=`pwd`
+t0=`echo "$0"|sed 's,.*/,,'`.tmp; tmp=$t0/$$
+trap 'status=$?; cd "$pwd" && chmod -R u+rwx $t0 && rm -rf $t0 && exit $status' 0
+trap '(exit $?); exit $?' 1 2 13 15
+
+framework_failure=0
+mkdir -p $tmp || framework_failure=1
+cd $tmp || framework_failure=1
+
+if test $framework_failure = 1; then
+ echo "$0: failure in testing framework" 1>&2
+ (exit 1); exit 1
+fi
+
+fail=0
+
+saved_state=`stty -g` || fail=1
+stty $saved_state || fail=1
+
+# Before coreutils-6.10, if stty were given an argument with 35 colons
+# separating 36 hexadecimal strings, stty would fail to diagnose as invalid
+# any number that was out of range as long as sscanf happened to
+# overflow/wrap it back into the range of the corresponding type (either
+# tcflag_t or cc_t).
+
+# For each of the following, before 6.10, stty would fail to
+# diagnose the error on at least Solaris 10.
+hex_2_64=10000000000000000
+stty `echo $saved_state |sed 's/^[^:]*:/'$hex_2_64:/` 2>/dev/null && fail=1
+stty `echo $saved_state |sed 's/:[0-9a-f]*$/:'$hex_2_64/` 2>/dev/null && fail=1
+
+# Just in case either of the above mistakenly succeeds (and changes
+# the state of our tty), try to restore the initial state.
+stty $saved_state || fail=1
+
+(exit $fail); exit $fail