CVE-2014-9112: Heap-based buffer overflow in the process_copy_in

function allows remote attackers to cause a denial of service via
a large block value in a cpio archive.
Fix from a series of upstream commits by Sergey Poznyakoff, via Debian.

CVE-2015-1197: cpio, when using the --no-absolute-filenames option,
allows local users to write to arbitrary files via a symlink attack
on a file in an archive.
Fix from Vitezslav Cizek after 3.5 years of gestation in the SUSE
bug tracker, via Debian.

Also apply an upstream fix for some regression tests while here.
This commit is contained in:
naddy 2015-03-31 15:36:52 +00:00
parent 9462c3f268
commit c1d595ad3d
10 changed files with 318 additions and 21 deletions

View File

@ -1,10 +1,10 @@
# $OpenBSD: Makefile,v 1.23 2013/11/09 23:19:01 naddy Exp $
# $OpenBSD: Makefile,v 1.24 2015/03/31 15:36:52 naddy Exp $
COMMENT= GNU copy-in/out (cpio)
DISTNAME= cpio-2.11
PKGNAME= g${DISTNAME}
REVISION= 0
REVISION= 1
CATEGORIES= archivers
HOMEPAGE= https://www.gnu.org/software/cpio/
@ -22,4 +22,9 @@ CONFIGURE_ARGS= --program-prefix="g" \
--with-rmt=/etc/rmt
MODGNU_CONFIG_GUESS_DIRS=${WRKSRC}/build-aux
# autom4te
AUTOCONF_VERSION=2.63
TEST_DEPENDS= ${MODGNU_AUTOCONF_DEPENDS}
TEST_ENV= AUTOCONF_VERSION=${AUTOCONF_VERSION}
.include <bsd.port.mk>

View File

@ -1,6 +1,9 @@
$OpenBSD: patch-doc_cpio_1,v 1.2 2007/07/09 17:38:42 naddy Exp $
--- doc/cpio.1.orig Thu Jun 28 10:59:17 2007
+++ doc/cpio.1 Fri Jul 6 18:06:24 2007
$OpenBSD: patch-doc_cpio_1,v 1.3 2015/03/31 15:36:52 naddy Exp $
CVE-2015-1197: cpio directory traversal
--- doc/cpio.1.orig Sat Feb 14 19:15:50 2009
+++ doc/cpio.1 Sun Mar 29 21:11:10 2015
@@ -1,8 +1,8 @@
.TH CPIO 1L \" -*- nroff -*-
.SH NAME
@ -21,8 +24,11 @@ $OpenBSD: patch-doc_cpio_1,v 1.2 2007/07/09 17:38:42 naddy Exp $
{\-i|\-\-extract} [\-bcdfmnrtsuvBSV] [\-C bytes] [\-E file] [\-H format]
[\-M message] [\-R [user][:.][group]] [\-I [[user@]host:]archive]
[\-F [[user@]host:]archive] [\-\-file=[[user@]host:]archive]
@@ -24,7 +24,7 @@ cpio \- copy files to and from archives
@@ -22,9 +22,10 @@ cpio \- copy files to and from archives
[\-\-owner=[user][:.][group]] [\-\-no-preserve-owner] [\-\-message=message]
[\-\-force\-local] [\-\-no\-absolute\-filenames] [\-\-sparse]
[\-\-only\-verify\-crc] [\-\-to\-stdout] [\-\-quiet] [\-\-rsh-command=command]
+[\-\-extract\-over\-symlinks]
[\-\-help] [\-\-version] [pattern...] [< archive]
-.B cpio

View File

@ -0,0 +1,189 @@
$OpenBSD: patch-src_copyin_c,v 1.3 2015/03/31 15:36:52 naddy Exp $
CVE-2014-9112: heap overflow in process_copy_in()
CVE-2015-1197: cpio directory traversal
--- src/copyin.c.orig Mon Feb 15 11:02:23 2010
+++ src/copyin.c Sun Mar 29 21:11:10 2015
@@ -124,10 +124,30 @@ tape_skip_padding (int in_file_des, off_t offset)
if (pad != 0)
tape_toss_input (in_file_des, pad);
}
-
+static char *
+get_link_name (struct cpio_file_stat *file_hdr, int in_file_des)
+{
+ char *link_name;
+
+ 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);
+ link_name = NULL;
+ }
+ else
+ {
+ link_name = xmalloc (file_hdr->c_filesize + 1);
+ tape_buffered_read (link_name, in_file_des, file_hdr->c_filesize);
+ link_name[file_hdr->c_filesize] = '\0';
+ tape_skip_padding (in_file_des, file_hdr->c_filesize);
+ }
+ return link_name;
+}
+
static void
-list_file(struct cpio_file_stat* file_hdr, int in_file_des)
+list_file (struct cpio_file_stat* file_hdr, int in_file_des)
{
if (verbose_flag)
{
@@ -136,21 +156,16 @@ list_file(struct cpio_file_stat* file_hdr, int in_file
{
if (archive_format != arf_tar && archive_format != arf_ustar)
{
- char *link_name = NULL; /* Name of hard and symbolic links. */
-
- link_name = (char *) xmalloc ((unsigned int) file_hdr->c_filesize + 1);
- link_name[file_hdr->c_filesize] = '\0';
- tape_buffered_read (link_name, in_file_des, file_hdr->c_filesize);
- long_format (file_hdr, link_name);
- free (link_name);
- tape_skip_padding (in_file_des, file_hdr->c_filesize);
- return;
+ char *link_name = get_link_name (file_hdr, in_file_des);
+ if (link_name)
+ {
+ long_format (file_hdr, link_name);
+ free (link_name);
+ }
}
else
- {
- long_format (file_hdr, file_hdr->c_tar_linkname);
- return;
- }
+ long_format (file_hdr, file_hdr->c_tar_linkname);
+ return;
}
else
#endif
@@ -640,7 +655,7 @@ copyin_device (struct cpio_file_stat* file_hdr)
}
static void
-copyin_link(struct cpio_file_stat *file_hdr, int in_file_des)
+copyin_link (struct cpio_file_stat *file_hdr, int in_file_des)
{
char *link_name = NULL; /* Name of hard and symbolic links. */
int res; /* Result of various function calls. */
@@ -650,10 +665,9 @@ copyin_link(struct cpio_file_stat *file_hdr, int in_fi
if (archive_format != arf_tar && archive_format != arf_ustar)
{
- link_name = (char *) xmalloc ((unsigned int) file_hdr->c_filesize + 1);
- link_name[file_hdr->c_filesize] = '\0';
- tape_buffered_read (link_name, in_file_des, file_hdr->c_filesize);
- tape_skip_padding (in_file_des, file_hdr->c_filesize);
+ link_name = get_link_name (file_hdr, in_file_des);
+ if (!link_name)
+ return;
}
else
{
@@ -686,6 +700,51 @@ copyin_link(struct cpio_file_stat *file_hdr, int in_fi
free (link_name);
}
+
+static int
+path_contains_symlink(char *path)
+{
+ struct stat st;
+ char *slash;
+ char *nextslash;
+
+ /* we got NULL pointer or empty string */
+ if (!path || !*path) {
+ return false;
+ }
+
+ slash = path;
+
+ while ((nextslash = strchr(slash + 1, '/')) != NULL) {
+ slash = nextslash;
+ *slash = '\0';
+
+ if (lstat(path, &st) != 0) {
+ if (errno == ELOOP) {
+ /* ELOOP - too many symlinks */
+ *slash = '/';
+ return true;
+ } else if (errno == ENOMEM) {
+ /* No memory for lstat - terminate */
+ xalloc_die();
+ } else {
+ /* cannot lstat path - give up */
+ *slash = '/';
+ return false;
+ }
+ }
+
+ if (S_ISLNK(st.st_mode)) {
+ *slash = '/';
+ return true;
+ }
+
+ *slash = '/';
+ }
+
+ return false;
+}
+
static void
copyin_file (struct cpio_file_stat *file_hdr, int in_file_des)
{
@@ -1005,7 +1064,7 @@ read_in_header (struct cpio_file_stat *file_hdr, int i
file_hdr->c_tar_linkname = NULL;
- tape_buffered_read (magic.str, in_des, 6L);
+ tape_buffered_read (magic.str, in_des, sizeof (magic.str));
while (1)
{
if (append_flag)
@@ -1050,8 +1109,8 @@ read_in_header (struct cpio_file_stat *file_hdr, int i
break;
}
bytes_skipped++;
- memmove (magic.str, magic.str + 1, 5);
- tape_buffered_read (magic.str, in_des, 1L);
+ memmove (magic.str, magic.str + 1, sizeof (magic.str) - 1);
+ tape_buffered_read (magic.str + sizeof (magic.str) - 1, in_des, 1L);
}
}
@@ -1456,6 +1515,23 @@ process_copy_in ()
else
{
/* Copy the input file into the directory structure. */
+
+ /* Can we write files over symlinks? */
+ if (!extract_over_symlinks)
+ {
+ if (path_contains_symlink(file_hdr.c_name))
+ {
+ /* skip the file */
+ /*
+ fprintf(stderr, "Can't write over symlinks. Skipping %s\n", file_hdr.c_name);
+ tape_toss_input (in_file_des, file_hdr.c_filesize);
+ tape_skip_padding (in_file_des, file_hdr.c_filesize);
+ continue;
+ */
+ /* terminate */
+ error (1, 0, _("Can't write over symlinks: %s\n"), file_hdr.c_name);
+ }
+ }
/* Do we need to rename the file? */
if (rename_flag || rename_batch_file)

View File

@ -0,0 +1,14 @@
$OpenBSD: patch-src_extern_h,v 1.1 2015/03/31 15:36:52 naddy Exp $
CVE-2015-1197: cpio directory traversal
--- src/extern.h.orig Mon Feb 15 11:02:23 2010
+++ src/extern.h Sun Mar 29 21:11:10 2015
@@ -95,6 +95,7 @@ extern char input_is_special;
extern char output_is_special;
extern char input_is_seekable;
extern char output_is_seekable;
+extern bool extract_over_symlinks;
extern int (*xstat) ();
extern void (*copy_function) ();

View File

@ -0,0 +1,16 @@
$OpenBSD: patch-src_global_c,v 1.1 2015/03/31 15:36:52 naddy Exp $
CVE-2015-1197: cpio directory traversal
--- src/global.c.orig Fri Feb 12 11:19:23 2010
+++ src/global.c Sun Mar 29 21:11:10 2015
@@ -187,6 +187,9 @@ bool to_stdout_option = false;
/* The name this program was run with. */
char *program_name;
+/* Extract files over symbolic links */
+bool extract_over_symlinks;
+
/* A pointer to either lstat or stat, depending on whether
dereferencing of symlinks is done for input files. */
int (*xstat) ();

View File

@ -0,0 +1,36 @@
$OpenBSD: patch-src_main_c,v 1.3 2015/03/31 15:36:52 naddy Exp $
CVE-2015-1197: cpio directory traversal
--- src/main.c.orig Fri Feb 12 12:35:09 2010
+++ src/main.c Sun Mar 29 21:11:10 2015
@@ -57,7 +57,8 @@ enum cpio_options {
FORCE_LOCAL_OPTION,
DEBUG_OPTION,
BLOCK_SIZE_OPTION,
- TO_STDOUT_OPTION
+ TO_STDOUT_OPTION,
+ EXTRACT_OVER_SYMLINKS
};
const char *program_authors[] =
@@ -222,6 +223,8 @@ static struct argp_option options[] = {
N_("Create leading directories where needed"), GRID+1 },
{"no-preserve-owner", NO_PRESERVE_OWNER_OPTION, 0, 0,
N_("Do not change the ownership of the files"), GRID+1 },
+ {"extract-over-symlinks", EXTRACT_OVER_SYMLINKS, 0, 0,
+ N_("Force writing over symbolic links"), GRID+1 },
{"unconditional", 'u', NULL, 0,
N_("Replace all files unconditionally"), GRID+1 },
{"sparse", SPARSE_OPTION, NULL, 0,
@@ -410,6 +413,10 @@ crc newc odc bin ustar tar (all-caps also recognized)"
error (PAXEXIT_FAILURE, 0,
_("--no-preserve-owner cannot be used with --owner"));
no_chown_flag = true;
+ break;
+
+ case EXTRACT_OVER_SYMLINKS: /* --extract-over-symlinks */
+ extract_over_symlinks = true;
break;
case 'o': /* Copy-out mode. */

View File

@ -1,15 +0,0 @@
$OpenBSD: patch-src_makepath_c,v 1.1 2007/07/09 17:38:42 naddy Exp $
--- src/makepath.c.orig Wed May 9 14:06:23 2007
+++ src/makepath.c Wed May 9 14:06:46 2007
@@ -65,10 +65,10 @@ make_path (char *argpath,
if (stat (dirpath, &stats))
{
+ char *slash = dirpath;
tmpmode = MODE_RWX & ~ newdir_umask;
invert_permissions = we_are_root ? 0 : MODE_WXUSR & ~ tmpmode;
- char *slash = dirpath;
while (*slash == '/')
slash++;
while ((slash = strchr (slash, '/')))

View File

@ -0,0 +1,18 @@
$OpenBSD: patch-src_util_c,v 1.1 2015/03/31 15:36:52 naddy Exp $
CVE-2014-9112: heap overflow in process_copy_in()
--- src/util.c.orig Wed Mar 10 11:22:30 2010
+++ src/util.c Sun Mar 29 21:11:01 2015
@@ -206,10 +206,7 @@ tape_fill_input_buffer (int in_des, int num_bytes)
if (input_size < 0)
error (1, errno, _("read error"));
if (input_size == 0)
- {
- error (0, 0, _("premature end of file"));
- exit (1);
- }
+ error (PAXEXIT_FAILURE, 0, _("premature end of file"));
input_bytes += input_size;
}

View File

@ -0,0 +1,14 @@
$OpenBSD: patch-tests_setstat01_at,v 1.1 2015/03/31 15:36:52 naddy Exp $
OpenBSD cannot rename a directory whose permissions disallow writing.
--- tests/setstat01.at.orig Mon Feb 15 11:02:23 2010
+++ tests/setstat01.at Tue Mar 31 17:16:44 2015
@@ -28,6 +28,7 @@ echo "test file" > dir/file
chmod 500 dir
find dir | cpio -o --quiet > archive
+chmod 700 dir
mv dir old
cpio -i --quiet < archive

View File

@ -0,0 +1,14 @@
$OpenBSD: patch-tests_setstat02_at,v 1.1 2015/03/31 15:36:52 naddy Exp $
OpenBSD cannot rename a directory whose permissions disallow writing.
--- tests/setstat02.at.orig Mon Feb 15 11:02:23 2010
+++ tests/setstat02.at Tue Mar 31 17:16:58 2015
@@ -33,6 +33,7 @@ echo "test file" > dir/file
chmod 500 dir
find dir -depth | cpio -o --quiet > archive
+chmod 700 dir
mv dir old
cpio -id --quiet < archive