Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package cpio for openSUSE:Factory checked in at 2026-08-27 18:48:40 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/cpio (Old) and /work/SRC/openSUSE:Factory/.cpio.new.1265 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "cpio" Thu Aug 27 18:48:40 2026 rev:73 rq:1373823 version:2.15 Changes: -------- --- /work/SRC/openSUSE:Factory/cpio/cpio.changes 2026-03-06 18:18:16.843380145 +0100 +++ /work/SRC/openSUSE:Factory/.cpio.new.1265/cpio.changes 2026-08-27 18:48:41.975984622 +0200 @@ -1,0 +2,23 @@ +Mon Aug 24 13:38:25 UTC 2026 - Antonio Teixeira <[email protected]> + +- Fix CVE-2026-66484: path traversal allows creating hard links outside + intended directory via malicious tar archives (bsc#1274856) + * CVE-2026-66484.patch +- Fix CVE-2026-66485: denial of service via uncontrolled memory allocation + from crafted archives (bsc#1274857) + * CVE-2026-66485.patch +- Fix CVE-2026-66486: terminal control sequence injection via crafted + archive member names (bsc#1274858) + * CVE-2026-66486.patch +- Refresh patches to apply with -p1: + * cpio-close_files_after_copy.patch + * cpio-default_tape_dev.patch + * cpio-dev_number.patch + * cpio-eof_tape_handling.patch + * cpio-open_nonblock.patch + * cpio-use_new_ascii_format.patch + * cpio-use_sbin_rmt.patch +- Reorder patches, apply with %autosetup -p1 +- Add makeinfo build requirement + +------------------------------------------------------------------- New: ---- CVE-2026-66484.patch CVE-2026-66485.patch CVE-2026-66486.patch ----------(New B)---------- New: intended directory via malicious tar archives (bsc#1274856) * CVE-2026-66484.patch - Fix CVE-2026-66485: denial of service via uncontrolled memory allocation New: from crafted archives (bsc#1274857) * CVE-2026-66485.patch - Fix CVE-2026-66486: terminal control sequence injection via crafted New: archive member names (bsc#1274858) * CVE-2026-66486.patch - Refresh patches to apply with -p1: ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ cpio.spec ++++++ --- /var/tmp/diff_new_pack.qevGYI/_old 2026-08-27 18:48:43.258028917 +0200 +++ /var/tmp/diff_new_pack.qevGYI/_new 2026-08-27 18:48:43.261029022 +0200 @@ -26,24 +26,34 @@ Source0: https://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.bz2 Source1: https://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.bz2.sig Source2: https://savannah.gnu.org/project/memberlist-gpgkeys.php?group=%{name}&download=1#/%{name}.keyring -Patch2: cpio-use_new_ascii_format.patch -Patch4: cpio-use_sbin_rmt.patch -#PATCH-FIX-UPSTREAM cpio-2.12 cpio-open_nonblock.patch bnc#94449, -#https://savannah.gnu.org/patch/?9263 -- open device with O_NONBLOCK option -Patch5: cpio-open_nonblock.patch -Patch15: cpio-eof_tape_handling.patch +Patch0: cpio-use_new_ascii_format.patch +Patch1: cpio-use_sbin_rmt.patch +# PATCH-FIX-UPSTREAM cpio-2.12 cpio-open_nonblock.patch bnc#94449, +# https://savannah.gnu.org/patch/?9263 -- open device with O_NONBLOCK option +Patch2: cpio-open_nonblock.patch +Patch3: cpio-eof_tape_handling.patch # make posibble to have device nodes with major number > 127 # Red Hat Bugzilla #450109 -Patch17: cpio-dev_number.patch -Patch18: cpio-default_tape_dev.patch -#PATCH-FIX-UPSTREAM cpio-2.10-close_files_after_copy.patch -Patch20: cpio-close_files_after_copy.patch -Patch21: cpio-pattern-file-sigsegv.patch -Patch23: paxutils-rtapelib_mtget.patch -Patch25: cpio-fix_truncation_check.patch -Patch26: fix-gcc14.patch +Patch4: cpio-dev_number.patch +Patch5: cpio-default_tape_dev.patch +# PATCH-FIX-UPSTREAM cpio-2.10-close_files_after_copy.patch +Patch6: cpio-close_files_after_copy.patch +Patch7: cpio-pattern-file-sigsegv.patch +Patch8: paxutils-rtapelib_mtget.patch +Patch9: cpio-fix_truncation_check.patch +Patch10: fix-gcc14.patch +# PATCH-FIX-UPSTREAM CVE-2026-66484.patch bsc#1274856 [email protected] +# CVE-2026-66484: path traversal allows creating hard links outside intended directory via malicious tar archives. +Patch11: CVE-2026-66484.patch +# PATCH-FIX-UPSTREAM CVE-2026-66485.patch bsc#1274857 [email protected] +# CVE-2026-66485: denial of service via uncontrolled memory allocation from crafted archives +Patch12: CVE-2026-66485.patch +# PATCH-FIX-UPSTREAM CVE-2026-66486.patch bsc#1274858 [email protected] +# CVE-2026-66486: terminal control sequence injection via crafted archive member names +Patch13: CVE-2026-66486.patch BuildRequires: autoconf >= 2.71 BuildRequires: automake +BuildRequires: makeinfo #Requires(post): %{xinstall_info_prereq} #Requires(preun): %{xinstall_info_prereq} Suggests: rmt @@ -72,9 +82,7 @@ %lang_package %prep -%setup -q -%autopatch -M 20 -p0 -%autopatch -m 21 -p1 +%autosetup -p1 %build gettextize -f --no-changelog ++++++ CVE-2026-66484.patch ++++++ commit e2b9cbdd3354d2b1569b7390d1bc15c1930559ad Author: Sergey Poznyakoff <[email protected]> Date: Thu Jul 23 15:55:46 2026 +0300 The --no-absolute-filenames option affects hard link targets too. * src/tar.c (stash_tar_linkname): Apply cpio_safer_name_suffix. diff --git a/src/tar.c b/src/tar.c index 493f299..a1fc60a 100644 --- a/src/tar.c +++ b/src/tar.c @@ -36,6 +36,8 @@ stash_tar_linkname (char *linkname) strncpy (hold_tar_linkname, linkname, TARLINKNAMESIZE); hold_tar_linkname[TARLINKNAMESIZE] = '\0'; + cpio_safer_name_suffix (hold_tar_linkname, true, !no_abs_paths_flag, + false); return hold_tar_linkname; } ++++++ CVE-2026-66485.patch ++++++ commit 3cd514031371d8aeeaf2048aa10103e02831aaa9 Author: Sergey Poznyakoff <[email protected]> Date: Fri May 1 08:19:41 2026 +0300 Minor fixes * src/makepath.c: Don't use alloca. * src/userspec.c: Likewise. diff --git a/src/makepath.c b/src/makepath.c index 35dbc73..c6329bf 100644 --- a/src/makepath.c +++ b/src/makepath.c @@ -46,24 +46,19 @@ Return 0 if ARGPATH exists as a directory with the proper ownership and permissions when done, otherwise 1. */ -int -make_path (char const *argpath, - uid_t owner, - gid_t group, - const char *verbose_fmt_string) +static int +make_path0 (char *dirpath, + uid_t owner, + gid_t group, + const char *verbose_fmt_string) { - char *dirpath; /* A copy we can scribble NULs on. */ struct stat stats; - int retval = 0; mode_t tmpmode; mode_t invert_permissions; int we_are_root = getuid () == 0; - dirpath = alloca (strlen (argpath) + 1); - - strcpy (dirpath, argpath); if (stat (dirpath, &stats)) - { + { tmpmode = MODE_RWX & ~ newdir_umask; invert_permissions = we_are_root ? 0 : MODE_WXUSR & ~ tmpmode; @@ -156,5 +151,19 @@ make_path (char const *argpath, } + return 0; +} + +int +make_path (char const *argpath, + uid_t owner, + gid_t group, + const char *verbose_fmt_string) +{ + char *dirpath = xstrdup (argpath); + int retval = make_path0 (dirpath, owner, group, verbose_fmt_string); + free (dirpath); return retval; } + + diff --git a/src/userspec.c b/src/userspec.c index 2a2b324..1a2bfa0 100644 --- a/src/userspec.c +++ b/src/userspec.c @@ -18,7 +18,6 @@ /* Written by David MacKenzie <[email protected]>. */ #include <system.h> -#include <alloca.h> #include <stdio.h> #include <ctype.h> #include <sys/types.h> @@ -32,18 +31,6 @@ # define endgrent() #endif -/* Perform the equivalent of the statement `dest = strdup (src);', - but obtaining storage via alloca instead of from the heap. */ - -#define V_STRDUP(dest, src) \ - do \ - { \ - int _len = strlen ((src)); \ - (dest) = (char *) alloca (_len + 1); \ - strcpy (dest, src); \ - } \ - while (0) - /* Return nonzero if STR represents an unsigned decimal integer, otherwise return 0. */ @@ -56,6 +43,18 @@ isnumber_p (const char *str) return 1; } +static void +store_string (char **bufptr, size_t *buflen, char *str) +{ + size_t len = strlen (str) + 1; + if (len > *buflen) + { + *bufptr = xrealloc (*bufptr, len); + *buflen = len; + } + strcpy (*bufptr, str); +} + /* Extract from NAME, which has the form "[user][:.][group]", a USERNAME, UID U, GROUPNAME, and GID G. Either user or group, or both, must be present. @@ -69,23 +68,21 @@ isnumber_p (const char *str) Return NULL if successful, a static error message string if not. */ const char * -parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid, - char **username_arg, char **groupname_arg) +parse_user_spec0 (char *spec, uid_t *uid, gid_t *gid, + char **username_arg, char **groupname_arg) { static const char *tired = "virtual memory exhausted"; const char *error_msg; - char *spec; /* A copy we can write on. */ struct passwd *pwd; struct group *grp; char *g, *u, *separator; - char *groupname; + char *groupname = NULL; + size_t grouplen = 0; error_msg = NULL; *username_arg = *groupname_arg = NULL; groupname = NULL; - V_STRDUP (spec, spec_arg); - /* Find the separator if there is one. */ separator = strchr (spec, ':'); if (separator == NULL) @@ -142,11 +139,12 @@ parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid, if (grp == NULL) { char nbuf[UINTMAX_STRSIZE_BOUND]; - V_STRDUP (groupname, umaxtostr (pwd->pw_gid, nbuf)); + store_string (&groupname, &grouplen, + umaxtostr (pwd->pw_gid, nbuf)); } else { - V_STRDUP (groupname, grp->gr_name); + store_string (&groupname, &grouplen, grp->gr_name); } endgrent (); } @@ -177,7 +175,7 @@ parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid, endgrent (); /* Save a file descriptor. */ if (error_msg == NULL) - V_STRDUP (groupname, g); + store_string (&groupname, &grouplen, g); } if (error_msg == NULL) @@ -190,23 +188,24 @@ parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid, } if (groupname != NULL && error_msg == NULL) - { - *groupname_arg = strdup (groupname); - if (*groupname_arg == NULL) - { - if (*username_arg != NULL) - { - free (*username_arg); - *username_arg = NULL; - } - error_msg = tired; - } - } + *groupname_arg = groupname; } + else + free (groupname); return error_msg; } +const char * +parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid, + char **username, char **groupname) +{ + char *spec = xstrdup (spec_arg); + const char *retval = parse_user_spec0 (spec, uid, gid, username, groupname); + free (spec); + return retval; +} + #ifdef TEST #define NULL_CHECK(s) ((s) == NULL ? "(null)" : (s)) ++++++ CVE-2026-66486.patch ++++++ commit 2ff9600c9ef32e88759843cdbde74c8db5ae9b30 Author: Sergey Poznyakoff <[email protected]> Date: Thu Jul 23 17:26:05 2026 +0300 Quote file names in error messages and in listings. * NEWS: Document changes. * doc/cpio.texi: Likewise. * src/copyin.c: Quote file and member names. * src/copyout.c: Likewise. * src/copypass.c: Likewise. * src/main.c: New options: --quoting-style and --quote-chars. (process_args): Set default quoting style. * tests/CVE-2019-14866.at: Fix expected output. Index: b/doc/cpio.texi =================================================================== --- a/doc/cpio.texi +++ b/doc/cpio.texi @@ -814,6 +814,19 @@ Run in copy-pass mode. [@ref{copy-in},@ref{copy-out},@ref{copy-pass}] @*Do not print the number of blocks copied. +@item --quote-chars=@var{string} +Always quote characters from @var{string}, even if the selected +quoting style would not quote them (@pxref{quoting styles,,,tar,GNU +tar}). + +@item --quoting-style=@var{style} +Set quoting style to use when printing member and file names +(@pxref{quoting styles,,,tar,GNU tar}). Valid @var{style} values are: +@code{literal}, @code{shell}, @code{shell-always}, @code{c}, +@code{escape}, @code{locale}, and @code{clocale}. Default quoting +style is @code{literal}, unless overridden while configuring the +package. + @item -r @itemx --rename [@ref{copy-in}] Index: b/src/copyin.c =================================================================== --- a/src/copyin.c +++ b/src/copyin.c @@ -114,7 +114,7 @@ get_link_name (struct cpio_file_stat *fi if (file_hdr->c_filesize < 0 || file_hdr->c_filesize > SIZE_MAX-1) { error (0, 0, _("%s: stored filename length is out of range"), - file_hdr->c_name); + quote (file_hdr->c_name)); link_name = NULL; } else @@ -150,7 +150,11 @@ list_file (struct cpio_file_stat* file_h } else #endif - long_format (file_hdr, (char *) 0); + long_format (file_hdr, NULL); + } + else if (name_end == '\n' && isatty (fileno (stdout))) + { + printf ("%s%c", quotearg (file_hdr->c_name), name_end); } else { @@ -173,7 +177,7 @@ list_file (struct cpio_file_stat* file_h if (crc != file_hdr->c_chksum) { error (0, 0, _("%s: checksum error (0x%x, should be 0x%x)"), - file_hdr->c_name, crc, file_hdr->c_chksum); + quote (file_hdr->c_name), crc, file_hdr->c_chksum); } } } @@ -200,7 +204,7 @@ try_existing_file (struct cpio_file_stat && file_hdr->c_mtime <= file_stat.st_mtime) { error (0, 0, _("%s not created: newer or same age version exists"), - file_hdr->c_name); + quote (file_hdr->c_name)); tape_toss_input (in_file_des, file_hdr->c_filesize); tape_skip_padding (in_file_des, file_hdr->c_filesize); return -1; /* Go to the next file. */ @@ -210,7 +214,7 @@ try_existing_file (struct cpio_file_stat : unlink (file_hdr->c_name)) { error (0, errno, _("cannot remove current %s"), - file_hdr->c_name); + quote (file_hdr->c_name)); tape_toss_input (in_file_des, file_hdr->c_filesize); tape_skip_padding (in_file_des, file_hdr->c_filesize); return -1; /* Go to the next file. */ @@ -271,7 +275,8 @@ create_defered_links (struct cpio_file_s if (link_res < 0) { error (0, errno, _("cannot link %s to %s"), - d->header.c_name, file_hdr->c_name); + quote_n (0, d->header.c_name), + quote_n (1, file_hdr->c_name)); } if (d_prev != NULL) d_prev->next = d->next; @@ -467,7 +472,8 @@ copyin_regular_file (struct cpio_file_st if (link_res < 0) { error (0, errno, _("cannot link %s to %s"), - file_hdr->c_tar_linkname, file_hdr->c_name); + quote_n (0, file_hdr->c_tar_linkname), + quote_n (1, file_hdr->c_name)); } return; } @@ -500,7 +506,7 @@ copyin_regular_file (struct cpio_file_st swapping_halfwords = true; else error (0, 0, _("cannot swap halfwords of %s: odd number of halfwords"), - file_hdr->c_name); + quote (file_hdr->c_name)); } if (swap_bytes_flag) { @@ -508,7 +514,7 @@ copyin_regular_file (struct cpio_file_st swapping_bytes = true; else error (0, 0, _("cannot swap bytes of %s: odd number of bytes"), - file_hdr->c_name); + quote (file_hdr->c_name)); } copy_files_tape_to_disk (in_file_des, out_file_des, file_hdr->c_filesize); disk_empty_output_buffer (out_file_des, true); @@ -519,7 +525,7 @@ copyin_regular_file (struct cpio_file_st { if (crc != file_hdr->c_chksum) error (0, 0, _("%s: checksum error (0x%x, should be 0x%x)"), - file_hdr->c_name, crc, file_hdr->c_chksum); + quote (file_hdr->c_name), crc, file_hdr->c_chksum); } tape_skip_padding (in_file_des, file_hdr->c_filesize); return; @@ -534,7 +540,7 @@ copyin_regular_file (struct cpio_file_st { if (crc != file_hdr->c_chksum) error (0, 0, _("%s: checksum error (0x%x, should be 0x%x)"), - file_hdr->c_name, crc, file_hdr->c_chksum); + quote (file_hdr->c_name), crc, file_hdr->c_chksum); } tape_skip_padding (in_file_des, file_hdr->c_filesize); @@ -582,7 +588,8 @@ copyin_device (struct cpio_file_stat* fi if (link_res < 0) { error (0, errno, _("cannot link %s to %s"), - file_hdr->c_tar_linkname, file_hdr->c_name); + quote_n (0, file_hdr->c_tar_linkname), + quote_n (1, file_hdr->c_name)); /* Something must be wrong, because we couldn't find the file to link to. But can we assume that the device maj/min numbers are correct @@ -855,7 +862,7 @@ copyin_file (struct cpio_file_stat *file #endif default: - error (0, 0, _("%s: unknown file type"), file_hdr->c_name); + error (0, 0, _("%s: unknown file type"), quote (file_hdr->c_name)); tape_toss_input (in_file_des, file_hdr->c_filesize); tape_skip_padding (in_file_des, file_hdr->c_filesize); } @@ -1553,13 +1560,13 @@ process_copy_in (void) if (crc != file_hdr.c_chksum) { error (0, 0, _("%s: checksum error (0x%x, should be 0x%x)"), - file_hdr.c_name, crc, file_hdr.c_chksum); + quote (file_hdr.c_name), crc, file_hdr.c_chksum); } /* Debian hack: -v and -V now work with --only-verify-crc. (99/11/10) -BEM */ if (verbose_flag) { - fprintf (stderr, "%s\n", file_hdr.c_name); + fprintf (stderr, "%s\n", quotearg (file_hdr.c_name)); } if (dot_flag) { @@ -1584,7 +1591,7 @@ process_copy_in (void) copyin_file(&file_hdr, in_file_des); if (verbose_flag) - fprintf (stderr, "%s\n", file_hdr.c_name); + fprintf (stderr, "%s\n", quotearg (file_hdr.c_name)); if (dot_flag) fputc ('.', stderr); } Index: b/src/copyout.c =================================================================== --- a/src/copyout.c +++ b/src/copyout.c @@ -46,7 +46,8 @@ read_for_checksum (int in_file_des, off_ { bytes_read = read (in_file_des, buf, BUFSIZ); if (bytes_read < 0) - error (PAXEXIT_FAILURE, errno, _("cannot read checksum for %s"), file_name); + error (PAXEXIT_FAILURE, errno, _("cannot read checksum for %s"), + quote (file_name)); if (bytes_read == 0) break; for (i = 0; i < bytes_read; i++) @@ -54,7 +55,8 @@ read_for_checksum (int in_file_des, off_ file_size -= bytes_read; } if (lseek (in_file_des, 0L, SEEK_SET)) - error (PAXEXIT_FAILURE, errno, _("cannot read checksum for %s"), file_name); + error (PAXEXIT_FAILURE, errno, _("cannot read checksum for %s"), + quote (file_name)); return crc; } @@ -288,7 +290,7 @@ field_width_error (const char *filename, char valbuf[UINTMAX_STRSIZE_BOUND + 1]; char maxbuf[UINTMAX_STRSIZE_BOUND + 1]; error (0, 0, _("%s: value %s %s out of allowed range 0..%s"), - filename, fieldname, + quote (filename), fieldname, STRINGIFY_BIGINT (value, valbuf), STRINGIFY_BIGINT (MAX_VAL_WITH_DIGITS (width - nul, LG_8), maxbuf)); @@ -298,7 +300,7 @@ static void field_width_warning (const char *filename, const char *fieldname) { if (warn_option & CPIO_WARN_TRUNCATE) - error (0, 0, _("%s: truncating %s"), filename, fieldname); + error (0, 0, _("%s: truncating %s"), quote (filename), fieldname); } void @@ -466,7 +468,7 @@ write_out_binary_header (dev_t rdev, short_hdr.c_dev = makedev (file_hdr->c_dev_maj, file_hdr->c_dev_min); if ((warn_option & CPIO_WARN_TRUNCATE) && (file_hdr->c_ino >> 16) != 0) - error (0, 0, _("%s: truncating inode number"), file_hdr->c_name); + error (0, 0, _("%s: truncating inode number"), quote (file_hdr->c_name)); short_hdr.c_ino = file_hdr->c_ino & 0xFFFF; if (short_hdr.c_ino != file_hdr->c_ino) @@ -497,7 +499,7 @@ write_out_binary_header (dev_t rdev, { char maxbuf[UINTMAX_STRSIZE_BOUND + 1]; error (0, 0, _("%s: value %s %s out of allowed range 0..%u"), - file_hdr->c_name, _("name size"), + quote (file_hdr->c_name), _("name size"), STRINGIFY_BIGINT (file_hdr->c_namesize, maxbuf), 0xFFFFu); return 1; } @@ -510,7 +512,7 @@ write_out_binary_header (dev_t rdev, { char maxbuf[UINTMAX_STRSIZE_BOUND + 1]; error (0, 0, _("%s: value %s %s out of allowed range 0..%lu"), - file_hdr->c_name, _("file size"), + quote (file_hdr->c_name), _("file size"), STRINGIFY_BIGINT (file_hdr->c_namesize, maxbuf), 0xFFFFFFFFlu); return 1; } @@ -558,7 +560,7 @@ write_out_header (struct cpio_file_stat case arf_ustar: if (is_tar_filename_too_long (file_hdr->c_name)) { - error (0, 0, _("%s: file name too long"), file_hdr->c_name); + error (0, 0, _("%s: file name too long"), quote (file_hdr->c_name)); return 1; } return write_out_tar_header (file_hdr, out_des); @@ -749,7 +751,7 @@ process_copy_out (void) if (archive_format == arf_tar) { error (0, 0, _("%s not dumped: not a regular file"), - orig_file_name); + quote (orig_file_name)); continue; } else if (archive_format == arf_ustar) @@ -800,7 +802,7 @@ process_copy_out (void) if (link_size + 1 > 100) { error (0, 0, _("%s: symbolic link too long"), - file_hdr.c_name); + quote (file_hdr.c_name)); } else { @@ -823,11 +825,11 @@ process_copy_out (void) #endif default: - error (0, 0, _("%s: unknown file type"), orig_file_name); + error (0, 0, _("%s: unknown file type"), quote (orig_file_name)); } if (verbose_flag) - fprintf (stderr, "%s\n", orig_file_name); + fprintf (stderr, "%s\n", quote (orig_file_name)); if (dot_flag) fputc ('.', stderr); } Index: b/src/copypass.c =================================================================== --- a/src/copypass.c +++ b/src/copypass.c @@ -127,7 +127,7 @@ process_copy_pass (void) && in_file_stat.st_mtime <= out_file_stat.st_mtime) { error (0, 0, _("%s not created: newer or same age version exists"), - output_name.ds_string); + quote (output_name.ds_string)); continue; /* Go to the next file. */ } else if (S_ISDIR (out_file_stat.st_mode) @@ -135,7 +135,7 @@ process_copy_pass (void) : unlink (output_name.ds_string)) { error (0, errno, _("cannot remove current %s"), - output_name.ds_string); + quote (output_name.ds_string)); continue; /* Go to the next file. */ } } @@ -312,7 +312,8 @@ process_copy_pass (void) #endif else { - error (0, 0, _("%s: unknown file type"), input_name.ds_string); + error (0, 0, _("%s: unknown file type"), + quote (input_name.ds_string)); } if (verbose_flag) @@ -388,12 +389,12 @@ link_to_name (char const *link_name, cha { if (verbose_flag) error (0, 0, _("%s linked to %s"), - link_target, link_name); + quote_n (0, link_target), quote_n (1, link_name)); } else if (link_flag) { error (0, errno, _("cannot link %s to %s"), - link_target, link_name); + quote_n (0, link_target), quote_n (1, link_name)); } return res; } Index: b/src/main.c =================================================================== --- a/src/main.c +++ b/src/main.c @@ -61,7 +61,9 @@ enum cpio_options { RENUMBER_INODES_OPTION, IGNORE_DEVNO_OPTION, IGNORE_DIRNLINK_OPTION, - DEVICE_INDEPENDENT_OPTION + DEVICE_INDEPENDENT_OPTION, + QUOTING_STYLE_OPTION, + QUOTE_CHARS_OPTION }; const char *program_authors[] = @@ -141,6 +143,12 @@ static struct argp_option options[] = { N_("Control warning display. Currently FLAG is one of 'none', 'truncate', 'all'. Multiple options accumulate."), GRID+1 }, {"owner", 'R', N_("[USER][:.][GROUP]"), 0, N_("Set the ownership of all files created to the specified USER and/or GROUP"), GRID+1 }, + {"quoting-style", QUOTING_STYLE_OPTION, N_("STYLE"), 0, + N_("set name quoting style; use --quoting-style=help for a list of valid STYLE values"), + GRID+1 }, + {"quote-chars", QUOTE_CHARS_OPTION, N_("STRING"), 0, + N_("additionally quote characters from STRING"), + GRID+1 }, #undef GRID #define GRID 110 @@ -295,6 +303,36 @@ warn_control (char *arg) return 1; } +static void +cpio_list_quoting_styles (int indent) +{ + int i; + + for (i = 0; quoting_style_args[i]; i++) + printf ("%*.*s%s\n", indent, indent, "", quoting_style_args[i]); +} + +static void +cpio_set_quoting_style (char *arg) +{ + if (strcmp (arg, "help") == 0) + { + cpio_list_quoting_styles (0); + exit (EXIT_SUCCESS); + } + + for (idx_t i = 0; quoting_style_args[i]; i++) + if (strcmp (arg, quoting_style_args[i]) == 0) + { + set_quoting_style (NULL, i); + return; + } + USAGE_ERROR ((0, 0, + _("Unknown quoting style '%s'." + " Try '%s --quoting-style=help' to get a list."), + arg, program_name)); +} + static error_t parse_opt (int key, char *arg, struct argp_state *state) { @@ -455,10 +493,19 @@ crc newc odc bin ustar tar (all-caps als copy_function = process_copy_pass; break; + case QUOTE_CHARS_OPTION: + for (;*arg; arg++) + set_char_quoting (NULL, *arg, 1); + break; + + case QUOTING_STYLE_OPTION: + cpio_set_quoting_style (arg); + break; + case IGNORE_DEVNO_OPTION: ignore_devno_option = 1; break; - + case RENUMBER_INODES_OPTION: renumber_inodes_option = 1; break; @@ -594,6 +641,8 @@ process_args (int argc, char *argv[]) xstat = lstat; + set_quoting_style (NULL, DEFAULT_QUOTING_STYLE); + if (argp_parse (&argp, argc, argv, ARGP_IN_ORDER, &index, NULL)) exit (PAXEXIT_FAILURE); Index: b/tests/CVE-2019-14866.at =================================================================== --- a/tests/CVE-2019-14866.at +++ b/tests/CVE-2019-14866.at @@ -29,7 +29,7 @@ fi ], [0], [], -[cpio: file: value size 17179869184 out of allowed range 0..8589934591 +[cpio: 'file': value size 17179869184 out of allowed range 0..8589934591 2 blocks ]) AT_CLEANUP ++++++ cpio-close_files_after_copy.patch ++++++ --- /var/tmp/diff_new_pack.qevGYI/_old 2026-08-27 18:48:43.358032413 +0200 +++ /var/tmp/diff_new_pack.qevGYI/_new 2026-08-27 18:48:43.362032553 +0200 @@ -1,8 +1,8 @@ -Index: src/copyin.c +Index: b/src/copyin.c =================================================================== ---- src/copyin.c.orig -+++ src/copyin.c -@@ -1420,6 +1420,19 @@ process_copy_in () +--- a/src/copyin.c ++++ b/src/copyin.c +@@ -1595,6 +1595,19 @@ process_copy_in (void) cpio_file_stat_free (&file_hdr); ++++++ cpio-default_tape_dev.patch ++++++ --- /var/tmp/diff_new_pack.qevGYI/_old 2026-08-27 18:48:43.379033147 +0200 +++ /var/tmp/diff_new_pack.qevGYI/_new 2026-08-27 18:48:43.387033427 +0200 @@ -1,7 +1,7 @@ -Index: src/mt.c +Index: b/src/mt.c =================================================================== ---- src/mt.c.orig -+++ src/mt.c +--- a/src/mt.c ++++ b/src/mt.c @@ -224,11 +224,18 @@ parse_opt (int key, char *arg, struct ar { tapedev = getenv ("TAPE"); ++++++ cpio-dev_number.patch ++++++ --- /var/tmp/diff_new_pack.qevGYI/_old 2026-08-27 18:48:43.404034021 +0200 +++ /var/tmp/diff_new_pack.qevGYI/_new 2026-08-27 18:48:43.408034161 +0200 @@ -1,8 +1,8 @@ -Index: src/copyin.c +Index: b/src/copyin.c =================================================================== ---- src/copyin.c.orig -+++ src/copyin.c -@@ -1287,15 +1287,15 @@ read_in_binary (struct cpio_file_stat *f +--- a/src/copyin.c ++++ b/src/copyin.c +@@ -1303,15 +1303,15 @@ read_in_binary (struct cpio_file_stat *f swab_array ((char *) short_hdr, 13); } ++++++ cpio-eof_tape_handling.patch ++++++ --- /var/tmp/diff_new_pack.qevGYI/_old 2026-08-27 18:48:43.429034895 +0200 +++ /var/tmp/diff_new_pack.qevGYI/_new 2026-08-27 18:48:43.434035070 +0200 @@ -1,8 +1,8 @@ -Index: src/util.c +Index: b/src/util.c =================================================================== ---- src/util.c.orig -+++ src/util.c -@@ -203,8 +203,15 @@ tape_fill_input_buffer (int in_des, int +--- a/src/util.c ++++ b/src/util.c +@@ -201,8 +201,15 @@ tape_fill_input_buffer (int in_des, int input_size = rmtread (in_des, input_buffer, num_bytes); if (input_size == 0 && input_is_special) { @@ -19,7 +19,7 @@ } if (input_size == SAFE_READ_ERROR) error (PAXEXIT_FAILURE, errno, _("read error")); -@@ -366,8 +373,15 @@ tape_buffered_peek (char *peek_buf, int +@@ -364,8 +371,15 @@ tape_buffered_peek (char *peek_buf, int { if (input_is_special) { @@ -36,7 +36,7 @@ } else break; -@@ -829,6 +843,40 @@ tape_offline (int tape_des) +@@ -827,6 +841,40 @@ tape_offline (int tape_des) #endif } ++++++ cpio-open_nonblock.patch ++++++ --- /var/tmp/diff_new_pack.qevGYI/_old 2026-08-27 18:48:43.460035979 +0200 +++ /var/tmp/diff_new_pack.qevGYI/_new 2026-08-27 18:48:43.464036119 +0200 @@ -26,10 +26,10 @@ for long-running commands such as "fsf", one cannot tell if the command is progressing or if it's blocking waiting for media. -Index: src/mt.c +Index: b/src/mt.c =================================================================== ---- src/mt.c.orig -+++ src/mt.c +--- a/src/mt.c ++++ b/src/mt.c @@ -332,11 +332,11 @@ main (int argc, char **argv) #ifdef MTERASE case MTERASE: @@ -44,10 +44,10 @@ } if (tapedesc == -1) -Index: src/util.c +Index: b/src/util.c =================================================================== ---- src/util.c.orig -+++ src/util.c +--- a/src/util.c ++++ b/src/util.c @@ -799,14 +799,14 @@ open_archive (char *file) copy_in = process_copy_in; ++++++ cpio-use_new_ascii_format.patch ++++++ --- /var/tmp/diff_new_pack.qevGYI/_old 2026-08-27 18:48:43.483036783 +0200 +++ /var/tmp/diff_new_pack.qevGYI/_new 2026-08-27 18:48:43.486036888 +0200 @@ -1,8 +1,8 @@ -Index: doc/cpio.info +Index: b/doc/cpio.info =================================================================== ---- doc/cpio.info.orig -+++ doc/cpio.info -@@ -226,7 +226,8 @@ option, e.g.: +--- a/doc/cpio.info ++++ b/doc/cpio.info +@@ -224,7 +224,8 @@ option, e.g.: '-B' Set the I/O block size to 5120 bytes. '-c' @@ -12,7 +12,7 @@ '-C NUMBER' '--io-size=NUMBER' Set the I/O block size to the given NUMBER of bytes. -@@ -307,7 +308,8 @@ option. +@@ -305,7 +306,8 @@ option. '-B' Set the I/O block size to 5120 bytes. '-c' @@ -22,7 +22,7 @@ '-C NUMBER' '--io-size=NUMBER' Set the I/O block size to the given NUMBER of bytes. -@@ -417,7 +419,8 @@ option. +@@ -415,7 +417,8 @@ option. '-B' Set the I/O block size to 5120 bytes. '-c' @@ -32,7 +32,7 @@ '-C NUMBER' '--io-size=NUMBER' Set the I/O block size to the given NUMBER of bytes. -@@ -565,7 +568,8 @@ option is valid. +@@ -566,7 +569,8 @@ option is valid. '-c' [*note copy-in::,*note copy-out::,*note copy-pass::] @@ -42,11 +42,11 @@ '-C IO-SIZE' '--io-size=IO-SIZE' -Index: src/main.c +Index: b/src/main.c =================================================================== ---- src/main.c.orig -+++ src/main.c -@@ -328,6 +328,7 @@ parse_opt (int key, char *arg, struct ar +--- a/src/main.c ++++ b/src/main.c +@@ -331,6 +331,7 @@ parse_opt (int key, char *arg, struct ar case 'c': /* Use the old portable ASCII format. */ if (archive_format != arf_unknown) USAGE_ERROR ((0, 0, _("Archive format multiply defined"))); ++++++ cpio-use_sbin_rmt.patch ++++++ --- /var/tmp/diff_new_pack.qevGYI/_old 2026-08-27 18:48:43.500037377 +0200 +++ /var/tmp/diff_new_pack.qevGYI/_new 2026-08-27 18:48:43.514037866 +0200 @@ -1,8 +1,8 @@ -Index: lib/rtapelib.c +Index: b/lib/rtapelib.c =================================================================== ---- lib/rtapelib.c.orig -+++ lib/rtapelib.c -@@ -17,7 +17,7 @@ +--- a/lib/rtapelib.c ++++ b/lib/rtapelib.c +@@ -16,7 +16,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @@ -11,7 +11,7 @@ which rdump and rrestore use. Unfortunately, the man page is *WRONG*. The author of the routines I'm including originally wrote his code just based on the man page, and it didn't work, so he went to the rdump source -@@ -267,7 +267,7 @@ get_status_off (int handle) +@@ -263,7 +263,7 @@ get_status_off (int handle) #if WITH_REXEC
