From bacdf8602bacedb65023c832348dae92fe50bbb3 Mon Sep 17 00:00:00 2001 From: fly_fzc <2385803914@qq.com> Date: Sat, 27 May 2023 15:19:01 +0800 Subject: [PATCH] Fix CVE-2015-1197 (cherry picked from commit 1bdcb10ee771804c82e4ee7398145d0b00296d1e) --- ...ee2b407913c533f7ded8d6f8cbeec16ff6ca.patch | 273 ++++++++++++++++++ cpio.spec | 9 +- 2 files changed, 281 insertions(+), 1 deletion(-) create mode 100644 backport-CVE-2015-1197-Fix-45b0ee2b407913c533f7ded8d6f8cbeec16ff6ca.patch diff --git a/backport-CVE-2015-1197-Fix-45b0ee2b407913c533f7ded8d6f8cbeec16ff6ca.patch b/backport-CVE-2015-1197-Fix-45b0ee2b407913c533f7ded8d6f8cbeec16ff6ca.patch new file mode 100644 index 0000000..e70b169 --- /dev/null +++ b/backport-CVE-2015-1197-Fix-45b0ee2b407913c533f7ded8d6f8cbeec16ff6ca.patch @@ -0,0 +1,273 @@ +From 376d663340a9dc91c91a5849e5713f07571c1628 Mon Sep 17 00:00:00 2001 +From: Sergey Poznyakoff +Date: Thu, 27 Apr 2023 15:14:23 +0300 +Subject: [PATCH] Fix 45b0ee2b407913c533f7ded8d6f8cbeec16ff6ca. + +The commit in question brought in more problems than solutions. To +properly fix the issue, use symlink placeholders, modelled after +delayed symlinks in tar. + +* src/copyin.c (symlink_placeholder) +(replace_symlink_placeholders): New functions. +(copyin_link): Create symlink placeholder if --no-absolute-filenames +was given. +(process_copy_in): Replace placeholders after extraction. +* tests/CVE-2015-1197.at: Update. Don't use /tmp. +--- + src/copyin.c | 172 +++++++++++++++++++++++++++++++++++------ + tests/CVE-2015-1197.at | 40 +++++++++++++++++++++++++++++++++++ + 2 files changed, 192 insertions(+), 20 deletions(-) + +diff --git a/src/copyin.c b/src/copyin.c +index 60cef9d..5ed2db6 100644 +--- a/src/copyin.c ++++ b/src/copyin.c +@@ -30,6 +30,7 @@ + #ifndef FNM_PATHNAME + # include + #endif ++#include + + #ifndef HAVE_LCHOWN + # define lchown(f,u,g) 0 +@@ -620,6 +621,136 @@ copyin_device (struct cpio_file_stat* file_hdr) + file_hdr->c_mtime); + } + ++struct delayed_link ++ { ++ /* The device and inode number of the placeholder. */ ++ dev_t dev; ++ ino_t ino; ++ ++ /* The desired link metadata. */ ++ mode_t mode; ++ uid_t uid; ++ gid_t gid; ++ time_t mtime; ++ ++ /* Link source and target names. */ ++ char *source; ++ char target[1]; ++ }; ++ ++static Hash_table *delayed_link_table; ++ ++static size_t ++dl_hash (void const *entry, size_t table_size) ++{ ++ struct delayed_link const *dl = entry; ++ uintmax_t n = dl->dev; ++ int nshift = (sizeof (n) - sizeof (dl->dev)) * CHAR_BIT; ++ if (0 < nshift) ++ n <<= nshift; ++ n ^= dl->ino; ++ return n % table_size; ++} ++ ++static bool ++dl_compare (void const *a, void const *b) ++{ ++ struct delayed_link const *da = a, *db = b; ++ return (da->dev == db->dev) & (da->ino == db->ino); ++} ++ ++static int ++symlink_placeholder (char *oldpath, char *newpath, struct cpio_file_stat *file_stat) ++{ ++ int fd = open (newpath, O_WRONLY | O_CREAT | O_EXCL, 0); ++ struct stat st; ++ struct delayed_link *p; ++ size_t newlen = strlen (newpath); ++ ++ if (fd < 0) ++ { ++ open_error (newpath); ++ return -1; ++ } ++ ++ if (fstat (fd, &st) != 0) ++ { ++ stat_error (newpath); ++ close (fd); ++ return -1; ++ } ++ ++ close (fd); ++ ++ p = xmalloc (sizeof (*p) + strlen (oldpath) + newlen + 1); ++ p->dev = st.st_dev; ++ p->ino = st.st_ino; ++ ++ p->mode = file_stat->c_mode; ++ p->uid = file_stat->c_uid; ++ p->gid = file_stat->c_gid; ++ p->mtime = file_stat->c_mtime; ++ ++ strcpy (p->target, newpath); ++ p->source = p->target + newlen + 1; ++ strcpy (p->source, oldpath); ++ ++ if (!((delayed_link_table ++ || (delayed_link_table = hash_initialize (0, 0, dl_hash, ++ dl_compare, free))) ++ && hash_insert (delayed_link_table, p))) ++ xalloc_die (); ++ ++ return 0; ++} ++ ++static void ++replace_symlink_placeholders (void) ++{ ++ struct delayed_link *dl; ++ ++ if (!delayed_link_table) ++ return; ++ for (dl = hash_get_first (delayed_link_table); ++ dl; ++ dl = hash_get_next (delayed_link_table, dl)) ++ { ++ struct stat st; ++ ++ /* Make sure the placeholder file is still there. If not, ++ don't create a link, as the placeholder was probably ++ removed by a later extraction. */ ++ if (lstat (dl->target, &st) == 0 ++ && st.st_dev == dl->dev ++ && st.st_ino == dl->ino) ++ { ++ if (unlink (dl->target)) ++ unlink_error (dl->target); ++ else ++ { ++ int res = UMASKED_SYMLINK (dl->source, dl->target, dl->mode); ++ if (res < 0 && create_dir_flag) ++ { ++ create_all_directories (dl->target); ++ res = UMASKED_SYMLINK (dl->source, dl->target, dl->mode); ++ } ++ if (res < 0) ++ symlink_error (dl->source, dl->target); ++ else if (!no_chown_flag) ++ { ++ uid_t uid = set_owner_flag ? set_owner : dl->uid; ++ gid_t gid = set_group_flag ? set_group : dl->gid; ++ if (lchown (dl->target, uid, gid) < 0 && errno != EPERM) ++ chown_error_details (dl->target, uid, gid); ++ } ++ } ++ } ++ } ++ ++ hash_free (delayed_link_table); ++ delayed_link_table = NULL; ++} ++ + static void + copyin_link (struct cpio_file_stat *file_hdr, int in_file_des) + { +@@ -645,28 +776,26 @@ copyin_link (struct cpio_file_stat *file_hdr, int in_file_des) + link_name = xstrdup (file_hdr->c_tar_linkname); + } + +- res = UMASKED_SYMLINK (link_name, file_hdr->c_name, +- file_hdr->c_mode); +- if (res < 0 && create_dir_flag) ++ if (no_abs_paths_flag) ++ symlink_placeholder (link_name, file_hdr->c_name, file_hdr); ++ else + { +- create_all_directories (file_hdr->c_name); + res = UMASKED_SYMLINK (link_name, file_hdr->c_name, +- file_hdr->c_mode); +- } +- if (res < 0) +- { +- error (0, errno, _("%s: Cannot symlink to %s"), +- quotearg_colon (link_name), quote_n (1, file_hdr->c_name)); +- free (link_name); +- return; +- } +- if (!no_chown_flag) +- { +- uid_t uid = set_owner_flag ? set_owner : file_hdr->c_uid; +- gid_t gid = set_group_flag ? set_group : file_hdr->c_gid; +- if ((lchown (file_hdr->c_name, uid, gid) < 0) +- && errno != EPERM) +- chown_error_details (file_hdr->c_name, uid, gid); ++ file_hdr->c_mode); ++ if (res < 0 && create_dir_flag) ++ { ++ create_all_directories (file_hdr->c_name); ++ res = UMASKED_SYMLINK (link_name, file_hdr->c_name, file_hdr->c_mode); ++ } ++ if (res < 0) ++ symlink_error (link_name, file_hdr->c_name); ++ else if (!no_chown_flag) ++ { ++ uid_t uid = set_owner_flag ? set_owner : file_hdr->c_uid; ++ gid_t gid = set_group_flag ? set_group : file_hdr->c_gid; ++ if (lchown (file_hdr->c_name, uid, gid) < 0 && errno != EPERM) ++ chown_error_details (file_hdr->c_name, uid, gid); ++ } + } + free (link_name); + } +@@ -1425,6 +1553,7 @@ process_copy_in (void) + if (dot_flag) + fputc ('\n', stderr); + ++ replace_symlink_placeholders (); + apply_delayed_set_stat (); + + cpio_file_stat_free (&file_hdr); +diff --git a/tests/CVE-2015-1197.at b/tests/CVE-2015-1197.at +new file mode 100644 +index 0000000..6079af7 +--- /dev/null ++++ b/tests/CVE-2015-1197.at +@@ -0,0 +1,40 @@ ++# Process this file with autom4te to create testsuite. -*- Autotest-*- ++# Copyright (C) 2009-2019 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, 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 . ++ ++AT_SETUP([CVE-2015-1197 (--no-absolute-filenames for symlinks)]) ++AT_CHECK([ ++tempdir=$(pwd)/tmp ++mkdir $tempdir ++touch $tempdir/file ++ln -s $tempdir dir ++AT_DATA([filelist], ++[dir ++dir/file ++]) ++cpio -o < filelist > test.cpio ++rm -rf dir $tempdir ++cpio --no-absolute-filenames -iv < test.cpio ++], ++[2], ++[], ++[1 block ++dir ++cpio: dir/file: Cannot open: Not a directory ++dir/file ++1 block ++]) ++AT_CLEANUP ++ +-- +2.27.0 + diff --git a/cpio.spec b/cpio.spec index a9a1d82..68cc4ef 100644 --- a/cpio.spec +++ b/cpio.spec @@ -1,6 +1,6 @@ Name: cpio Version: 2.13 -Release: 4 +Release: 5 Summary: A GNU archiving program License: GPLv3+ @@ -18,6 +18,7 @@ Patch7: revert-CVE-2015-1197.patch Patch8: backport-0001-CVE-2021-38185-Rewrite-dynamic-string-support.patch Patch9: backport-0002-CVE-2021-38185-Fix-previous-commit.patch Patch10: backport-0003-CVE-2021-38185-Fix-dynamic-string-reallocations.patch +Patch11: backport-CVE-2015-1197-Fix-45b0ee2b407913c533f7ded8d6f8cbeec16ff6ca.patch Patch9000: add-option-to-add-metadata-in-copy-out-mode.patch Patch9001: Fix-use-after-free-and-return-appropriate-error.patch @@ -63,6 +64,12 @@ make check %{_datadir}/man/man1/%{name}.1.gz %changelog +* Sat May 27 2023 fuanan - 2.13-5 +- Type:CVE +- ID:CVE-2015-1197 +- SUG:NA +- DESC:Fix CVE-2015-1197 + * Tue Aug 24 2021 yangzhuangzhuang - 2.13-4 - Type:CVE - ID:CVE-2021-38185 -- Gitee