diff -cpr ../binutils-2.24.orig/bfd/archive.c ./bfd/archive.c *** ../binutils-2.24.orig/bfd/archive.c 2014-11-13 11:08:46.720741346 +0000 --- ./bfd/archive.c 2014-11-13 11:12:38.908876606 +0000 *************** _bfd_slurp_extended_name_table (bfd *abf *** 1299,1304 **** --- 1299,1306 ---- { byebye: free (namedata); + bfd_ardata (abfd)->extended_names = NULL; + bfd_ardata (abfd)->extended_names_size = 0; return FALSE; } diff -cpr ../binutils-2.24.orig/binutils/ar.c ./binutils/ar.c *** ../binutils-2.24.orig/binutils/ar.c 2014-11-13 11:08:46.808741776 +0000 --- ./binutils/ar.c 2014-11-13 11:10:10.510151199 +0000 *************** extract_file (bfd *abfd) *** 1031,1036 **** --- 1031,1045 ---- bfd_size_type size; struct stat buf; + /* PR binutils/17533: Do not allow directory traversal + outside of the current directory tree. */ + if (! is_valid_archive_path (bfd_get_filename (abfd))) + { + non_fatal (_("illegal pathname found in archive member: %s"), + bfd_get_filename (abfd)); + return; + } + if (bfd_stat_arch_elt (abfd, &buf) != 0) /* xgettext:c-format */ fatal (_("internal stat error on %s"), bfd_get_filename (abfd)); Only in ./binutils: ar.c.orig diff -cpr ../binutils-2.24.orig/binutils/bucomm.c ./binutils/bucomm.c *** ../binutils-2.24.orig/binutils/bucomm.c 2014-11-13 11:08:46.791741693 +0000 --- ./binutils/bucomm.c 2014-11-13 11:10:10.511151188 +0000 *************** bfd_get_archive_filename (const bfd *abf *** 624,626 **** --- 624,652 ---- bfd_get_filename (abfd)); return buf; } + + /* Returns TRUE iff PATHNAME, a filename of an archive member, + is valid for writing. For security reasons absolute paths + and paths containing /../ are not allowed. See PR 17533. */ + + bfd_boolean + is_valid_archive_path (char const * pathname) + { + const char * n = pathname; + + if (IS_ABSOLUTE_PATH (n)) + return FALSE; + + while (*n) + { + if (*n == '.' && *++n == '.' && ( ! *++n || IS_DIR_SEPARATOR (*n))) + return FALSE; + + while (*n && ! IS_DIR_SEPARATOR (*n)) + n++; + while (IS_DIR_SEPARATOR (*n)) + n++; + } + + return TRUE; + } diff -cpr ../binutils-2.24.orig/binutils/bucomm.h ./binutils/bucomm.h *** ../binutils-2.24.orig/binutils/bucomm.h 2014-11-13 11:08:46.798741727 +0000 --- ./binutils/bucomm.h 2014-11-13 11:10:10.511151188 +0000 *************** bfd_vma parse_vma (const char *, const c *** 58,63 **** --- 58,65 ---- off_t get_file_size (const char *); + bfd_boolean is_valid_archive_path (char const *); + extern char *program_name; /* filemode.c */ diff -cpr ../binutils-2.24.orig/binutils/doc/binutils.texi ./binutils/doc/binutils.texi *** ../binutils-2.24.orig/binutils/doc/binutils.texi 2014-11-13 11:08:46.955742495 +0000 --- ./binutils/doc/binutils.texi 2014-11-13 11:10:10.513151165 +0000 *************** a normal archive. Instead the elements *** 234,240 **** individually to the second archive. The paths to the elements of the archive are stored relative to the ! archive itself. @cindex compatibility, @command{ar} @cindex @command{ar} compatibility --- 234,241 ---- individually to the second archive. The paths to the elements of the archive are stored relative to the ! archive itself. For security reasons absolute paths and paths with a ! @code{/../} component are not allowed. @cindex compatibility, @command{ar} @cindex @command{ar} compatibility diff -cpr ../binutils-2.24.orig/binutils/objcopy.c ./binutils/objcopy.c *** ../binutils-2.24.orig/binutils/objcopy.c 2014-11-13 11:08:46.798741727 +0000 --- ./binutils/objcopy.c 2014-11-13 11:10:10.514151156 +0000 *************** copy_archive (bfd *ibfd, bfd *obfd, cons *** 2182,2187 **** --- 2182,2197 ---- bfd_boolean del = TRUE; bfd_boolean ok_object; + /* PR binutils/17533: Do not allow directory traversal + outside of the current directory tree by archive members. */ + if (! is_valid_archive_path (bfd_get_filename (this_element))) + { + non_fatal (_("illegal pathname found in archive member: %s"), + bfd_get_filename (this_element)); + status = 1; + goto cleanup_and_exit; + } + /* Create an output file for this member. */ output_name = concat (dir, "/", bfd_get_filename (this_element), (char *) 0); *************** copy_archive (bfd *ibfd, bfd *obfd, cons *** 2191,2198 **** { output_name = make_tempdir (output_name); if (output_name == NULL) ! fatal (_("cannot create tempdir for archive copying (error: %s)"), ! strerror (errno)); l = (struct name_list *) xmalloc (sizeof (struct name_list)); l->name = output_name; --- 2201,2212 ---- { output_name = make_tempdir (output_name); if (output_name == NULL) ! { ! non_fatal (_("cannot create tempdir for archive copying (error: %s)"), ! strerror (errno)); ! status = 1; ! goto cleanup_and_exit; ! } l = (struct name_list *) xmalloc (sizeof (struct name_list)); l->name = output_name; *************** copy_archive (bfd *ibfd, bfd *obfd, cons *** 2234,2240 **** { bfd_nonfatal_message (output_name, NULL, NULL, NULL); status = 1; ! return; } if (ok_object) --- 2248,2254 ---- { bfd_nonfatal_message (output_name, NULL, NULL, NULL); status = 1; ! goto cleanup_and_exit; } if (ok_object) *************** copy_archive (bfd *ibfd, bfd *obfd, cons *** 2295,2301 **** { status = 1; bfd_nonfatal_message (filename, NULL, NULL, NULL); - return; } filename = bfd_get_filename (ibfd); --- 2309,2314 ---- *************** copy_archive (bfd *ibfd, bfd *obfd, cons *** 2303,2311 **** { status = 1; bfd_nonfatal_message (filename, NULL, NULL, NULL); - return; } /* Delete all the files that we opened. */ for (l = list; l != NULL; l = l->next) { --- 2316,2324 ---- { status = 1; bfd_nonfatal_message (filename, NULL, NULL, NULL); } + cleanup_and_exit: /* Delete all the files that we opened. */ for (l = list; l != NULL; l = l->next) {