Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Step:15-SP6
cpio
fix-CVE-2023-7207.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File fix-CVE-2023-7207.patch of Package cpio
From 376d663340a9dc91c91a5849e5713f07571c1628 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff <gray@gnu.org> Date: Thu, 27 Apr 2023 15:14:23 +0300 Subject: 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 | 173 ++++++++++++++++++++++++++++++++++++++++++------- tests/CVE-2015-1197.at | 7 +- 2 files changed, 153 insertions(+), 27 deletions(-) Index: cpio-2.13/src/copyin.c =================================================================== --- cpio-2.13.orig/src/copyin.c +++ cpio-2.13/src/copyin.c @@ -31,6 +31,7 @@ #ifndef FNM_PATHNAME # include <fnmatch.h> #endif +#include <hash.h> #ifndef HAVE_LCHOWN # define lchown(f,u,g) 0 @@ -621,6 +622,136 @@ copyin_device (struct cpio_file_stat* fi 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) { @@ -646,28 +777,26 @@ copyin_link (struct cpio_file_stat *file 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); + 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); } @@ -1418,6 +1547,7 @@ process_copy_in () if (dot_flag) fputc ('\n', stderr); + replace_symlink_placeholders (); apply_delayed_set_stat (); cpio_file_stat_free (&file_hdr);
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor