Attempt n.2 :
Created a function that walks the whole path. If anything not-directory is
found, return an error. If the path is not fully created, we consider that
a success and let cpio decides when time has come.
Files will be skipped if no-absolute-path is set and error is return.

On Wed, Jun 7, 2017 at 10:46 AM, Pavel Raiskup <prais...@redhat.com> wrote:

> On Wednesday, June 7, 2017 10:07:21 AM CEST Cedric Buissart wrote:
> > > In other words and IMO, if we were about to fix this issue - we should
> only
> > > refuse to extract files through symlinks.
> >
> > Through any symlinks, or only those created by the archive itself ?
>
> Remembering the extracted links might be expensive, and with
> --no-absolute-filenames we want to stay in CWD anyway - no matter how the
> links
> in CWD were created.
>
> > The latter might look less restrictive, but what happens if a local
> > attacker is able to create a symlink. Is it something that should be
> > considered ?
>
> Usually user should avoid races manually when running archiver:
> https://www.gnu.org/software/tar/manual/html_node/Race-conditions.html

based on the above, I did not try to avoid races.

>
>
> Pavel
>
>
>
>


-- 
Cedric Buissart,
Product Security
commit 3fa889b71dd543b70c511d9b84894bd096061d51
Author: Cedric Buissart <cedric.buiss...@gmail.com>
Date:   Thu Jun 15 21:00:43 2017 +0200

    Prevent symlink follow when no-absolute-path

diff --git a/src/copyin.c b/src/copyin.c
index 38d809f..809b9e9 100644
--- a/src/copyin.c
+++ b/src/copyin.c
@@ -1465,6 +1465,16 @@ process_copy_in ()
 		}
 	    }
 
+
+#ifdef CP_IFLNK
+      /*  no_abs_paths_flag prevents us to follow symlink */
+      if (no_abs_paths_flag && existing_path_has_symlink(file_hdr.c_name) == -1) {
+          error (0, 0, _("%s not created: symlink in its path"), 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;
+      }
+#endif
 	  copyin_file(&file_hdr, in_file_des);
 
 	  if (verbose_flag)
diff --git a/src/util.c b/src/util.c
index 18b3e42..dd04edf 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1627,3 +1627,45 @@ change_dir ()
 	     _("cannot change to directory `%s'"), change_directory_option);
     }
 }
+
+#ifdef CP_IFLNK
+/*  existing_path_has_symlink will walk the path as far as possible. 
+ * returns -1 if unexpected error or if any non-directory is found on the way 
+ * (with the exception of the filename)
+ * returns 0 otherwise
+ * Note: if part of the path is missing, it's ok, cpio might be allowed to create it
+ */
+int existing_path_has_symlink(char* path) {
+    int ret = 0;
+    struct stat stat;
+    char *next, *dup;
+    dup = malloc((strlen(path)+1) * sizeof(char));
+    if (! dup)
+        return -1;
+
+    next = path;
+    while (1) {
+        next = strchr(next, '/');
+        if (! next) {
+            break;
+        }
+        strncpy(dup, path, next - path);
+        dup[next - path] = '\0';
+        if ( lstat(dup, &stat) != 0) {
+            /* only ENOENT is expected here (we let cpio create path if required */
+            if ( errno != ENOENT ) 
+                ret = -1;
+            break;
+        }
+
+        if ( ! S_ISDIR(stat.st_mode) ) {
+            ret = -1;
+            break;
+        }
+        next++;
+    }
+
+    free(dup);
+    return ret;
+}
+#endif

Reply via email to