backport patches from upstream

This commit is contained in:
panxiaohe 2022-03-29 18:50:31 +08:00
parent 7492b03e4a
commit ac46782ea2
6 changed files with 1014 additions and 1 deletions

View File

@ -0,0 +1,41 @@
From 604f8a6c4d58a646c8722fdf7cad9ee67479d8f7 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Mon, 31 Jan 2022 10:20:21 -0800
Subject: [PATCH] dd: do not access uninitialized
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* src/dd.c (parse_integer): Avoid undefined behavior
that accesses an uninitialized n when e == LONGINT_INVALID.
Return more-accurate error code when INTMAX_MAX < n.
---
src/dd.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/dd.c b/src/dd.c
index e55f87f149..7360a49738 100644
--- a/src/dd.c
+++ b/src/dd.c
@@ -1427,8 +1427,10 @@ static intmax_t
parse_integer (char const *str, strtol_error *invalid)
{
/* Call xstrtoumax, not xstrtoimax, since we don't want to
- allow strings like " -0". */
- uintmax_t n;
+ allow strings like " -0". Initialize N to an interminate value;
+ calling code should not rely on this function returning 0
+ when *INVALID represents a non-overflow error. */
+ uintmax_t n = 0;
char *suffix;
strtol_error e = xstrtoumax (str, &suffix, 10, &n, "bcEGkKMPTwYZ0");
@@ -1468,7 +1470,7 @@ parse_integer (char const *str, strtol_error *invalid)
if (INTMAX_MAX < n)
{
- *invalid = LONGINT_OVERFLOW;
+ *invalid = e | LONGINT_OVERFLOW;
return INTMAX_MAX;
}

View File

@ -0,0 +1,833 @@
From e94d95075dd919e5e6ec0c8ed09477e58b863788 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Tue, 18 Jan 2022 13:22:02 -0800
Subject: [PATCH] dd: improve integer overflow checking
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* src/dd.c: Prefer signed to unsigned types where either will do,
as this helps improve checking with gcc -fsanitize=undefined.
Limit the signed types to their intended ranges.
(MAX_BLOCKSIZE): Dont exceed IDX_MAX - slop either.
(input_offset_overflow): Remove; overflow now denoted by negative.
(parse_integer): Return INTMAX_MAX on overflow, instead of unspecified.
Do not falsely report overflow for 00x99999999999999999999999999999.
* tests/dd/misc.sh: New test for 00xBIG.
* tests/dd/skip-seek-past-file.sh: Adjust to new diagnostic wording.
New test for BIGxBIG.
---
src/dd.c | 298 +++++++++++++++++---------------
tests/dd/misc.sh | 9 +-
tests/dd/skip-seek-past-file.sh | 9 +-
3 files changed, 177 insertions(+), 139 deletions(-)
diff --git a/src/dd.c b/src/dd.c
index 35002f4d2e..bde92e97a4 100644
--- a/src/dd.c
+++ b/src/dd.c
@@ -98,11 +98,12 @@
#define OUTPUT_BLOCK_SLOP (page_size - 1)
/* Maximum blocksize for the given SLOP.
- Keep it smaller than SIZE_MAX - SLOP, so that we can
+ Keep it smaller than MIN (IDX_MAX, SIZE_MAX) - SLOP, so that we can
allocate buffers that size. Keep it smaller than SSIZE_MAX, for
the benefit of system calls like "read". And keep it smaller than
OFF_T_MAX, for the benefit of the large-offset seek code. */
-#define MAX_BLOCKSIZE(slop) MIN (SIZE_MAX - (slop), MIN (SSIZE_MAX, OFF_T_MAX))
+#define MAX_BLOCKSIZE(slop) MIN (MIN (IDX_MAX, SIZE_MAX) - (slop), \
+ MIN (SSIZE_MAX, OFF_T_MAX))
/* Conversions bit masks. */
enum
@@ -148,39 +149,39 @@ static char const *input_file = NULL;
static char const *output_file = NULL;
/* The page size on this host. */
-static size_t page_size;
+static idx_t page_size;
/* The number of bytes in which atomic reads are done. */
-static size_t input_blocksize = 0;
+static idx_t input_blocksize = 0;
/* The number of bytes in which atomic writes are done. */
-static size_t output_blocksize = 0;
+static idx_t output_blocksize = 0;
/* Conversion buffer size, in bytes. 0 prevents conversions. */
-static size_t conversion_blocksize = 0;
+static idx_t conversion_blocksize = 0;
/* Skip this many records of 'input_blocksize' bytes before input. */
-static uintmax_t skip_records = 0;
+static intmax_t skip_records = 0;
/* Skip this many bytes before input in addition of 'skip_records'
records. */
-static size_t skip_bytes = 0;
+static idx_t skip_bytes = 0;
/* Skip this many records of 'output_blocksize' bytes before output. */
-static uintmax_t seek_records = 0;
+static intmax_t seek_records = 0;
/* Skip this many bytes in addition to 'seek_records' records before
output. */
-static uintmax_t seek_bytes = 0;
+static intmax_t seek_bytes = 0;
/* Whether the final output was done with a seek (rather than a write). */
static bool final_op_was_seek;
/* Copy only this many records. The default is effectively infinity. */
-static uintmax_t max_records = (uintmax_t) -1;
+static intmax_t max_records = INTMAX_MAX;
/* Copy this many bytes in addition to 'max_records' records. */
-static size_t max_bytes = 0;
+static idx_t max_bytes = 0;
/* Bit vector of conversions to apply. */
static int conversions_mask = 0;
@@ -196,19 +197,19 @@ static int status_level = STATUS_DEFAULT;
static bool translation_needed = false;
/* Number of partial blocks written. */
-static uintmax_t w_partial = 0;
+static intmax_t w_partial = 0;
/* Number of full blocks written. */
-static uintmax_t w_full = 0;
+static intmax_t w_full = 0;
/* Number of partial blocks read. */
-static uintmax_t r_partial = 0;
+static intmax_t r_partial = 0;
/* Number of full blocks read. */
-static uintmax_t r_full = 0;
+static intmax_t r_full = 0;
/* Number of bytes written. */
-static uintmax_t w_bytes = 0;
+static intmax_t w_bytes = 0;
/* Time that dd started. */
static xtime_t start_time;
@@ -226,16 +227,14 @@ static bool input_seekable;
If ESPIPE, do not issue any more diagnostics about it. */
static int input_seek_errno;
-/* File offset of the input, in bytes, along with a flag recording
- whether it overflowed. */
-static uintmax_t input_offset;
-static bool input_offset_overflow;
+/* File offset of the input, in bytes, or -1 if it overflowed. */
+static off_t input_offset;
/* True if a partial read should be diagnosed. */
static bool warn_partial_read;
/* Records truncated by conv=block. */
-static uintmax_t r_truncate = 0;
+static intmax_t r_truncate = 0;
/* Output representation of newline and space characters.
They change if we're converting to EBCDIC. */
@@ -253,10 +252,10 @@ static char *ibuf;
static char *obuf;
/* Current index into 'obuf'. */
-static size_t oc = 0;
+static idx_t oc = 0;
/* Index into current line, for 'conv=block' and 'conv=unblock'. */
-static size_t col = 0;
+static idx_t col = 0;
/* The set of signals that are caught. */
static sigset_t caught_signals;
@@ -274,7 +273,7 @@ static bool i_nocache, o_nocache;
static bool i_nocache_eof, o_nocache_eof;
/* Function used for read (to handle iflag=fullblock parameter). */
-static ssize_t (*iread_fnc) (int fd, char *buf, size_t size);
+static ssize_t (*iread_fnc) (int fd, char *buf, idx_t size);
/* A longest symbol in the struct symbol_values tables below. */
#define LONGEST_SYMBOL "count_bytes"
@@ -701,11 +700,10 @@ alloc_ibuf (void)
char *buf = malloc (input_blocksize + INPUT_BLOCK_SLOP);
if (!buf)
{
- uintmax_t ibs = input_blocksize;
char hbuf[LONGEST_HUMAN_READABLE + 1];
die (EXIT_FAILURE, 0,
- _("memory exhausted by input buffer of size %"PRIuMAX" bytes (%s)"),
- ibs,
+ _("memory exhausted by input buffer of size %td bytes (%s)"),
+ input_blocksize,
human_readable (input_blocksize, hbuf,
human_opts | human_base_1024, 1, 1));
}
@@ -729,12 +727,11 @@ alloc_obuf (void)
char *buf = malloc (output_blocksize + OUTPUT_BLOCK_SLOP);
if (!buf)
{
- uintmax_t obs = output_blocksize;
char hbuf[LONGEST_HUMAN_READABLE + 1];
die (EXIT_FAILURE, 0,
- _("memory exhausted by output buffer of size %"PRIuMAX
+ _("memory exhausted by output buffer of size %td"
" bytes (%s)"),
- obs,
+ output_blocksize,
human_readable (output_blocksize, hbuf,
human_opts | human_base_1024, 1, 1));
}
@@ -793,8 +790,7 @@ print_xfer_stats (xtime_t progress_time)
if (start_time < now)
{
double XTIME_PRECISIONe0 = XTIME_PRECISION;
- uintmax_t delta_xtime = now;
- delta_xtime -= start_time;
+ xtime_t delta_xtime = now - start_time;
delta_s = delta_xtime / XTIME_PRECISIONe0;
bytes_per_second = human_readable (w_bytes, bpsbuf, human_opts,
XTIME_PRECISION, delta_xtime);
@@ -822,16 +818,16 @@ print_xfer_stats (xtime_t progress_time)
int stats_len
= (abbreviation_lacks_prefix (si)
? fprintf (stderr,
- ngettext ("%"PRIuMAX" byte copied, %s, %s",
- "%"PRIuMAX" bytes copied, %s, %s",
+ ngettext ("%"PRIdMAX" byte copied, %s, %s",
+ "%"PRIdMAX" bytes copied, %s, %s",
select_plural (w_bytes)),
w_bytes, delta_s_buf, bytes_per_second)
: abbreviation_lacks_prefix (iec)
? fprintf (stderr,
- _("%"PRIuMAX" bytes (%s) copied, %s, %s"),
+ _("%"PRIdMAX" bytes (%s) copied, %s, %s"),
w_bytes, si, delta_s_buf, bytes_per_second)
: fprintf (stderr,
- _("%"PRIuMAX" bytes (%s, %s) copied, %s, %s"),
+ _("%"PRIdMAX" bytes (%s, %s) copied, %s, %s"),
w_bytes, si, iec, delta_s_buf, bytes_per_second));
if (progress_time)
@@ -863,14 +859,14 @@ print_stats (void)
}
fprintf (stderr,
- _("%"PRIuMAX"+%"PRIuMAX" records in\n"
- "%"PRIuMAX"+%"PRIuMAX" records out\n"),
+ _("%"PRIdMAX"+%"PRIdMAX" records in\n"
+ "%"PRIdMAX"+%"PRIdMAX" records out\n"),
r_full, r_partial, w_full, w_partial);
if (r_truncate != 0)
fprintf (stderr,
- ngettext ("%"PRIuMAX" truncated record\n",
- "%"PRIuMAX" truncated records\n",
+ ngettext ("%"PRIdMAX" truncated record\n",
+ "%"PRIdMAX" truncated records\n",
select_plural (r_truncate)),
r_truncate);
@@ -1050,7 +1046,9 @@ cache_round (int fd, off_t len)
if (len)
{
- uintmax_t c_pending = *pending + len;
+ intmax_t c_pending;
+ if (INT_ADD_WRAPV (*pending, len, &c_pending))
+ c_pending = INTMAX_MAX;
*pending = c_pending % IO_BUFSIZE;
if (c_pending > *pending)
len = c_pending - *pending;
@@ -1138,7 +1136,7 @@ invalidate_cache (int fd, off_t len)
bytes read if successful, -1 (setting errno) on failure. */
static ssize_t
-iread (int fd, char *buf, size_t size)
+iread (int fd, char *buf, idx_t size)
{
ssize_t nread;
static ssize_t prev_nread;
@@ -1167,11 +1165,11 @@ iread (int fd, char *buf, size_t size)
{
if (0 < prev_nread && prev_nread < size)
{
- uintmax_t prev = prev_nread;
+ idx_t prev = prev_nread;
if (status_level != STATUS_NONE)
- error (0, 0, ngettext (("warning: partial read (%"PRIuMAX" byte); "
+ error (0, 0, ngettext (("warning: partial read (%td byte); "
"suggest iflag=fullblock"),
- ("warning: partial read (%"PRIuMAX" bytes); "
+ ("warning: partial read (%td bytes); "
"suggest iflag=fullblock"),
select_plural (prev)),
prev);
@@ -1185,7 +1183,7 @@ iread (int fd, char *buf, size_t size)
/* Wrapper around iread function to accumulate full blocks. */
static ssize_t
-iread_fullblock (int fd, char *buf, size_t size)
+iread_fullblock (int fd, char *buf, idx_t size)
{
ssize_t nread = 0;
@@ -1209,10 +1207,10 @@ iread_fullblock (int fd, char *buf, size_t size)
this is less than SIZE. Keep trying if there are partial
writes. */
-static size_t
-iwrite (int fd, char const *buf, size_t size)
+static idx_t
+iwrite (int fd, char const *buf, idx_t size)
{
- size_t total_written = 0;
+ idx_t total_written = 0;
if ((output_flags & O_DIRECT) && size < output_blocksize)
{
@@ -1290,7 +1288,7 @@ iwrite (int fd, char const *buf, size_t size)
static void
write_output (void)
{
- size_t nwritten = iwrite (STDOUT_FILENO, obuf, output_blocksize);
+ idx_t nwritten = iwrite (STDOUT_FILENO, obuf, output_blocksize);
w_bytes += nwritten;
if (nwritten != output_blocksize)
{
@@ -1422,7 +1420,7 @@ parse_symbols (char const *str, struct symbol_value const *table,
{
if (! entry->symbol[0])
{
- size_t slen = strcomma ? strcomma - str : strlen (str);
+ idx_t slen = strcomma ? strcomma - str : strlen (str);
error (0, 0, "%s: %s", _(error_msgid),
quotearg_n_style_mem (0, locale_quoting_style, str, slen));
usage (EXIT_FAILURE);
@@ -1443,40 +1441,61 @@ parse_symbols (char const *str, struct symbol_value const *table,
/* Return the value of STR, interpreted as a non-negative decimal integer,
optionally multiplied by various values.
- Set *INVALID to a nonzero error value if STR does not represent a
- number in this format. */
+ If STR does not represent a number in this format,
+ set *INVALID to a nonzero error value and return
+ INTMAX_MAX if it is an overflow, an indeterminate value otherwise. */
-static uintmax_t
+static intmax_t
parse_integer (char const *str, strtol_error *invalid)
{
+ /* Call xstrtoumax, not xstrtoimax, since we don't want to
+ allow strings like " -0". */
uintmax_t n;
char *suffix;
strtol_error e = xstrtoumax (str, &suffix, 10, &n, "bcEGkKMPTwYZ0");
- if (e == LONGINT_INVALID_SUFFIX_CHAR && *suffix == 'x')
+ if ((e & ~LONGINT_OVERFLOW) == LONGINT_INVALID_SUFFIX_CHAR
+ && *suffix == 'x')
{
- uintmax_t multiplier = parse_integer (suffix + 1, invalid);
+ strtol_error invalid2 = LONGINT_OK;
+ intmax_t result = parse_integer (suffix + 1, &invalid2);
+ if ((invalid2 & ~LONGINT_OVERFLOW) != LONGINT_OK)
+ {
+ *invalid = invalid2;
+ return result;
+ }
- if (multiplier != 0 && n * multiplier / multiplier != n)
+ if (INT_MULTIPLY_WRAPV (n, result, &result))
{
*invalid = LONGINT_OVERFLOW;
- return 0;
+ return INTMAX_MAX;
}
- if (n == 0 && STRPREFIX (str, "0x"))
- error (0, 0,
- _("warning: %s is a zero multiplier; "
- "use %s if that is intended"),
- quote_n (0, "0x"), quote_n (1, "00x"));
+ if (result == 0)
+ {
+ if (STRPREFIX (str, "0x"))
+ error (0, 0,
+ _("warning: %s is a zero multiplier; "
+ "use %s if that is intended"),
+ quote_n (0, "0x"), quote_n (1, "00x"));
+ }
+ else if ((e | invalid2) & LONGINT_OVERFLOW)
+ {
+ *invalid = LONGINT_OVERFLOW;
+ return INTMAX_MAX;
+ }
- n *= multiplier;
+ return result;
}
- else if (e != LONGINT_OK)
+
+ if (INTMAX_MAX < n)
{
- *invalid = e;
- return 0;
+ *invalid = LONGINT_OVERFLOW;
+ return INTMAX_MAX;
}
+ if (e != LONGINT_OK)
+ *invalid = e;
return n;
}
@@ -1492,10 +1511,10 @@ operand_is (char const *operand, char const *name)
static void
scanargs (int argc, char *const *argv)
{
- size_t blocksize = 0;
- uintmax_t count = (uintmax_t) -1;
- uintmax_t skip = 0;
- uintmax_t seek = 0;
+ idx_t blocksize = 0;
+ intmax_t count = INTMAX_MAX;
+ intmax_t skip = 0;
+ intmax_t seek = 0;
for (int i = optind; i < argc; i++)
{
@@ -1529,33 +1548,34 @@ scanargs (int argc, char *const *argv)
else
{
strtol_error invalid = LONGINT_OK;
- uintmax_t n = parse_integer (val, &invalid);
- uintmax_t n_min = 0;
- uintmax_t n_max = UINTMAX_MAX;
+ intmax_t n = parse_integer (val, &invalid);
+ intmax_t n_min = 0;
+ intmax_t n_max = INTMAX_MAX;
+ idx_t *converted_idx = NULL;
if (operand_is (name, "ibs"))
{
n_min = 1;
n_max = MAX_BLOCKSIZE (INPUT_BLOCK_SLOP);
- input_blocksize = n;
+ converted_idx = &input_blocksize;
}
else if (operand_is (name, "obs"))
{
n_min = 1;
n_max = MAX_BLOCKSIZE (OUTPUT_BLOCK_SLOP);
- output_blocksize = n;
+ converted_idx = &output_blocksize;
}
else if (operand_is (name, "bs"))
{
n_min = 1;
n_max = MAX_BLOCKSIZE (INPUT_BLOCK_SLOP);
- blocksize = n;
+ converted_idx = &blocksize;
}
else if (operand_is (name, "cbs"))
{
n_min = 1;
- n_max = SIZE_MAX;
- conversion_blocksize = n;
+ n_max = MIN (SIZE_MAX, IDX_MAX);
+ converted_idx = &conversion_blocksize;
}
else if (operand_is (name, "skip"))
skip = n;
@@ -1578,6 +1598,8 @@ scanargs (int argc, char *const *argv)
if (invalid != LONGINT_OK)
die (EXIT_FAILURE, invalid == LONGINT_OVERFLOW ? EOVERFLOW : 0,
"%s: %s", _("invalid number"), quote (val));
+ else if (converted_idx)
+ *converted_idx = n;
}
}
@@ -1628,12 +1650,12 @@ scanargs (int argc, char *const *argv)
else if (skip != 0)
skip_records = skip;
- if (input_flags & O_COUNT_BYTES && count != (uintmax_t) -1)
+ if (input_flags & O_COUNT_BYTES && count != INTMAX_MAX)
{
max_records = count / input_blocksize;
max_bytes = count % input_blocksize;
}
- else if (count != (uintmax_t) -1)
+ else if (count != INTMAX_MAX)
max_records = count;
if (output_flags & O_SEEK_BYTES && seek != 0)
@@ -1651,7 +1673,7 @@ scanargs (int argc, char *const *argv)
warn_partial_read =
(! (conversions_mask & C_TWOBUFS) && ! (input_flags & O_FULLBLOCK)
&& (skip_records
- || (0 < max_records && max_records < (uintmax_t) -1)
+ || (0 < max_records && max_records < INTMAX_MAX)
|| (input_flags | output_flags) & O_DIRECT));
iread_fnc = ((input_flags & O_FULLBLOCK)
@@ -1726,9 +1748,9 @@ apply_translations (void)
to the NREAD bytes in BUF. */
static void
-translate_buffer (char *buf, size_t nread)
+translate_buffer (char *buf, idx_t nread)
{
- size_t i;
+ idx_t i;
char *cp;
for (i = nread, cp = buf; i; i--, cp++)
*cp = trans_table[to_uchar (*cp)];
@@ -1746,7 +1768,7 @@ static char saved_char;
next call. Return the new start of the BUF buffer. */
static char *
-swab_buffer (char *buf, size_t *nread)
+swab_buffer (char *buf, idx_t *nread)
{
char *bufstart = buf;
@@ -1770,7 +1792,7 @@ swab_buffer (char *buf, size_t *nread)
toward the beginning. This way we only move half of the data. */
char *cp = bufstart + *nread; /* Start one char past the last. */
- for (size_t i = *nread / 2; i; i--, cp -= 2)
+ for (idx_t i = *nread >> 1; i; i--, cp -= 2)
*cp = *(cp - 2);
return ++bufstart;
@@ -1780,11 +1802,10 @@ swab_buffer (char *buf, size_t *nread)
necessary. */
static void
-advance_input_offset (uintmax_t offset)
+advance_input_offset (intmax_t offset)
{
- input_offset += offset;
- if (input_offset < offset)
- input_offset_overflow = true;
+ if (0 <= input_offset && INT_ADD_WRAPV (input_offset, offset, &input_offset))
+ input_offset = -1;
}
/* Throw away RECORDS blocks of BLOCKSIZE bytes plus BYTES bytes on
@@ -1796,18 +1817,18 @@ advance_input_offset (uintmax_t offset)
reached. If FDESC is STDOUT_FILENO, on return, BYTES is the
remaining bytes in addition to the remaining records. */
-static uintmax_t
-skip (int fdesc, char const *file, uintmax_t records, size_t blocksize,
- size_t *bytes)
+static intmax_t
+skip (int fdesc, char const *file, intmax_t records, idx_t blocksize,
+ idx_t *bytes)
{
- uintmax_t offset = records * blocksize + *bytes;
-
/* Try lseek and if an error indicates it was an inappropriate operation --
or if the file offset is not representable as an off_t --
fall back on using read. */
errno = 0;
- if (records <= OFF_T_MAX / blocksize
+ off_t offset;
+ if (! INT_MULTIPLY_WRAPV (records, blocksize, &offset)
+ && ! INT_ADD_WRAPV (offset, *bytes, &offset)
&& 0 <= lseek (fdesc, offset, SEEK_CUR))
{
if (fdesc == STDIN_FILENO)
@@ -1815,7 +1836,8 @@ skip (int fdesc, char const *file, uintmax_t records, size_t blocksize,
struct stat st;
if (ifstat (STDIN_FILENO, &st) != 0)
die (EXIT_FAILURE, errno, _("cannot fstat %s"), quoteaf (file));
- if (usable_st_size (&st) && st.st_size < input_offset + offset)
+ if (usable_st_size (&st) && 0 <= input_offset
+ && st.st_size - input_offset < offset)
{
/* When skipping past EOF, return the number of _full_ blocks
* that are not skipped, and set offset to EOF, so the caller
@@ -1920,7 +1942,7 @@ skip (int fdesc, char const *file, uintmax_t records, size_t blocksize,
be seekable. */
static bool
-advance_input_after_read_error (size_t nbytes)
+advance_input_after_read_error (idx_t nbytes)
{
if (! input_seekable)
{
@@ -1932,8 +1954,7 @@ advance_input_after_read_error (size_t nbytes)
{
off_t offset;
advance_input_offset (nbytes);
- input_offset_overflow |= (OFF_T_MAX < input_offset);
- if (input_offset_overflow)
+ if (input_offset < 0)
{
error (0, 0, _("offset overflow while reading file %s"),
quoteaf (input_file));
@@ -1962,13 +1983,13 @@ advance_input_after_read_error (size_t nbytes)
/* Copy NREAD bytes of BUF, with no conversions. */
static void
-copy_simple (char const *buf, size_t nread)
+copy_simple (char const *buf, idx_t nread)
{
char const *start = buf; /* First uncopied char in BUF. */
do
{
- size_t nfree = MIN (nread, output_blocksize - oc);
+ idx_t nfree = MIN (nread, output_blocksize - oc);
memcpy (obuf + oc, start, nfree);
@@ -1986,15 +2007,15 @@ copy_simple (char const *buf, size_t nread)
replacing the newline with trailing spaces). */
static void
-copy_with_block (char const *buf, size_t nread)
+copy_with_block (char const *buf, idx_t nread)
{
- for (size_t i = nread; i; i--, buf++)
+ for (idx_t i = nread; i; i--, buf++)
{
if (*buf == newline_character)
{
if (col < conversion_blocksize)
{
- size_t j;
+ idx_t j;
for (j = col; j < conversion_blocksize; j++)
output_char (space_character);
}
@@ -2016,11 +2037,11 @@ copy_with_block (char const *buf, size_t nread)
with a newline). */
static void
-copy_with_unblock (char const *buf, size_t nread)
+copy_with_unblock (char const *buf, idx_t nread)
{
- static size_t pending_spaces = 0;
+ static idx_t pending_spaces = 0;
- for (size_t i = 0; i < nread; i++)
+ for (idx_t i = 0; i < nread; i++)
{
char c = buf[i];
@@ -2104,10 +2125,10 @@ dd_copy (void)
/* If nonzero, then the previously read block was partial and
PARTREAD was its size. */
- size_t partread = 0;
+ idx_t partread = 0;
int exit_status = EXIT_SUCCESS;
- size_t n_bytes_read;
+ idx_t n_bytes_read;
/* Leave at least one extra byte at the beginning and end of 'ibuf'
for conv=swab, but keep the buffer address even. But some peculiar
@@ -2128,11 +2149,13 @@ dd_copy (void)
if (skip_records != 0 || skip_bytes != 0)
{
- uintmax_t us_bytes = input_offset + (skip_records * input_blocksize)
- + skip_bytes;
- uintmax_t us_blocks = skip (STDIN_FILENO, input_file,
- skip_records, input_blocksize, &skip_bytes);
- us_bytes -= input_offset;
+ intmax_t us_bytes;
+ bool us_bytes_overflow =
+ (INT_MULTIPLY_WRAPV (skip_records, input_blocksize, &us_bytes)
+ || INT_ADD_WRAPV (skip_bytes, us_bytes, &us_bytes));
+ off_t input_offset0 = input_offset;
+ intmax_t us_blocks = skip (STDIN_FILENO, input_file,
+ skip_records, input_blocksize, &skip_bytes);
/* POSIX doesn't say what to do when dd detects it has been
asked to skip past EOF, so I assume it's non-fatal.
@@ -2140,7 +2163,10 @@ dd_copy (void)
1. file is too small
2. pipe has not enough data
3. partial reads */
- if ((us_blocks || (!input_offset_overflow && us_bytes))
+ if ((us_blocks
+ || (0 <= input_offset
+ && (us_bytes_overflow
+ || us_bytes != input_offset - input_offset0)))
&& status_level != STATUS_NONE)
{
error (0, 0,
@@ -2150,8 +2176,8 @@ dd_copy (void)
if (seek_records != 0 || seek_bytes != 0)
{
- size_t bytes = seek_bytes;
- uintmax_t write_records = skip (STDOUT_FILENO, output_file,
+ idx_t bytes = seek_bytes;
+ intmax_t write_records = skip (STDOUT_FILENO, output_file,
seek_records, output_blocksize, &bytes);
if (write_records != 0 || bytes != 0)
@@ -2160,7 +2186,7 @@ dd_copy (void)
do
{
- size_t size = write_records ? output_blocksize : bytes;
+ idx_t size = write_records ? output_blocksize : bytes;
if (iwrite (STDOUT_FILENO, obuf, size) != size)
{
error (0, errno, _("writing to %s"), quoteaf (output_file));
@@ -2230,7 +2256,7 @@ dd_copy (void)
if (conversions_mask & C_NOERROR)
{
print_stats ();
- size_t bad_portion = input_blocksize - partread;
+ idx_t bad_portion = input_blocksize - partread;
/* We already know this data is not cached,
but call this so that correct offsets are maintained. */
@@ -2284,7 +2310,7 @@ dd_copy (void)
if (ibuf == obuf) /* If not C_TWOBUFS. */
{
- size_t nwritten = iwrite (STDOUT_FILENO, obuf, n_bytes_read);
+ idx_t nwritten = iwrite (STDOUT_FILENO, obuf, n_bytes_read);
w_bytes += nwritten;
if (nwritten != n_bytes_read)
{
@@ -2331,7 +2357,7 @@ dd_copy (void)
{
/* If the final input line didn't end with a '\n', pad
the output block to 'conversion_blocksize' chars. */
- for (size_t i = col; i < conversion_blocksize; i++)
+ for (idx_t i = col; i < conversion_blocksize; i++)
output_char (space_character);
}
@@ -2344,7 +2370,7 @@ dd_copy (void)
/* Write out the last block. */
if (oc != 0)
{
- size_t nwritten = iwrite (STDOUT_FILENO, obuf, oc);
+ idx_t nwritten = iwrite (STDOUT_FILENO, obuf, oc);
w_bytes += nwritten;
if (nwritten != 0)
w_partial++;
@@ -2477,15 +2503,14 @@ main (int argc, char **argv)
if (seek_records != 0 && !(conversions_mask & C_NOTRUNC))
{
- uintmax_t size = seek_records * output_blocksize + seek_bytes;
- unsigned long int obs = output_blocksize;
-
- if (OFF_T_MAX / output_blocksize < seek_records)
+ off_t size;
+ if (INT_MULTIPLY_WRAPV (seek_records, output_blocksize, &size)
+ || INT_ADD_WRAPV (seek_bytes, size, &size))
die (EXIT_FAILURE, 0,
_("offset too large: "
- "cannot truncate to a length of seek=%"PRIuMAX""
- " (%lu-byte) blocks"),
- seek_records, obs);
+ "cannot truncate to a length of seek=%"PRIdMAX""
+ " (%td-byte) blocks"),
+ seek_records, output_blocksize);
if (iftruncate (STDOUT_FILENO, size) != 0)
{
@@ -2502,10 +2527,13 @@ main (int argc, char **argv)
if (S_ISREG (stdout_stat.st_mode)
|| S_ISDIR (stdout_stat.st_mode)
|| S_TYPEISSHM (&stdout_stat))
- die (EXIT_FAILURE, ftruncate_errno,
- _("failed to truncate to %"PRIuMAX" bytes"
- " in output file %s"),
- size, quoteaf (output_file));
+ {
+ intmax_t isize = size;
+ die (EXIT_FAILURE, ftruncate_errno,
+ _("failed to truncate to %"PRIdMAX" bytes"
+ " in output file %s"),
+ isize, quoteaf (output_file));
+ }
}
}
}
diff --git a/tests/dd/misc.sh b/tests/dd/misc.sh
index 6ca54faac3..d20cbacc87 100755
--- a/tests/dd/misc.sh
+++ b/tests/dd/misc.sh
@@ -19,6 +19,7 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ dd
+export LC_ALL=C
tmp_in=dd-in
tmp_in2=dd-in2
@@ -98,7 +99,7 @@ test "$outbytes" -eq 3 || fail=1
# A delay is required to trigger a failure.
# There might be some missed failures but it's unlikely.
(echo a; sleep .1; echo b) \
- | env LC_ALL=C dd bs=4 status=noxfer iflag=fullblock >out 2>err || fail=1
+ | dd bs=4 status=noxfer iflag=fullblock >out 2>err || fail=1
printf 'a\nb\n' > out_ok || framework_failure_
echo "1+0 records in
1+0 records out" > err_ok || framework_failure_
@@ -116,5 +117,11 @@ dd: warning: '0x' is a zero multiplier; use '00x' if that is intended
EOF
compare exp err || fail=1
+echo "0+0 records in
+0+0 records out" >err_ok || framework_failure_
+big=9999999999999999999999999999999999999999999999999999999999999
+dd if=$tmp_in of=$tmp_out count=00x$big status=noxfer 2>err || fail=1
+compare /dev/null $tmp_out || fail=1
+compare err_ok err || fail=1
Exit $fail
diff --git a/tests/dd/skip-seek-past-file.sh b/tests/dd/skip-seek-past-file.sh
index 7c2baa2e1a..e952448e2b 100755
--- a/tests/dd/skip-seek-past-file.sh
+++ b/tests/dd/skip-seek-past-file.sh
@@ -20,7 +20,7 @@
print_ver_ dd
require_sparse_support_ # for 'truncate --size=$OFF_T_MAX'
eval $(getlimits) # for OFF_T limits
-
+export LC_ALL=C
printf "1234" > file || framework_failure_
@@ -65,8 +65,11 @@ compare err_ok err || fail=1
# skipping > OFF_T_MAX should fail immediately
dd bs=1 skip=$OFF_T_OFLOW count=0 status=noxfer < file 2> err && fail=1
-# error message should be "... cannot skip: strerror(EOVERFLOW)"
-grep "cannot skip:" err >/dev/null || fail=1
+# error message should be "... invalid number: strerror(EOVERFLOW)"
+grep "invalid number:" err >/dev/null || fail=1
+dd bs=1 skip=${OFF_T_OFLOW}x$OFF_T_OFLOW count=0 status=noxfer < file 2> err &&
+ fail=1
+grep "invalid number:" err >/dev/null || fail=1
# skipping > max file size should fail immediately
if ! truncate --size=$OFF_T_MAX in 2>/dev/null; then

View File

@ -0,0 +1,51 @@
From fb7579768d688a300c4ac76451e1fc7cad59e3e8 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Mon, 31 Jan 2022 19:52:43 -0800
Subject: [PATCH] df: fix memory leak
* src/df.c (devlist_free): Remove.
(filter_mount_list): Free all of devlist, instead of merely
the entries in devlist_table.
---
src/df.c | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/src/df.c b/src/df.c
index 7d32078071..4b2cfb77a6 100644
--- a/src/df.c
+++ b/src/df.c
@@ -710,12 +710,6 @@ devlist_for_dev (dev_t dev)
return found->seen_last;
}
-static void
-devlist_free (void *p)
-{
- free (p);
-}
-
/* Filter mount list by skipping duplicate entries.
In the case of duplicates - based on the device number - the mount entry
with a '/' in its me_devname (i.e., not pseudo name like tmpfs) wins.
@@ -736,9 +730,7 @@ filter_mount_list (bool devices_only)
mount_list_size++;
devlist_table = hash_initialize (mount_list_size, NULL,
- devlist_hash,
- devlist_compare,
- devlist_free);
+ devlist_hash, devlist_compare, NULL);
if (devlist_table == NULL)
xalloc_die ();
@@ -845,7 +837,9 @@ filter_mount_list (bool devices_only)
me = device_list->me;
me->me_next = mount_list;
mount_list = me;
- device_list = device_list->next;
+ struct devlist *next = device_list->next;
+ free (device_list);
+ device_list = next;
}
hash_free (devlist_table);

View File

@ -0,0 +1,32 @@
From 85c975df2c25bd799370b04bb294e568e001102f Mon Sep 17 00:00:00 2001
From: Rohan Sable <rsable@redhat.com>
Date: Mon, 7 Mar 2022 14:14:13 +0000
Subject: [PATCH] ls: avoid triggering automounts
statx() has different defaults wrt automounting
compared to stat() or lstat(), so explicitly
set the AT_NO_AUTOMOUNT flag to suppress that behavior,
and avoid unintended operations or potential errors.
* src/ls.c (do_statx): Pass AT_NO_AUTOMOUNT to avoid this behavior.
* NEWS: Mention the change in behavior.
Fixes https://bugs.gnu.org/54286
Signed-off-by: Rohan Sable <rsable@redhat.com>
---
src/ls.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/ls.c b/src/ls.c
index 1930e4abbc..255789061b 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -1177,7 +1177,7 @@ do_statx (int fd, char const *name, struct stat *st, int flags,
{
struct statx stx;
bool want_btime = mask & STATX_BTIME;
- int ret = statx (fd, name, flags, mask, &stx);
+ int ret = statx (fd, name, flags | AT_NO_AUTOMOUNT, mask, &stx);
if (ret >= 0)
{
statx_to_stat (&stx, st);

View File

@ -0,0 +1,44 @@
From 92cb8427c537f37edd43c5cef1909585201372ab Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <P@draigBrady.com>
Date: Mon, 7 Mar 2022 23:29:20 +0000
Subject: [PATCH] stat: only automount with --cached=never
Revert to the default behavior before the introduction of statx().
* src/stat.c (do_stat): Set AT_NO_AUTOMOUNT without --cached=never.
* doc/coreutils.texi (stat invocation): Mention the automount
behavior with --cached=never.
* NEWS: Mention the change in behavior.
Fixes https://bugs.gnu.org/54287
---
doc/coreutils.texi | 1 +
src/stat.c | 3 +++
2 files changed, 4 insertions(+)
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index e9be0993ac..05dc5ee21f 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -12608,6 +12608,7 @@ Always read the already cached attributes if available.
@item never
Always sychronize with the latest file system attributes.
+This also mounts automounted files.
@item default
Leave the caching behavior to the underlying file system.
diff --git a/src/stat.c b/src/stat.c
index edafd02854..3765a8f65a 100644
--- a/src/stat.c
+++ b/src/stat.c
@@ -1394,6 +1394,9 @@ do_stat (char const *filename, char const *format, char const *format2)
else if (force_sync)
flags |= AT_STATX_FORCE_SYNC;
+ if (! force_sync)
+ flags |= AT_NO_AUTOMOUNT;
+
fd = statx (fd, pathname, flags, format_to_mask (format), &stx);
if (fd < 0)
{

View File

@ -1,6 +1,6 @@
Name: coreutils
Version: 9.0
Release: 2
Release: 3
License: GPLv3+
Summary: A set of basic GNU tools commonly used in shell scripts
Url: https://www.gnu.org/software/coreutils/
@ -21,6 +21,11 @@ Patch5: bugfix-selinux-flask.patch
Patch6: skip-the-tests-that-require-selinux-if-selinux-is-di.patch
Patch7: backport-chmod-fix-exit-status-when-ignoring-symlinks.patch
Patch8: backport-timeout-ensure-foreground-k-exits-with-status-137.patch
Patch9: backport-dd-improve-integer-overflow-checking.patch
Patch10: backport-dd-do-not-access-uninitialized.patch
Patch11: backport-df-fix-memory-leak.patch
Patch12: backport-ls-avoid-triggering-automounts.patch
Patch13: backport-stat-only-automount-with-cached-never.patch
Conflicts: filesystem < 3
# To avoid clobbering installs
@ -135,6 +140,13 @@ fi
%{_mandir}/man*/*
%changelog
* Tue Mar 29 2022 panxiaohe <panxh.life@foxmail.com> - 9.0-3
- dd: improve integer overflow checking
- dd: do not access uninitialized
- df: fix memory leak
- ls: avoid triggering automounts
- stat: only automount with --cached=never
* Sat Feb 12 2022 yangzhuangzhuang <yangzhuangzhuang1@h-partners.com> - 9.0-2
- timeout: ensure --foreground -k exits with status 137