diff --git a/SOURCES/cpio-2.12-improper-input-validation.patch b/SOURCES/cpio-2.12-improper-input-validation.patch new file mode 100644 index 0000000..25c0b4c --- /dev/null +++ b/SOURCES/cpio-2.12-improper-input-validation.patch @@ -0,0 +1,154 @@ +From: Thomas Habets +Subject: [PATCH] Check for size overflow in tar header fields. + +This prevents surprising outputs being created, e.g. this cpio tar +output with more than one file: + +tar cf suffix.tar AUTHORS +dd if=/dev/zero seek=16G bs=1 count=0 of=suffix.tar +echo suffix.tar | cpio -H tar -o | tar tvf - + +-rw-r--r-- 1000/1000 0 2019-08-30 16:40 suffix.tar +-rw-r--r-- thomas/thomas 161 2019-08-30 16:40 AUTHORS +--- + src/copyout.c | 3 +-- + src/extern.h | 2 +- + src/tar.c | 45 ++++++++++++++++++++++++++++++++------------- + 3 files changed, 34 insertions(+), 16 deletions(-) + +diff --git a/src/copyout.c b/src/copyout.c +index dcae449..56416ba 100644 +--- a/src/copyout.c ++++ b/src/copyout.c +@@ -552,8 +552,7 @@ write_out_header (struct cpio_file_stat *file_hdr, int out_des) + error (0, 0, _("%s: file name too long"), file_hdr->c_name); + return 1; + } +- write_out_tar_header (file_hdr, out_des); /* FIXME: No error checking */ +- return 0; ++ return write_out_tar_header (file_hdr, out_des); + + case arf_binary: + return write_out_binary_header (makedev (file_hdr->c_rdev_maj, +diff --git a/src/extern.h b/src/extern.h +index e27d662..47b477a 100644 +--- a/src/extern.h ++++ b/src/extern.h +@@ -145,7 +145,7 @@ int make_path (char *argpath, uid_t owner, gid_t group, + const char *verbose_fmt_string); + + /* tar.c */ +-void write_out_tar_header (struct cpio_file_stat *file_hdr, int out_des); ++int write_out_tar_header (struct cpio_file_stat *file_hdr, int out_des); + int null_block (long *block, int size); + void read_in_tar_header (struct cpio_file_stat *file_hdr, int in_des); + int otoa (char *s, unsigned long *n); +diff --git a/src/tar.c b/src/tar.c +index e2b5f45..53dc99a 100644 +--- a/src/tar.c ++++ b/src/tar.c +@@ -93,8 +93,9 @@ stash_tar_filename (char *prefix, char *filename) + sprintf (where, "%*lo ", digits - 2, value); + except that sprintf fills in the trailing NUL and we don't. */ + +-static void +-to_oct (register long value, register int digits, register char *where) ++static int ++to_oct_or_error (register long value, register int digits, register char *where, ++ const char *filename, const char *fieldname) + { + --digits; /* Leave the trailing NUL slot alone. */ + +@@ -105,10 +106,17 @@ to_oct (register long value, register int digits, register char *where) + value >>= 3; + } + while (digits > 0 && value != 0); ++ if (value > 0) ++ { ++ error (0, 0, _("%s: field width not sufficient for storing %s"), ++ filename, fieldname); ++ return 1; ++ } + + /* Add leading zeroes, if necessary. */ + while (digits > 0) + where[--digits] = '0'; ++ return 0; + } + + +@@ -139,7 +147,7 @@ tar_checksum (struct tar_header *tar_hdr) + /* Write out header FILE_HDR, including the file name, to file + descriptor OUT_DES. */ + +-void ++int + write_out_tar_header (struct cpio_file_stat *file_hdr, int out_des) + { + int name_len; +@@ -168,11 +176,16 @@ write_out_tar_header (struct cpio_file_stat *file_hdr, int out_des) + + /* Ustar standard (POSIX.1-1988) requires the mode to contain only 3 octal + digits */ +- to_oct (file_hdr->c_mode & MODE_ALL, 8, tar_hdr->mode); +- to_oct (file_hdr->c_uid, 8, tar_hdr->uid); +- to_oct (file_hdr->c_gid, 8, tar_hdr->gid); +- to_oct (file_hdr->c_filesize, 12, tar_hdr->size); +- to_oct (file_hdr->c_mtime, 12, tar_hdr->mtime); ++ if (to_oct_or_error (file_hdr->c_mode & MODE_ALL, 8, tar_hdr->mode, file_hdr->c_name, _("mode"))) ++ return 1; ++ if (to_oct_or_error (file_hdr->c_uid, 8, tar_hdr->uid, file_hdr->c_name, _("uid"))) ++ return 1; ++ if (to_oct_or_error (file_hdr->c_gid, 8, tar_hdr->gid, file_hdr->c_name, _("gid"))) ++ return 1; ++ if (to_oct_or_error (file_hdr->c_filesize, 12, tar_hdr->size, file_hdr->c_name, _("file size"))) ++ return 1; ++ if (to_oct_or_error (file_hdr->c_mtime, 12, tar_hdr->mtime, file_hdr->c_name, _("modification time"))) ++ return 1; + + switch (file_hdr->c_mode & CP_IFMT) + { +@@ -184,7 +197,8 @@ write_out_tar_header (struct cpio_file_stat *file_hdr, int out_des) + strncpy (tar_hdr->linkname, file_hdr->c_tar_linkname, + TARLINKNAMESIZE); + tar_hdr->typeflag = LNKTYPE; +- to_oct (0, 12, tar_hdr->size); ++ if (to_oct_or_error (0, 12, tar_hdr->size, file_hdr->c_name, _("file size"))) ++ return 1; + } + else + tar_hdr->typeflag = REGTYPE; +@@ -210,7 +224,8 @@ write_out_tar_header (struct cpio_file_stat *file_hdr, int out_des) + than TARLINKNAMESIZE. */ + strncpy (tar_hdr->linkname, file_hdr->c_tar_linkname, + TARLINKNAMESIZE); +- to_oct (0, 12, tar_hdr->size); ++ if (to_oct_or_error (0, 12, tar_hdr->size, file_hdr->c_name, _("file size"))) ++ return 1; + break; + #endif /* CP_IFLNK */ + } +@@ -229,13 +244,17 @@ write_out_tar_header (struct cpio_file_stat *file_hdr, int out_des) + if (name) + strcpy (tar_hdr->gname, name); + +- to_oct (file_hdr->c_rdev_maj, 8, tar_hdr->devmajor); +- to_oct (file_hdr->c_rdev_min, 8, tar_hdr->devminor); ++ if (to_oct_or_error (file_hdr->c_rdev_maj, 8, tar_hdr->devmajor, file_hdr->c_name, _("rdev major"))) ++ return 1; ++ if (to_oct_or_error (file_hdr->c_rdev_min, 8, tar_hdr->devminor, file_hdr->c_name, _("rdev minor"))) ++ return 1; + } + +- to_oct (tar_checksum (tar_hdr), 8, tar_hdr->chksum); ++ if (to_oct_or_error (tar_checksum (tar_hdr), 8, tar_hdr->chksum, file_hdr->c_name, _("checksum"))) ++ return 1; + + tape_buffered_write ((char *) &tar_rec, out_des, TARRECORDSIZE); ++ return 0; + } + + /* Return nonzero iff all the bytes in BLOCK are NUL. +-- +2.26.0 + diff --git a/SPECS/cpio.spec b/SPECS/cpio.spec index 2077dc7..4a3b745 100644 --- a/SPECS/cpio.spec +++ b/SPECS/cpio.spec @@ -1,7 +1,7 @@ Summary: A GNU archiving program Name: cpio Version: 2.12 -Release: 9%{?dist} +Release: 10%{?dist} License: GPLv3+ URL: http://www.gnu.org/software/cpio/ Source: ftp://ftp.gnu.org/gnu/cpio/cpio-%{version}.tar.bz2 @@ -41,6 +41,11 @@ Patch8: cpio-2.11-crc-fips-nit.patch # https://www.mail-archive.com/bug-cpio@gnu.org/msg00605.html Patch9: cpio-2.11-retain-symlink-times.patch +# Fixed improper input validation when writing tar header fields +# upstream patch (#1766223) +# https://cement.retrofitta.se/tmp/cpio-tar.patch +Patch10: cpio-2.12-improper-input-validation.patch + Provides: bundled(gnulib) Provides: /bin/cpio @@ -101,6 +106,9 @@ make check || { %{_infodir}/*.info* %changelog +* Thu Jan 21 2021 Ondrej Dubaj - 2.12-10 +- Fixed improper input validation when writing tar header fields (#1766223) + * Mon Jun 15 2020 Ondrej Dubaj - 2.12-9 - Extract: retain times for symlinks (#1487673)