bug-tar
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Bug-tar] [PATCH] Option to treat tarbombs as errors


From: Connor Behan
Subject: [Bug-tar] [PATCH] Option to treat tarbombs as errors
Date: Sat, 5 Oct 2013 19:40:09 -0700

* src/common.h (one_top_level_option): New global.
* src/extract.c (extract_archive): If one_top_level_option is set, check
for whether the archive tries to create two file trees.
* src/tar.c (ONE_TOP_LEVEL_OPTION): New constant.
(options): New option --one-top-level.
(parse_opt): Handle this option.
(decode_options): Make it conflict with --absolute-names.

* NEWS: Update.
* doc/tar.texi: Document new option.
---
 NEWS          | 10 ++++++++++
 doc/tar.texi  |  9 +++++++++
 src/common.h  |  3 +++
 src/extract.c | 43 +++++++++++++++++++++++++++++++++++++++++++
 src/tar.c     | 10 ++++++++++
 5 files changed, 75 insertions(+)

diff --git a/NEWS b/NEWS
index ffeb4b8..88f8d2c 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,16 @@
 GNU tar NEWS - User visible changes. 2013-10-05
 Please send GNU tar bug reports to <address@hidden>
 
+
+version 1.27.90 (Git)
+
+* The --one-top-level option.
+
+This new command line option tells tar that the working directory
+(or the one passed to -C) should not be populated with more than one
+name directly under it. A fatal error is thrown if, after name
+transformations, a second member that would be extracted to this location
+is found.
 
 version 1.27 - Sergey Poznyakoff, 2013-10-05
 
diff --git a/doc/tar.texi b/doc/tar.texi
index 9fde5a0..86d7064 100644
--- a/doc/tar.texi
+++ b/doc/tar.texi
@@ -3086,6 +3086,15 @@ Used when creating an archive.  Prevents @command{tar} 
from recursing into
 directories that are on different file systems from the current
 directory.
 
address@hidden
address@hidden --one-top-level
+
+Tells @command{tar} that only one name from the archive should be placed 
directly
+under the extraction directory (the working directory or the one specified with
address@hidden). A fatal error is thrown if a second one is found. The 
top-level of
+a member is determined after the transformations from 
@option{--strip-components}
+and @option{--transform} are applied.
+
 @opsummary{overwrite}
 @item --overwrite
 
diff --git a/src/common.h b/src/common.h
index eb801bb..fcf1b7d 100644
--- a/src/common.h
+++ b/src/common.h
@@ -235,6 +235,9 @@ GLOBAL bool numeric_owner_option;
 
 GLOBAL bool one_file_system_option;
 
+/* Refuse to extract more than one top-level name.  */
+GLOBAL bool one_top_level_option;
+
 /* Specified value to be put into tar file in place of stat () results, or
    just null and -1 if such an override should not take place.  */
 GLOBAL char const *owner_name_option;
diff --git a/src/extract.c b/src/extract.c
index 9b6b7f9..ea5be67 100644
--- a/src/extract.c
+++ b/src/extract.c
@@ -1578,6 +1578,45 @@ prepare_to_extract (char const *file_name, int typeflag, 
tar_extractor_t *fun)
   return 1;
 }
 
+/* Throws an error if passed file name is the second top-level name.  */
+void
+depth_check (char *file_name)
+{
+  size_t i;
+  size_t start = 0;
+
+  static char *first_top_level;
+  static bool first_top_level_found = false;
+
+  /* Leading slashes have already been removed so it is safe to start at 1.  */
+  for (i = 1; i <= strlen (file_name); i++)
+    {
+      if (ISSLASH (file_name[i]) || file_name[i] == '\0')
+        {
+         if ((i == start) || (i - start == 1 && file_name[start] == '.'))
+           start = i + 1;
+         else
+           {
+             if (first_top_level_found)
+               {
+                 /* Still reject two top-levels if one is a substring of the 
other.  */
+                 if (strncmp (first_top_level, file_name + start, i - start)
+                     || strlen (first_top_level) != i - start)
+                     FATAL_ERROR  ((0, 0, _("Found multiple top-level names, 
exiting")));
+               }
+             else
+               {
+                 first_top_level_found = true;
+                 first_top_level = xmalloc (i - start + 1);
+                 strncpy (first_top_level, file_name + start, i - start);
+                 first_top_level[i - start] = '\0';
+               }
+             return;
+           }
+       }
+    }
+}
+
 /* Extract a file from the archive.  */
 void
 extract_archive (void)
@@ -1623,6 +1662,10 @@ extract_archive (void)
        return;
       }
 
+  /* Check for names where the depth is too high.  */
+  if (one_top_level_option)
+    depth_check (current_stat_info.file_name);
+
   /* Extract the archive entry according to its type.  */
   /* KLUDGE */
   typeflag = sparse_member_p (&current_stat_info) ?
diff --git a/src/tar.c b/src/tar.c
index 4f5017d..8c3014e 100644
--- a/src/tar.c
+++ b/src/tar.c
@@ -319,6 +319,7 @@ enum
   OCCURRENCE_OPTION,
   OLD_ARCHIVE_OPTION,
   ONE_FILE_SYSTEM_OPTION,
+  ONE_TOP_LEVEL_OPTION,
   OVERWRITE_DIR_OPTION,
   OVERWRITE_OPTION,
   OWNER_OPTION,
@@ -489,6 +490,8 @@ static struct argp_option options[] = {
   {"keep-directory-symlink", KEEP_DIRECTORY_SYMLINK_OPTION, 0, 0,
    N_("preserve existing symlinks to directories when extracting"),
    GRID+1 },
+  {"one-top-level", ONE_TOP_LEVEL_OPTION, 0, 0,
+   N_("allow at most one top-level name when extracting"), GRID+1 },
 #undef GRID
 
 #define GRID 40
@@ -1438,6 +1441,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
       one_file_system_option = true;
       break;
 
+    case ONE_TOP_LEVEL_OPTION:
+      one_top_level_option = true;
+      break;
+
     case 'l':
       check_links_option = 1;
       break;
@@ -2390,6 +2397,9 @@ decode_options (int argc, char **argv)
                      subcommand_string (subcommand_option)));
     }
 
+  if (one_top_level_option && absolute_names_option)
+    USAGE_ERROR ((0, 0, _("--one-top-level cannot be used with 
--absolute-names")));
+
   if (archive_names == 0)
     {
       /* If no archive file name given, try TAPE from the environment, or
-- 
1.8.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]