From 074b70de63bbbb5271b8292d0eae995b774d6254 Mon Sep 17 00:00:00 2001 From: huyubiao Date: Tue, 21 Oct 2025 08:47:07 +0800 Subject: [PATCH] coreutils:sync patches from community and fix bugs related to the od --- backport-od-fix-N.-bug.patch | 95 +++++ ...nother-off-by-one-issue-with-strings.patch | 30 ++ ...-integer-overflow-with-large-pseudos.patch | 35 ++ ...-fix-some-unlikely-integer-overflows.patch | 324 ++++++++++++++++++ ...ff-by-one-issues-with-strings-with-N.patch | 202 +++++++++++ coreutils.spec | 10 +- 6 files changed, 695 insertions(+), 1 deletion(-) create mode 100644 backport-od-fix-N.-bug.patch create mode 100644 backport-od-fix-another-off-by-one-issue-with-strings.patch create mode 100644 backport-od-fix-integer-overflow-with-large-pseudos.patch create mode 100644 backport-od-fix-some-unlikely-integer-overflows.patch create mode 100644 backport-od-fix-various-off-by-one-issues-with-strings-with-N.patch diff --git a/backport-od-fix-N.-bug.patch b/backport-od-fix-N.-bug.patch new file mode 100644 index 0000000..171f62e --- /dev/null +++ b/backport-od-fix-N.-bug.patch @@ -0,0 +1,95 @@ +From 66464e61f549e9f2fd35f82567345721798288f9 Mon Sep 17 00:00:00 2001 +From: Paul Eggert +Date: Sat, 28 Jun 2025 17:29:22 -0700 +Subject: [PATCH] od: fix '+N.' bug + +* src/od.c (parse_old_offset): First arg is now char *, +not char const *. If a decimal number, temporarily +modify the string so that xstrtoumax does not complain +about the '.'. +* tests/od/od.pl: Test for the bug. + +Conflict:1.delete NEWS; 2.nullptr to NULL; 3.tests/od/ to tests/misc/ +Reference:https://github.com/coreutils/coreutils/commit/66464e61f549e9f2fd35f82567345721798288f9 + +--- + src/od.c | 31 +++++++++++++++++++++++++++---- + tests/misc/od.pl | 4 ++++ + 3 files changed, 34 insertions(+), 4 deletions(-) + +diff --git a/src/od.c b/src/od.c +index 8bb463ca8..fd5fc45bd 100644 +--- a/src/od.c ++++ b/src/od.c +@@ -1402,7 +1402,7 @@ get_lcm (void) + leading '+' return true and set *OFFSET to the offset it denotes. */ + + static bool +-parse_old_offset (char const *s, uintmax_t *offset) ++parse_old_offset (char *s, uintmax_t *offset) + { + int radix; + +@@ -1414,10 +1414,24 @@ parse_old_offset (char const *s, uintmax_t *offset) + ++s; + + /* Determine the radix we'll use to interpret S. If there is a '.', ++ optionally followed by 'B' or 'b' and then end of string, + it's decimal, otherwise, if the string begins with '0X'or '0x', + it's hexadecimal, else octal. */ +- if (strchr (s, '.') != NULL) +- radix = 10; ++ char *dot = strchr (s, '.'); ++ if (dot) ++ { ++ bool b = dot[1] == 'B' || dot[1] == 'b'; ++ if (dot[b + 1]) ++ dot = NULL; ++ } ++ ++ if (dot) ++ { ++ /* Temporarily remove the '.' from the decimal string. */ ++ dot[0] = dot[1]; ++ dot[1] = '\0'; ++ radix = 10; ++ } + else + { + if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) +@@ -1426,7 +1440,16 @@ parse_old_offset (char const *s, uintmax_t *offset) + radix = 8; + } + +- return xstrtoumax (s, NULL, radix, offset, "Bb") == LONGINT_OK; ++ enum strtol_error s_err = xstrtoumax (s, NULL, radix, offset, "Bb"); ++ ++ if (dot) ++ { ++ /* Restore the decimal string's original value. */ ++ dot[1] = dot[0]; ++ dot[0] = '.'; ++ } ++ ++ return s_err == LONGINT_OK; + } + + /* Read a chunk of size BYTES_PER_BLOCK from the input files, write the +diff --git a/tests/misc/od.pl b/tests/misc/od.pl +index 5bb271e60..9688607c6 100755 +--- a/tests/misc/od.pl ++++ b/tests/misc/od.pl +@@ -60,6 +60,10 @@ my @Tests = + ['j-proc', "-An -c -j $proc_file_byte_count $proc_file", + {IN=>{f2=>'e'}}, {OUT=>" e\n"}], + ++ # Check that the traditional form '+N.' works, as per POSIX. ++ ['trad-dot1', '+1.', {IN_PIPE=>'a'}, {OUT=>"0000001\n"}], ++ ['trad-dot512', '+1.b', {IN_PIPE => 'a' x 512}, {OUT=>"0001000\n"}], ++ + # Ensure that a large width does not cause trouble. + # From coreutils-7.0 through coreutils-8.21, these would print + # approximately 128KiB of padding. +-- +2.43.0 + diff --git a/backport-od-fix-another-off-by-one-issue-with-strings.patch b/backport-od-fix-another-off-by-one-issue-with-strings.patch new file mode 100644 index 0000000..450142a --- /dev/null +++ b/backport-od-fix-another-off-by-one-issue-with-strings.patch @@ -0,0 +1,30 @@ +From 69b07cc58de0a86f7b06d6709049077c6bd486ea Mon Sep 17 00:00:00 2001 +From: Paul Eggert +Date: Sat, 28 Jun 2025 08:07:54 -0700 +Subject: [PATCH] od: fix another off-by-one issue with --strings + +* src/od.c (main): Fix off-by-one error in string_min limit. + +Conflict:1.Adapt Context; 2. 'MIN(IDX_MAX, SIZE_MAX) <= tmp' adapted to 'SIZE_MAX <= tmp' +Reference:https://github.com/coreutils/coreutils/commit/69b07cc58de0a86f7b06d6709049077c6bd486ea + +--- + src/od.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/od.c b/src/od.c +index aaf9572..2c4f8b4 100644 +--- a/src/od.c ++++ b/src/od.c +@@ -1702,7 +1702,7 @@ main (int argc, char **argv) + + /* The minimum string length may be no larger than SIZE_MAX, + since we may allocate a buffer of this size. */ +- if (SIZE_MAX < tmp) ++ if (SIZE_MAX <= tmp) + die (EXIT_FAILURE, 0, _("%s is too large"), quote (optarg)); + + string_min = tmp; +-- +2.43.0 + diff --git a/backport-od-fix-integer-overflow-with-large-pseudos.patch b/backport-od-fix-integer-overflow-with-large-pseudos.patch new file mode 100644 index 0000000..1a91b8b --- /dev/null +++ b/backport-od-fix-integer-overflow-with-large-pseudos.patch @@ -0,0 +1,35 @@ +From d5ea5e8aed304337489a4dbbaf0f00d40bd92fc6 Mon Sep 17 00:00:00 2001 +From: Paul Eggert +Date: Sat, 28 Jun 2025 17:36:04 -0700 +Subject: [PATCH] od: fix integer overflow with large pseudos + +* src/od.c (format_address_label): Diagnose overflow. + +Conflict:1.ckd_add adapt to INT_ADD_WRAPV; 2. intmax_t adapt to uintmax_t +Reference:https://github.com/coreutils/coreutils/commit/d5ea5e8aed304337489a4dbbaf0f00d40bd92fc6 + +--- + src/od.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/src/od.c b/src/od.c +index b3af4c72f..c3c76cc86 100644 +--- a/src/od.c ++++ b/src/od.c +@@ -1227,7 +1227,12 @@ static void + format_address_label (uintmax_t address, char c) + { + format_address_std (address, ' '); +- format_address_paren (address + pseudo_offset, c); ++ ++ uintmax_t addr; ++ if (INT_ADD_WRAPV(address, pseudo_offset, &addr)) ++ error (EXIT_FAILURE, 0, _("pseudo address too large for input")); ++ ++ format_address_paren (addr, c); + } + + /* Write N_BYTES bytes from CURR_BLOCK to standard output once for each +-- +2.43.0 + diff --git a/backport-od-fix-some-unlikely-integer-overflows.patch b/backport-od-fix-some-unlikely-integer-overflows.patch new file mode 100644 index 0000000..3af4862 --- /dev/null +++ b/backport-od-fix-some-unlikely-integer-overflows.patch @@ -0,0 +1,324 @@ +From 88f30ee0a5c355701914d4446dc7ec729a344fa2 Mon Sep 17 00:00:00 2001 +From: Paul Eggert +Date: Wed, 25 Jun 2025 23:22:37 -0700 +Subject: [PATCH] od: fix some unlikely integer overflows + +* src/od.c (print_n_spaces, pad_at, pad_at_overflow): +New static functions. +(struct tspec, PRINT_FIELDS, print_named_ascii, print_ascii) +(decode_one_format, write_block, main): +Use idx_t, not int, for counts that depend on the number +of bytes in an object. +(decode_one_format): Use print_n_spaces to output spaces. +(PRINT_FIELDS, print_named_ascii, print_ascii): +Use pad_at to avoid integer overflow. +(write_block): Do not use %*s to pad, as the total pad might +exceed INT_MAX. Instead, pad by hand with putchar (' '). +(main): Use pad_at_overflow to report integer overflow due to +oversize -w. Use better way to tell whether -w is used, +without needing IF_LINT. +* tests/od/big-w.sh: New test. +* tests/local.mk (all_tests): Add it. + +Conflict:1.delete news; 2.Context Adaptation; 3. ckd_mul adapt to INT_MULTIPLY_WRAPV; 4.`FMT_STRING_DECL` adapt to `char const *FMT_STRING`; 5.Test file path adaptation; 6. idx_t adapt to size_t +Reference:https://github.com/coreutils/coreutils/commit/88f30ee0a5c355701914d4446dc7ec729a344fa2 + +--- + src/od.c | 97 ++++++++++++++++++++++++++++++--------------- + tests/local.mk | 1 + + tests/misc/big-w.sh | 43 ++++++++++++++++++++ + 3 files changed, 108 insertions(+), 33 deletions(-) + create mode 100755 tests/misc/big-w.sh + +diff --git a/src/od.c b/src/od.c +index 2f3113c..fba4a9c 100644 +--- a/src/od.c ++++ b/src/od.c +@@ -107,11 +107,11 @@ struct tspec + leading space, and PAD is total pad to divide among FIELDS. + PAD is at least as large as FIELDS. */ + void (*print_function) (size_t fields, size_t blank, void const *data, +- char const *fmt, int width, int pad); ++ char const *fmt, int width, idx_t pad); + char fmt_string[FMT_BYTES_ALLOCATED]; /* Of the style "%*d". */ + bool hexl_mode_trailer; + int field_width; /* Minimum width of a field, excluding leading space. */ +- int pad_width; /* Total padding to be divided among fields. */ ++ idx_t pad_width; /* Total padding to be divided among fields. */ + }; + + /* Convert the number of 8-bit bytes of a binary representation to +@@ -426,17 +426,45 @@ Binary prefixes can be used, too: KiB=K, MiB=M, and so on.\n\ + + /* Define the print functions. */ + ++/* Print N spaces, where 0 <= N. ++ Do not rely on printf ("%*s", N, "") as N may exceed INT_MAX. */ ++static void ++print_n_spaces (intmax_t n) ++{ ++ for (; 0 < n; n--) ++ putchar (' '); ++} ++ ++/* If there are FIELDS fields, return the total padding up to the ++ start of field I, where I < FIELDS. PAD is the total padding for ++ all fields. The result equals (PAD * I) / FIELDS, except it does ++ not suffer from internal overflow. */ ++static idx_t ++pad_at (idx_t fields, idx_t i, idx_t pad) ++{ ++ /* This implementation assumes that (FIELDS - 1)^2 does not overflow ++ intmax_t, an assumption checked by pad_at_overflow. */ ++ intmax_t m = pad % fields; ++ return pad / fields * i + m * i / fields; ++} ++static bool ++pad_at_overflow (idx_t fields) ++{ ++ intmax_t product; ++ return INT_MULTIPLY_WRAPV(fields - 1, fields - 1, &product); ++} ++ + #define PRINT_FIELDS(N, T, FMT_STRING, ACTION) \ + static void \ + N (size_t fields, size_t blank, void const *block, \ +- char const *FMT_STRING, int width, int pad) \ ++ char const *FMT_STRING, int width, idx_t pad) \ + { \ + T const *p = block; \ + uintmax_t i; \ +- int pad_remaining = pad; \ ++ idx_t pad_remaining = pad; \ + for (i = fields; blank < i; i--) \ + { \ +- int next_pad = pad * (i - 1) / fields; \ ++ idx_t next_pad = pad_at (fields, i - 1, pad); \ + int adjusted_width = pad_remaining - next_pad + width; \ + T x; \ + if (input_swap && sizeof (T) > 1) \ +@@ -498,14 +526,13 @@ dump_hexl_mode_trailer (size_t n_bytes, char const *block) + static void + print_named_ascii (size_t fields, size_t blank, void const *block, + char const *unused_fmt_string _GL_UNUSED, +- int width, int pad) ++ int width, idx_t pad) + { + unsigned char const *p = block; + uintmax_t i; +- int pad_remaining = pad; ++ idx_t pad_remaining = pad; + for (i = fields; blank < i; i--) + { +- int next_pad = pad * (i - 1) / fields; + int masked_c = *p++ & 0x7f; + char const *s; + char buf[2]; +@@ -521,7 +548,9 @@ print_named_ascii (size_t fields, size_t blank, void const *block, + s = buf; + } + +- xprintf ("%*s", pad_remaining - next_pad + width, s); ++ idx_t next_pad = pad_at (fields, i - 1, pad); ++ int adjusted_width = pad_remaining - next_pad + width; ++ xprintf ("%*s", adjusted_width, s); + pad_remaining = next_pad; + } + } +@@ -529,14 +558,13 @@ print_named_ascii (size_t fields, size_t blank, void const *block, + static void + print_ascii (size_t fields, size_t blank, void const *block, + char const *unused_fmt_string _GL_UNUSED, int width, +- int pad) ++ idx_t pad) + { + unsigned char const *p = block; + uintmax_t i; +- int pad_remaining = pad; ++ idx_t pad_remaining = pad; + for (i = fields; blank < i; i--) + { +- int next_pad = pad * (i - 1) / fields; + unsigned char c = *p++; + char const *s; + char buf[4]; +@@ -580,7 +608,9 @@ print_ascii (size_t fields, size_t blank, void const *block, + s = buf; + } + +- xprintf ("%*s", pad_remaining - next_pad + width, s); ++ idx_t next_pad = pad_at (fields, i - 1, pad); ++ int adjusted_width = pad_remaining - next_pad + width; ++ xprintf ("%*s", adjusted_width, s); + pad_remaining = next_pad; + } + } +@@ -638,7 +668,7 @@ decode_one_format (char const *s_orig, char const *s, char const **next, + unsigned long int size; + enum output_format fmt; + void (*print_function) (size_t, size_t, void const *, char const *, +- int, int); ++ int, idx_t); + char const *p; + char c; + int field_width; +@@ -1217,22 +1247,24 @@ write_block (uintmax_t current_offset, size_t n_bytes, + for (size_t i = 0; i < n_specs; i++) + { + int datum_width = width_bytes[spec[i].size]; +- int fields_per_block = bytes_per_block / datum_width; +- int blank_fields = (bytes_per_block - n_bytes) / datum_width; ++ idx_t fields_per_block = bytes_per_block / datum_width; ++ idx_t blank_fields = (bytes_per_block - n_bytes) / datum_width; + if (i == 0) + format_address (current_offset, '\0'); + else +- printf ("%*s", address_pad_len, ""); ++ print_n_spaces (address_pad_len); + (*spec[i].print_function) (fields_per_block, blank_fields, + curr_block, spec[i].fmt_string, + spec[i].field_width, spec[i].pad_width); + if (spec[i].hexl_mode_trailer) + { +- /* space-pad out to full line width, then dump the trailer */ ++ /* Space-pad out to full line width, then dump the trailer. */ + int field_width = spec[i].field_width; +- int pad_width = (spec[i].pad_width * blank_fields +- / fields_per_block); +- printf ("%*s", blank_fields * field_width + pad_width, ""); ++ for (idx_t f = 0; f < blank_fields; f++) ++ print_n_spaces (field_width); ++ idx_t pad_width = pad_at (fields_per_block, blank_fields, ++ spec[i].pad_width); ++ print_n_spaces (pad_width); + dump_hexl_mode_trailer (n_bytes, curr_block); + } + putchar ('\n'); +@@ -1584,9 +1616,8 @@ main (int argc, char **argv) + int n_files; + size_t i; + int l_c_m; +- size_t desired_width IF_LINT ( = 0); ++ size_t desired_width = 0; + bool modern = false; +- bool width_specified = false; + bool ok = true; + size_t width_per_block = 0; + static char const multipliers[] = "bEGKkMmPTYZ0"; +@@ -1777,7 +1808,6 @@ main (int argc, char **argv) + + case 'w': + modern = true; +- width_specified = true; + if (optarg == NULL) + { + desired_width = 32; +@@ -1942,9 +1972,9 @@ main (int argc, char **argv) + /* Compute output block length. */ + l_c_m = get_lcm (); + +- if (width_specified) ++ if (desired_width != 0) + { +- if (desired_width != 0 && desired_width % l_c_m == 0) ++ if (desired_width % l_c_m == 0) + bytes_per_block = desired_width; + else + { +@@ -1964,24 +1994,25 @@ main (int argc, char **argv) + /* Compute padding necessary to align output block. */ + for (i = 0; i < n_specs; i++) + { +- int fields_per_block = bytes_per_block / width_bytes[spec[i].size]; +- int block_width = (spec[i].field_width + 1) * fields_per_block; ++ idx_t fields_per_block = bytes_per_block / width_bytes[spec[i].size]; ++ if (pad_at_overflow (fields_per_block)) ++ error (EXIT_FAILURE, 0, _("%td is too large"), desired_width); ++ idx_t block_width = (spec[i].field_width + 1) * fields_per_block; + if (width_per_block < block_width) + width_per_block = block_width; + } + for (i = 0; i < n_specs; i++) + { +- int fields_per_block = bytes_per_block / width_bytes[spec[i].size]; +- int block_width = spec[i].field_width * fields_per_block; ++ idx_t fields_per_block = bytes_per_block / width_bytes[spec[i].size]; ++ idx_t block_width = spec[i].field_width * fields_per_block; + spec[i].pad_width = width_per_block - block_width; + } + + #ifdef DEBUG +- printf ("lcm=%d, width_per_block=%"PRIuMAX"\n", l_c_m, +- (uintmax_t) width_per_block); ++ printf ("lcm=%d, width_per_block=%td\n", l_c_m, width_per_block); + for (i = 0; i < n_specs; i++) + { +- int fields_per_block = bytes_per_block / width_bytes[spec[i].size]; ++ idx_t fields_per_block = bytes_per_block / width_bytes[spec[i].size]; + assert (bytes_per_block % width_bytes[spec[i].size] == 0); + assert (1 <= spec[i].pad_width / fields_per_block); + printf ("%d: fmt=\"%s\" in_width=%d out_width=%d pad=%d\n", +diff --git a/tests/local.mk b/tests/local.mk +index 532153d..9ea346a 100644 +--- a/tests/local.mk ++++ b/tests/local.mk +@@ -261,6 +261,7 @@ all_tests = \ + tests/misc/xstrtol.pl \ + tests/tail-2/overlay-headers.sh \ + tests/tail-2/pid.sh \ ++ tests/misc/big-w.sh \ + tests/misc/od.pl \ + tests/misc/od-endian.sh \ + tests/misc/od-float.sh \ +diff --git a/tests/misc/big-w.sh b/tests/misc/big-w.sh +new file mode 100755 +index 0000000..27c125c +--- /dev/null ++++ b/tests/misc/big-w.sh +@@ -0,0 +1,43 @@ ++#!/bin/sh ++# Check whether od -wN works with big N ++ ++# Copyright 2025 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=.}/tests/init.sh"; path_prepend_ ./src ++print_ver_ od ++very_expensive_ ++ ++export LC_ALL=C ++ ++cat >exp <<'EOF' || framework_failure_ ++0000000 x >x< ++0000001 ++EOF ++ ++# Try values near sqrt(2**31) and sqrt(2**63). ++for w in 46340 46341 3037000500 3037000501; do ++ printf x | od -w$w -tcz 2>err | tr -s ' ' ' ' >out ++ if test -s err; then ++ test ! -s out || fail=1 ++ else ++ compare exp out || fail=1 ++ outbytes=$(printf x | od -w$w -tcz | wc -c) ++ expbytes=$((4*$w + 21)) ++ test $expbytes -eq $outbytes || fail=1 ++ fi ++done ++ ++Exit $fail +-- +2.43.0 + diff --git a/backport-od-fix-various-off-by-one-issues-with-strings-with-N.patch b/backport-od-fix-various-off-by-one-issues-with-strings-with-N.patch new file mode 100644 index 0000000..76cee7a --- /dev/null +++ b/backport-od-fix-various-off-by-one-issues-with-strings-with-N.patch @@ -0,0 +1,202 @@ +From 44809c3379d64b9e580042124ccea6665d746d9a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A1draig=20Brady?= +Date: Tue, 24 Jun 2025 01:17:12 +0100 +Subject: [PATCH] od: fix various off-by-one issues with --strings with -N + +* src/od.c (dump_strings): There are three related issues here +due to not accounting for the terminating NUL char appropriately. + +1. Ensure BUF always has enough space for the terminating NUL. +This avoids CWE-122: Heap-based Buffer Overflow, +where we wrote a single NUL byte directly after the allocated buffer. +I.e., there should be no buffer overflow with: + printf '%100s' | od -N100 -S1 + +2. Ensure we support -S == -N (END_OFFSET - STRING_MIN == ADDRESS): +I.e., there should be output with: + printf '%100s' | od -N10 -S10 + +3. Ensure we always output a valid address by ensuring +the ADDRESS and I variables are kept in sync. +I.e., this should output address 0000000 not 1777777777777777777777: + printf '%100s' | od -N10 -S1 + +As well as fixing these we simplify by using a single loop +to read the data, rather than two. + +* doc/coreutils.texi (od invocation): Clarify that -N +implicitly NUL terminates strings. +* tests/od/od-N.sh: Add test cases. +* NEWS: Mention the bug fixes. + +Fixes https://bugs.gnu.org/78880 + +Conflict:1.delete news; 2. idx_t adapt to size_t; 3.Test file path adaptation +Reference:https://github.com/coreutils/coreutils/commit/44809c3379d64b9e580042124ccea6665d746d9a + +--- + doc/coreutils.texi | 2 ++ + src/od.c | 56 ++++++++++++++++++---------------------------- + tests/misc/od-N.sh | 29 ++++++++++++++++++++++-- + 3 files changed, 51 insertions(+), 36 deletions(-) + +diff --git a/doc/coreutils.texi b/doc/coreutils.texi +index ceefce9..360a4d6 100644 +--- a/doc/coreutils.texi ++++ b/doc/coreutils.texi +@@ -2036,6 +2036,8 @@ least @var{bytes} consecutive printable characters, + followed by a zero byte (ASCII NUL). + Prefixes and suffixes on @var{bytes} are interpreted as for the + @option{-j} option. ++If combined with the @option{-N} option, truncated strings ++are considered ASCII NUL terminated. + + If @var{bytes} is omitted with @option{--strings}, the default is 3. + +diff --git a/src/od.c b/src/od.c +index 40d8d32..316403e 100644 +--- a/src/od.c ++++ b/src/od.c +@@ -1447,72 +1447,60 @@ dump (void) + } + + /* STRINGS mode. Find each "string constant" in the input. +- A string constant is a run of at least 'string_min' ASCII +- graphic (or formatting) characters terminated by a null. ++ A string constant is a run of at least STRING_MIN ++ printable characters terminated by a NUL or END_OFFSET. + Based on a function written by Richard Stallman for a + traditional version of od. Return true if successful. */ + + static bool + dump_strings (void) + { +- size_t bufsize = MAX (100, string_min); ++ size_t bufsize = MAX (100, string_min + 1); + char *buf = xmalloc (bufsize); + uintmax_t address = n_bytes_to_skip; + bool ok = true; + + while (true) + { +- size_t i; +- int c; +- +- /* See if the next 'string_min' chars are all printing chars. */ +- tryline: ++ size_t i= 0; ++ int c = 1; /* Init to 1 so can distinguish if NUL read. */ + + if (limit_bytes_to_format +- && (end_offset < string_min || end_offset - string_min <= address)) ++ && (end_offset < string_min || end_offset - string_min < address)) + break; + +- for (i = 0; i < string_min; i++) +- { +- ok &= read_char (&c); +- address++; +- if (c < 0) +- { +- free (buf); +- return ok; +- } +- if (! isprint (c)) +- /* Found a non-printing. Try again starting with next char. */ +- goto tryline; +- buf[i] = c; +- } +- +- /* We found a run of 'string_min' printable characters. +- Now see if it is terminated with a null byte. */ ++ /* Store consecutive printable characters to BUF. */ + while (!limit_bytes_to_format || address < end_offset) + { +- if (i == bufsize) ++ if (i == bufsize - 1) + { + buf = X2REALLOC (buf, &bufsize); + } + ok &= read_char (&c); +- address++; + if (c < 0) + { + free (buf); + return ok; + } ++ address++; ++ buf[i++] = c; + if (c == '\0') +- break; /* It is; print this string. */ ++ break; /* Print this string. */ + if (! isprint (c)) +- goto tryline; /* It isn't; give up on this string. */ +- buf[i++] = c; /* String continues; store it all. */ ++ { ++ c = -1; /* Give up on this string. */ ++ break; ++ } + } + +- /* If we get here, the string is all printable and null-terminated, +- so print it. It is all in 'buf' and 'i' is its length. */ ++ if (c == -1 || i - !c < string_min) ++ continue; ++ + buf[i] = 0; +- format_address (address - i - 1, ' '); ++ ++ /* If we get here, the string is all printable, so print it. */ ++ ++ format_address (address - i, ' '); + + for (i = 0; (c = buf[i]); i++) + { +diff --git a/tests/misc/od-N.sh b/tests/misc/od-N.sh +index 8e57fe2..b990212 100755 +--- a/tests/misc/od-N.sh ++++ b/tests/misc/od-N.sh +@@ -20,8 +20,6 @@ + print_ver_ od + + echo abcdefg > in || framework_failure_ +- +- + (od -An -N3 -c; od -An -N3 -c) < in > out + cat < exp || framework_failure_ + a b c +@@ -29,4 +27,31 @@ cat < exp || framework_failure_ + EOF + compare exp out || fail=1 + ++# coreutils <= 9.7 would buffer overflow with ++# a single NUL byte after the heap buffer ++printf '%100s' | od -N100 -S1 > out || fail=1 ++printf '%07o %100s\n' 0 '' > exp || framework_failure_ ++compare exp out || fail=1 ++ ++# coreutils <= 9.7 would output nothing ++printf '%100s' | od -N10 -S10 > out || fail=1 ++printf '%07o %10s\n' 0 '' > exp || framework_failure_ ++compare exp out || fail=1 ++ ++# coreutils <= 9.7 would output an invalid address ++printf '%100s' | od -N10 -S1 > out || fail=1 ++printf '%07o %10s\n' 0 '' > exp || framework_failure_ ++compare exp out || fail=1 ++ ++# Ensure -S limits appropriately ++printf '%10s\000' | od -N11 -S11 > out || fail=1 ++compare /dev/null out || fail=1 ++printf '%10s\000' | od -S11 > out || fail=1 ++compare /dev/null out || fail=1 ++printf '%10s' | od -S10 > out || fail=1 # Ignore unterminated at EOF? ++compare /dev/null out || fail=1 ++printf '\001%10s\000%10s\000' | od -S10 > out || fail=1 ++printf '%07o %10s\n' 1 '' 12 '' > exp || framework_failure_ ++compare exp out || fail=1 ++ + Exit $fail +-- +2.43.0 + diff --git a/coreutils.spec b/coreutils.spec index 7e05454..8ce18ce 100644 --- a/coreutils.spec +++ b/coreutils.spec @@ -1,6 +1,6 @@ Name: coreutils Version: 9.0 -Release: 23 +Release: 24 License: GPLv3+ Summary: A set of basic GNU tools commonly used in shell scripts Url: https://www.gnu.org/software/coreutils/ @@ -69,6 +69,11 @@ Patch54: backport-tests-dd-ensure-posix_fadvise-errors-are-handled.patch Patch55: backport-timeout-ensure-infinitesimal-timeouts-timeout-quickl.patch Patch56: backport-cksum-escape-filenames-with-a-leading-in-check-statu.patch Patch57: backport-cksum-improve-problematic_chars-function.patch +Patch58: backport-od-fix-various-off-by-one-issues-with-strings-with-N.patch +Patch59: backport-od-fix-N.-bug.patch +Patch60: backport-od-fix-another-off-by-one-issue-with-strings.patch +Patch61: backport-od-fix-integer-overflow-with-large-pseudos.patch +Patch62: backport-od-fix-some-unlikely-integer-overflows.patch Patch9001: coreutils-9.0-sw.patch @@ -197,6 +202,9 @@ fi %{_mandir}/man*/* %changelog +* Tue Oct 21 2025 huyubiao - 9.0-24 +- sync patches from community and fix bugs related to the od + * Thu Sep 04 2025 cenhuilin - 9.0-23 - cksum: improve problematic_chars function -- Gitee