]> Dogcows Code - chaz/tar/commitdiff
tar: fix symlink race and symlink transform bug
authorPaul Eggert <eggert@cs.ucla.edu>
Mon, 13 Jul 2015 16:53:00 +0000 (09:53 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Mon, 13 Jul 2015 16:53:56 +0000 (09:53 -0700)
Problem reported by Tobias Stoeckmann in:
http://lists.gnu.org/archive/html/bug-tar/2015-07/msg00004.html
* gnulib.modules: Add areadlinkat-with-size.
* src/create.c: Include areadlink.h.
(dump_file0): Use areadlinkat_with_size, rather than trying to do
it by hand, incorrectly.  This also avoids assumption that
the symlink contents fit on the stack.  Also, use the transformed
link name, not the original link name, when deciding whether the
name is long enough to require writing a long link.

gnulib.modules
src/create.c

index ec3dc9000611fca19f60914c538d845dcfa727c2..fe5ab737142a40fe820857f3372ab3eaa5fc8bdf 100644 (file)
@@ -19,6 +19,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 alloca
+areadlinkat-with-size
 argmatch
 argp
 argp-version-etc
index 1b08e0b21fd3e5f34675c01b8ad1f43b8477ca9c..7cdc9782895a988c36764e19cd4b8b191a070638 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <system.h>
 
+#include <areadlink.h>
 #include <quotearg.h>
 
 #include "common.h"
@@ -1114,7 +1115,7 @@ dump_dir0 (struct tar_stat_info *st, char const *directory)
     return;
 
   info_attach_exclist (st);
-  
+
   if (incremental_option && archive_format != POSIX_FORMAT)
     blk->header.typeflag = GNUTYPE_DUMPDIR;
   else /* if (standard_option) */
@@ -1198,7 +1199,7 @@ dump_dir0 (struct tar_stat_info *st, char const *directory)
            char const *entry;
            size_t entry_len;
            size_t name_len;
-           
+
            name_buf = xstrdup (st->orig_file_name);
            name_size = name_len = strlen (name_buf);
 
@@ -1837,22 +1838,17 @@ dump_file0 (struct tar_stat_info *st, char const *name, char const *p)
 #ifdef HAVE_READLINK
   else if (S_ISLNK (st->stat.st_mode))
     {
-      char *buffer;
-      int size;
-      size_t linklen = st->stat.st_size;
-      if (linklen != st->stat.st_size || linklen + 1 == 0)
-       xalloc_die ();
-      buffer = (char *) alloca (linklen + 1);
-      size = readlinkat (parentfd, name, buffer, linklen + 1);
-      if (size < 0)
+      st->link_name = areadlinkat_with_size (parentfd, name, st->stat.st_size);
+      if (!st->link_name)
        {
+         if (errno == ENOMEM)
+           xalloc_die ();
          file_removed_diag (p, top_level, readlink_diag);
          return;
        }
-      buffer[size] = '\0';
-      assign_string (&st->link_name, buffer);
       transform_name (&st->link_name, XFORM_SYMLINK);
-      if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < size)
+      if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT)
+         < strlen (st->link_name))
        write_long_link (st);
 
       xattrs_selinux_get (parentfd, name, st, 0);
This page took 0.021972 seconds and 4 git commands to generate.