From e8e81fc44b9cf5fa4c13fa8b2824278b75566398 Mon Sep 17 00:00:00 2001 From: =?utf8?q?P=C3=A1draig=20Brady?=
Date: Sat, 10 Jun 2023 14:18:00 +0100 Subject: [PATCH] dd: fix parsing of numbers with more than two multipliers * src/dd.c (parse_integer): Use recursion to support more than two multipliers. Also protect suffix[-1] access to ensure we don't inspect before the passed string. * tests/dd/bytes.sh: Add test cases. * doc/coreutils.texi (dd invocation): Note the support for specifying many multipliers in a number. * NEWS: Mention the bug fix. Fixes https://bugs.debian.org/1037275 --- NEWS | 4 ++++ doc/coreutils.texi | 2 +- src/dd.c | 8 ++++---- tests/dd/bytes.sh | 12 ++++++++++++ 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index e47701962a..7df9ff5b01 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,10 @@ GNU coreutils NEWS -*- outline -*- cksum again diagnoses read errors in its default CRC32 mode. [bug introduced in coreutils-9.0] + dd again supports more than two multipliers for numbers. + Previously numbers of the form '1024x1024x32' gave "invalid number" errors. + [bug introduced in coreutils-9.1] + factor, numfmt, and tsort now diagnose read errors on the input. [This bug was present in "the beginning".] diff --git a/doc/coreutils.texi b/doc/coreutils.texi index e9d7b8eb49..d6918e8ad5 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -9818,7 +9818,7 @@ can be followed by a multiplier: @samp{b}=512, @samp{c}=1, standard block size suffixes like @samp{k}=1024 (@pxref{Block size}). These multipliers are GNU extensions to POSIX, except that POSIX allows @var{bytes} to be followed by @samp{k}, @samp{b}, and -@samp{x@var{m}}. +@samp{x@var{m}}. Note @samp{x@var{m}} can be used more than once in a number. Block sizes (i.e., specified by @var{bytes} strings) must be nonzero. Any block size you specify via @samp{bs=}, @samp{ibs=}, @samp{obs=}, @samp{cbs=} diff --git a/src/dd.c b/src/dd.c index 665fc831c5..f06d4eba2b 100644 --- a/src/dd.c +++ b/src/dd.c @@ -1428,7 +1428,7 @@ parse_integer (char const *str, strtol_error *invalid) intmax_t result; if ((e & ~LONGINT_OVERFLOW) == LONGINT_INVALID_SUFFIX_CHAR - && suffix[-1] != 'B' && *suffix == 'B') + && *suffix == 'B' && str < suffix && suffix[-1] != 'B') { suffix++; if (!*suffix) @@ -1436,10 +1436,10 @@ parse_integer (char const *str, strtol_error *invalid) } if ((e & ~LONGINT_OVERFLOW) == LONGINT_INVALID_SUFFIX_CHAR - && *suffix == 'x' && ! (suffix[-1] == 'B' && strchr (suffix + 1, 'B'))) + && *suffix == 'x') { - uintmax_t o; - strtol_error f = xstrtoumax (suffix + 1, &suffix, 10, &o, suffixes); + strtol_error f = LONGINT_OK; + intmax_t o = parse_integer (suffix + 1, &f); if ((f & ~LONGINT_OVERFLOW) != LONGINT_OK) { e = f; diff --git a/tests/dd/bytes.sh b/tests/dd/bytes.sh index 01753d6a0e..d6105ccfda 100755 --- a/tests/dd/bytes.sh +++ b/tests/dd/bytes.sh @@ -60,4 +60,16 @@ for operands in "oseek=8B" "seek=8 oflag=seek_bytes"; do compare expected2 out2 || fail=1 done +# Check recursive integer parsing +for oseek in '1x2x4 oflag=seek_bytes' '1Bx2x4' '1Bx8' '2Bx4B' '2x4B'; do + # seek bytes + echo abcdefghijklm | + dd oseek=$oseek bs=5 > out 2> /dev/null || fail=1 + compare expected out || fail=1 +done + +# Negative checks for integer parsing +for count in B B1 Bx1 KBB BB KBb KBx x1 1x 1xx1; do + returns_ 1 dd count=$count /dev/null || fail=1 +done Exit $fail -- 2.47.2