1
0
mirror of https://git.FreeBSD.org/ports.git synced 2024-11-24 00:45:52 +00:00

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.

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.

PR:		198954
Obtained from:	Debian
This commit is contained in:
Christian Weisgerber 2015-03-31 14:29:26 +00:00
parent cd89d750a8
commit 22141a97fb
Notes: svn2git 2021-03-31 03:12:20 +00:00
svn path=/head/; revision=382823
10 changed files with 266 additions and 12 deletions

View File

@ -2,7 +2,7 @@
PORTNAME= cpio
PORTVERSION= 2.11
PORTREVISION= 2
PORTREVISION= 3
CATEGORIES= archivers
MASTER_SITES= ${MASTER_SITE_GNU}
MASTER_SITE_SUBDIR= ${PORTNAME}

View File

@ -1,5 +1,5 @@
--- doc/Makefile.in.orig 2010-03-25 22:34:54.000000000 +0100
+++ doc/Makefile.in 2010-03-25 22:35:08.000000000 +0100
--- doc/Makefile.in.orig 2010-03-10 13:00:35 UTC
+++ doc/Makefile.in
@@ -813,7 +813,7 @@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@

View File

@ -1,8 +1,7 @@
--- doc/cpio.1.orig 2009-02-14 19:15:50.000000000 +0100
+++ doc/cpio.1 2010-03-25 22:35:50.000000000 +0100
--- doc/cpio.1.orig 2009-02-14 18:15:50 UTC
+++ doc/cpio.1
@@ -1,8 +1,8 @@
-.TH CPIO 1L \" -*- nroff -*-
+.TH GCPIO 1L \" -*- nroff -*-
.TH CPIO 1L \" -*- nroff -*-
.SH NAME
-cpio \- copy files to and from archives
+gcpio \- copy files to and from archives
@ -21,8 +20,11 @@
{\-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

@ -1,5 +1,5 @@
--- gnu/Makefile.in.orig 2010-03-25 22:13:33.000000000 +0100
+++ gnu/Makefile.in 2010-03-25 22:14:21.000000000 +0100
--- gnu/Makefile.in.orig 2010-03-10 13:00:36 UTC
+++ gnu/Makefile.in
@@ -1720,7 +1720,7 @@ inttypes.h: inttypes.in.h $(WARN_ON_USE_
# avoid installing it.

View File

@ -0,0 +1,184 @@
--- src/copyin.c.orig 2010-02-15 10:02:23 UTC
+++ src/copyin.c
@@ -124,10 +124,30 @@ tape_skip_padding (int in_file_des, off_
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_hd
{
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* fi
}
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_
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_
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 *f
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 *f
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);
}
}
@@ -1457,6 +1516,23 @@ process_copy_in ()
{
/* 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,10 @@
--- src/extern.h.orig 2010-02-15 10:02:23 UTC
+++ src/extern.h
@@ -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

@ -1,5 +1,5 @@
--- src/filetypes.h.orig 2010-04-19 22:01:16.000000000 +0200
+++ src/filetypes.h 2010-04-19 22:04:16.000000000 +0200
--- src/filetypes.h.orig 2010-02-12 10:19:23 UTC
+++ src/filetypes.h
@@ -81,5 +81,9 @@
#ifndef S_ISLNK
#define lstat stat

View File

@ -0,0 +1,12 @@
--- src/global.c.orig 2010-02-12 10:19:23 UTC
+++ src/global.c
@@ -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,32 @@
--- src/main.c.orig 2010-02-12 11:35:09 UTC
+++ src/main.c
@@ -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,
@@ -412,6 +415,10 @@ crc newc odc bin ustar tar (all-caps als
no_chown_flag = true;
break;
+ case EXTRACT_OVER_SYMLINKS: /* --extract-over-symlinks */
+ extract_over_symlinks = true;
+ break;
+
case 'o': /* Copy-out mode. */
if (copy_function != 0)
error (PAXEXIT_FAILURE, 0, _("Mode already defined"));

View File

@ -0,0 +1,14 @@
--- src/util.c.orig 2010-03-10 10:22:30 UTC
+++ src/util.c
@@ -206,10 +206,7 @@ tape_fill_input_buffer (int in_des, int
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;
}