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