From ac46782ea2d165a21dc285ac23e347707c70a171 Mon Sep 17 00:00:00 2001 From: panxiaohe Date: Tue, 29 Mar 2022 18:50:31 +0800 Subject: [PATCH] backport patches from upstream --- backport-dd-do-not-access-uninitialized.patch | 41 + ...dd-improve-integer-overflow-checking.patch | 833 ++++++++++++++++++ backport-df-fix-memory-leak.patch | 51 ++ backport-ls-avoid-triggering-automounts.patch | 32 + ...tat-only-automount-with-cached-never.patch | 44 + coreutils.spec | 14 +- 6 files changed, 1014 insertions(+), 1 deletion(-) create mode 100644 backport-dd-do-not-access-uninitialized.patch create mode 100644 backport-dd-improve-integer-overflow-checking.patch create mode 100644 backport-df-fix-memory-leak.patch create mode 100644 backport-ls-avoid-triggering-automounts.patch create mode 100644 backport-stat-only-automount-with-cached-never.patch diff --git a/backport-dd-do-not-access-uninitialized.patch b/backport-dd-do-not-access-uninitialized.patch new file mode 100644 index 0000000..b4860ba --- /dev/null +++ b/backport-dd-do-not-access-uninitialized.patch @@ -0,0 +1,41 @@ +From 604f8a6c4d58a646c8722fdf7cad9ee67479d8f7 Mon Sep 17 00:00:00 2001 +From: Paul Eggert +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; + } + diff --git a/backport-dd-improve-integer-overflow-checking.patch b/backport-dd-improve-integer-overflow-checking.patch new file mode 100644 index 0000000..3fc5f01 --- /dev/null +++ b/backport-dd-improve-integer-overflow-checking.patch @@ -0,0 +1,833 @@ +From e94d95075dd919e5e6ec0c8ed09477e58b863788 Mon Sep 17 00:00:00 2001 +From: Paul Eggert +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): Don’t 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 diff --git a/backport-df-fix-memory-leak.patch b/backport-df-fix-memory-leak.patch new file mode 100644 index 0000000..83a43b6 --- /dev/null +++ b/backport-df-fix-memory-leak.patch @@ -0,0 +1,51 @@ +From fb7579768d688a300c4ac76451e1fc7cad59e3e8 Mon Sep 17 00:00:00 2001 +From: Paul Eggert +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); diff --git a/backport-ls-avoid-triggering-automounts.patch b/backport-ls-avoid-triggering-automounts.patch new file mode 100644 index 0000000..3a7bbbf --- /dev/null +++ b/backport-ls-avoid-triggering-automounts.patch @@ -0,0 +1,32 @@ +From 85c975df2c25bd799370b04bb294e568e001102f Mon Sep 17 00:00:00 2001 +From: Rohan Sable +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 +--- + 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); diff --git a/backport-stat-only-automount-with-cached-never.patch b/backport-stat-only-automount-with-cached-never.patch new file mode 100644 index 0000000..0c7df8b --- /dev/null +++ b/backport-stat-only-automount-with-cached-never.patch @@ -0,0 +1,44 @@ +From 92cb8427c537f37edd43c5cef1909585201372ab Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A1draig=20Brady?= +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) + { diff --git a/coreutils.spec b/coreutils.spec index 5b0b89e..80a544d 100644 --- a/coreutils.spec +++ b/coreutils.spec @@ -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 - 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 - 9.0-2 - timeout: ensure --foreground -k exits with status 137 -- Gitee