|
|
995285 |
From 139c528ab8016711b6b59a4460afd0d6b236beb5 Mon Sep 17 00:00:00 2001
|
|
|
995285 |
From: Tim Kientzle <kientzle@acm.org>
|
|
|
995285 |
Date: Sat, 11 Apr 2015 22:44:12 -0700
|
|
|
995285 |
Subject: [PATCH] This is a combination of 2 commits.
|
|
|
995285 |
|
|
|
995285 |
== The first commit's message is: ==
|
|
|
995285 |
|
|
|
995285 |
Issue #522: Dir loop in malformed ISO causes segfault
|
|
|
995285 |
|
|
|
995285 |
Github Issue #522 revealed that we could blow the stack
|
|
|
995285 |
when recursing to assemble ISO paths. I saw this happen
|
|
|
995285 |
at 130,000 dir levels. This patch addresses this by limiting
|
|
|
995285 |
the directory recursion to 1,000 elements.
|
|
|
995285 |
|
|
|
995285 |
TODO: It would be even better to track and detect the dir loop
|
|
|
995285 |
directly.
|
|
|
995285 |
|
|
|
995285 |
== This is the 2nd commit message: ==
|
|
|
995285 |
|
|
|
995285 |
Github Issue #522: Detect cycles in the ISO directory tree
|
|
|
995285 |
---
|
|
|
995285 |
libarchive/archive_read_support_format_iso9660.c | 43 +++++++++++++++++++-----
|
|
|
995285 |
1 file changed, 34 insertions(+), 9 deletions(-)
|
|
|
995285 |
|
|
|
995285 |
diff --git a/libarchive/archive_read_support_format_iso9660.c b/libarchive/archive_read_support_format_iso9660.c
|
|
|
995285 |
index 47268a2..6934cee 100644
|
|
|
995285 |
--- a/libarchive/archive_read_support_format_iso9660.c
|
|
|
995285 |
+++ b/libarchive/archive_read_support_format_iso9660.c
|
|
|
995285 |
@@ -387,7 +387,7 @@ static int archive_read_format_iso9660_read_data(struct archive_read *,
|
|
|
995285 |
static int archive_read_format_iso9660_read_data_skip(struct archive_read *);
|
|
|
995285 |
static int archive_read_format_iso9660_read_header(struct archive_read *,
|
|
|
995285 |
struct archive_entry *);
|
|
|
995285 |
-static const char *build_pathname(struct archive_string *, struct file_info *);
|
|
|
995285 |
+static const char *build_pathname(struct archive_string *, struct file_info *, int);
|
|
|
995285 |
static int build_pathname_utf16be(unsigned char *, size_t, size_t *,
|
|
|
995285 |
struct file_info *);
|
|
|
995285 |
#if DEBUG
|
|
|
995285 |
@@ -1225,6 +1225,7 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
|
|
|
995285 |
archive_set_error(&a->archive,
|
|
|
995285 |
ARCHIVE_ERRNO_FILE_FORMAT,
|
|
|
995285 |
"Pathname is too long");
|
|
|
995285 |
+ return (ARCHIVE_FATAL);
|
|
|
995285 |
}
|
|
|
995285 |
|
|
|
995285 |
r = archive_entry_copy_pathname_l(entry,
|
|
|
995285 |
@@ -1247,9 +1248,16 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
|
|
|
995285 |
rd_r = ARCHIVE_WARN;
|
|
|
995285 |
}
|
|
|
995285 |
} else {
|
|
|
995285 |
- archive_string_empty(&iso9660->pathname);
|
|
|
995285 |
- archive_entry_set_pathname(entry,
|
|
|
995285 |
- build_pathname(&iso9660->pathname, file));
|
|
|
995285 |
+ const char *path = build_pathname(&iso9660->pathname, file, 0);
|
|
|
995285 |
+ if (path == NULL) {
|
|
|
995285 |
+ archive_set_error(&a->archive,
|
|
|
995285 |
+ ARCHIVE_ERRNO_FILE_FORMAT,
|
|
|
995285 |
+ "Pathname is too long");
|
|
|
995285 |
+ return (ARCHIVE_FATAL);
|
|
|
995285 |
+ } else {
|
|
|
995285 |
+ archive_string_empty(&iso9660->pathname);
|
|
|
995285 |
+ archive_entry_set_pathname(entry, path);
|
|
|
995285 |
+ }
|
|
|
995285 |
}
|
|
|
995285 |
|
|
|
995285 |
iso9660->entry_bytes_remaining = file->size;
|
|
|
995285 |
@@ -1744,12 +1752,12 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
|
|
|
995285 |
const unsigned char *isodirrec)
|
|
|
995285 |
{
|
|
|
995285 |
struct iso9660 *iso9660;
|
|
|
995285 |
- struct file_info *file;
|
|
|
995285 |
+ struct file_info *file, *filep;
|
|
|
995285 |
size_t name_len;
|
|
|
995285 |
const unsigned char *rr_start, *rr_end;
|
|
|
995285 |
const unsigned char *p;
|
|
|
995285 |
size_t dr_len;
|
|
|
995285 |
- uint64_t fsize;
|
|
|
995285 |
+ uint64_t fsize, offset;
|
|
|
995285 |
int32_t location;
|
|
|
995285 |
int flags;
|
|
|
995285 |
|
|
|
995285 |
@@ -1793,6 +1801,16 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
|
|
|
995285 |
return (NULL);
|
|
|
995285 |
}
|
|
|
995285 |
|
|
|
995285 |
+ /* Sanity check that this entry does not create a cycle. */
|
|
|
995285 |
+ offset = iso9660->logical_block_size * (uint64_t)location;
|
|
|
995285 |
+ for (filep = parent; filep != NULL; filep = filep->parent) {
|
|
|
995285 |
+ if (filep->offset == offset) {
|
|
|
995285 |
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
|
|
995285 |
+ "Directory structure contains loop");
|
|
|
995285 |
+ return (NULL);
|
|
|
995285 |
+ }
|
|
|
995285 |
+ }
|
|
|
995285 |
+
|
|
|
995285 |
/* Create a new file entry and copy data from the ISO dir record. */
|
|
|
995285 |
file = (struct file_info *)calloc(1, sizeof(*file));
|
|
|
995285 |
if (file == NULL) {
|
|
|
995285 |
@@ -1801,7 +1819,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
|
|
|
995285 |
return (NULL);
|
|
|
995285 |
}
|
|
|
995285 |
file->parent = parent;
|
|
|
995285 |
- file->offset = iso9660->logical_block_size * (uint64_t)location;
|
|
|
995285 |
+ file->offset = offset;
|
|
|
995285 |
file->size = fsize;
|
|
|
995285 |
file->mtime = isodate7(isodirrec + DR_date_offset);
|
|
|
995285 |
file->ctime = file->atime = file->mtime;
|
|
|
995285 |
@@ -3169,10 +3187,17 @@ time_from_tm(struct tm *t)
|
|
|
995285 |
}
|
|
|
995285 |
|
|
|
995285 |
static const char *
|
|
|
995285 |
-build_pathname(struct archive_string *as, struct file_info *file)
|
|
|
995285 |
+build_pathname(struct archive_string *as, struct file_info *file, int depth)
|
|
|
995285 |
{
|
|
|
995285 |
+ // Plain ISO9660 only allows 8 dir levels; if we get
|
|
|
995285 |
+ // to 1000, then something is very, very wrong.
|
|
|
995285 |
+ if (depth > 1000) {
|
|
|
995285 |
+ return NULL;
|
|
|
995285 |
+ }
|
|
|
995285 |
if (file->parent != NULL && archive_strlen(&file->parent->name) > 0) {
|
|
|
995285 |
- build_pathname(as, file->parent);
|
|
|
995285 |
+ if (build_pathname(as, file->parent, depth + 1) == NULL) {
|
|
|
995285 |
+ return NULL;
|
|
|
995285 |
+ }
|
|
|
995285 |
archive_strcat(as, "/");
|
|
|
995285 |
}
|
|
|
995285 |
if (archive_strlen(&file->name) == 0)
|
|
|
995285 |
--
|
|
|
995285 |
2.7.4
|
|
|
995285 |
|