Blame SOURCES/libarchive-3.1.2-CVE-2016-5418-variation.patch

58251f
commit 3c378bb5e4ea8d4c9a5345083f278882322f9c9b
58251f
Author: Doran Moppert <dmoppert@redhat.com>
58251f
Date:   Fri Aug 12 13:58:57 2016 +0930
58251f
58251f
    Fix for hardlinks with .. in target path
58251f
     - factor cleanup_pathname into cleanup_pathname_fsobj
58251f
     - rename check_path_for_symlinks to check_path_fsobj for consistency
58251f
58251f
diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c
58251f
index 66fc0f5..37261a5 100644
58251f
--- a/libarchive/archive_write_disk_posix.c
58251f
+++ b/libarchive/archive_write_disk_posix.c
58251f
@@ -326,13 +326,14 @@ struct archive_write_disk {
58251f
 
58251f
 #define HFS_BLOCKS(s)	((s) >> 12)
58251f
 
58251f
-static int check_path_for_symlinks(char *path, int *error_number, struct archive_string *error_string, int flags);
58251f
+static int	check_symlinks_fsobj(char *path, int *error_number, struct archive_string *error_string, int flags);
58251f
 static int	check_symlinks(struct archive_write_disk *);
58251f
 static int	create_filesystem_object(struct archive_write_disk *);
58251f
 static struct fixup_entry *current_fixup(struct archive_write_disk *, const char *pathname);
58251f
 #if defined(HAVE_FCHDIR) && defined(PATH_MAX)
58251f
 static void	edit_deep_directories(struct archive_write_disk *ad);
58251f
 #endif
58251f
+static int	cleanup_pathname_fsobj(char *path, int *error_number, struct archive_string *error_string, int flags);
58251f
 static int	cleanup_pathname(struct archive_write_disk *);
58251f
 static int	create_dir(struct archive_write_disk *, char *);
58251f
 static int	create_parent_dir(struct archive_write_disk *, char *);
58251f
@@ -1997,7 +1998,7 @@ create_filesystem_object(struct archive_write_disk *a)
58251f
 	const char *linkname;
58251f
 	mode_t final_mode, mode;
58251f
 	int r;
58251f
-	/* these for check_path_for_symlinks */
58251f
+	/* these for check_symlinks_fsobj */
58251f
 	char *linkname_copy;	/* non-const copy of linkname */
58251f
 	struct archive_string error_string;
58251f
 	int error_number;
58251f
@@ -2014,13 +2015,22 @@ create_filesystem_object(struct archive_write_disk *a)
58251f
 		if (linkname_copy == NULL) {
58251f
 		    return (EPERM);
58251f
 		}
58251f
-		r = check_path_for_symlinks(linkname_copy, &error_number, &error_string, a->flags);
58251f
-		free(linkname_copy);
58251f
+		/* TODO: consider using the cleaned-up path as the link target? */
58251f
+		r = cleanup_pathname_fsobj(linkname_copy, &error_number, &error_string, a->flags);
58251f
+		if (r != ARCHIVE_OK) {
58251f
+			archive_set_error(&a->archive, error_number, "%s", error_string.s);
58251f
+			free(linkname_copy);
58251f
+			/* EPERM is more appropriate than error_number for our callers */
58251f
+			return (EPERM);
58251f
+		}
58251f
+		r = check_symlinks_fsobj(linkname_copy, &error_number, &error_string, a->flags);
58251f
 		if (r != ARCHIVE_OK) {
58251f
 			archive_set_error(&a->archive, error_number, "%s", error_string.s);
58251f
+			free(linkname_copy);
58251f
 			/* EPERM is more appropriate than error_number for our callers */
58251f
 			return (EPERM);
58251f
 		}
58251f
+		free(linkname_copy);
58251f
 		r = link(linkname, a->name) ? errno : 0;
58251f
 		/*
58251f
 		 * New cpio and pax formats allow hardlink entries
58251f
@@ -2365,7 +2375,8 @@ current_fixup(struct archive_write_disk *a, const char *pathname)
58251f
  * Checks the given path to see if any elements along it are symlinks.  Returns
58251f
  * ARCHIVE_OK if there are none, otherwise puts an error in errmsg.
58251f
  */
58251f
-static int check_path_for_symlinks(char *path, int *error_number, struct archive_string *error_string, int flags)
58251f
+static int
58251f
+check_symlinks_fsobj(char *path, int *error_number, struct archive_string *error_string, int flags)
58251f
 {
58251f
 #if !defined(HAVE_LSTAT)
58251f
 	/* Platform doesn't have lstat, so we can't look for symlinks. */
58251f
@@ -2558,7 +2569,7 @@ check_symlinks(struct archive_write_disk *a)
58251f
 	int error_number;
58251f
 	int rc;
58251f
 	archive_string_init(&error_string);
58251f
-	rc = check_path_for_symlinks(a->name, &error_number, &error_string, a->flags);
58251f
+	rc = check_symlinks_fsobj(a->name, &error_number, &error_string, a->flags);
58251f
 	if (rc != ARCHIVE_OK) {
58251f
 		archive_set_error(&a->archive, error_number, "%s", error_string.s);
58251f
 	}
58251f
@@ -2640,15 +2651,17 @@ cleanup_pathname_win(struct archive_write_disk *a)
58251f
  * set) any '..' in the path.
58251f
  */
58251f
 static int
58251f
-cleanup_pathname(struct archive_write_disk *a)
58251f
+cleanup_pathname_fsobj(char *path, int *error_number, struct archive_string *error_string, int flags)
58251f
 {
58251f
 	char *dest, *src;
58251f
 	char separator = '\0';
58251f
 
58251f
-	dest = src = a->name;
58251f
+	dest = src = path;
58251f
 	if (*src == '\0') {
58251f
-		archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
58251f
-		    "Invalid empty pathname");
58251f
+		if (error_number) *error_number = ARCHIVE_ERRNO_MISC;
58251f
+		if (error_string)
58251f
+			archive_string_sprintf(error_string,
58251f
+				"Invalid empty pathname");
58251f
 		return (ARCHIVE_FAILED);
58251f
 	}
58251f
 
58251f
@@ -2679,10 +2692,11 @@ cleanup_pathname(struct archive_write_disk *a)
58251f
 			} else if (src[1] == '.') {
58251f
 				if (src[2] == '/' || src[2] == '\0') {
58251f
 					/* Conditionally warn about '..' */
58251f
-					if (a->flags & ARCHIVE_EXTRACT_SECURE_NODOTDOT) {
58251f
-						archive_set_error(&a->archive,
58251f
-						    ARCHIVE_ERRNO_MISC,
58251f
-						    "Path contains '..'");
58251f
+					if (flags & ARCHIVE_EXTRACT_SECURE_NODOTDOT) {
58251f
+						if (error_number) *error_number = ARCHIVE_ERRNO_MISC;
58251f
+						if (error_string)
58251f
+							archive_string_sprintf(error_string,
58251f
+								"Path contains '..'");
58251f
 						return (ARCHIVE_FAILED);
58251f
 					}
58251f
 				}
58251f
@@ -2713,7 +2727,7 @@ cleanup_pathname(struct archive_write_disk *a)
58251f
 	 * We've just copied zero or more path elements, not including the
58251f
 	 * final '/'.
58251f
 	 */
58251f
-	if (dest == a->name) {
58251f
+	if (dest == path) {
58251f
 		/*
58251f
 		 * Nothing got copied.  The path must have been something
58251f
 		 * like '.' or '/' or './' or '/././././/./'.
58251f
@@ -2728,6 +2742,21 @@ cleanup_pathname(struct archive_write_disk *a)
58251f
 	return (ARCHIVE_OK);
58251f
 }
58251f
 
58251f
+static int
58251f
+cleanup_pathname(struct archive_write_disk *a)
58251f
+{
58251f
+	struct archive_string error_string;
58251f
+	int error_number;
58251f
+	int rc;
58251f
+	archive_string_init(&error_string);
58251f
+	rc = cleanup_pathname_fsobj(a->name, &error_number, &error_string, a->flags);
58251f
+	if (rc != ARCHIVE_OK) {
58251f
+		archive_set_error(&a->archive, error_number, "%s", error_string.s);
58251f
+	}
58251f
+	archive_string_free(&error_string);
58251f
+	return rc;
58251f
+}
58251f
+
58251f
 /*
58251f
  * Create the parent directory of the specified path, assuming path
58251f
  * is already in mutable storage.