summaryrefslogtreecommitdiff
path: root/libarchive/archive_read_support_format_iso9660.c
diff options
context:
space:
mode:
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>2011-11-23 23:03:55 -0500
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>2011-11-23 23:03:55 -0500
commit60ce19ccace48cd7a20fd1e1fc54b1b674de427f (patch)
tree320a1ae0955529c4983aedc79b5bf43ed546d62e /libarchive/archive_read_support_format_iso9660.c
parente01d746c3060b12aa8d001c4586ef0ca194f4074 (diff)
downloadlibarchive-60ce19ccace48cd7a20fd1e1fc54b1b674de427f.tar.gz
Issue 199: Improve robustness against corrupted ISO images.
- Back out r3823. it was not insufficient for such corrupted ISO images. - Check "RE" extension strictly: stop just clearing "RE" extension as if it were not defined. - Check "CL" extension strictly: * "CL" does not point at itself. * "CL" does not point at its parents. * A directory file cannot have "CL" extension. * A file which has "CL" extension is not on the top level of a directory tree. SVN-Revision: 3835
Diffstat (limited to 'libarchive/archive_read_support_format_iso9660.c')
-rw-r--r--libarchive/archive_read_support_format_iso9660.c92
1 files changed, 75 insertions, 17 deletions
diff --git a/libarchive/archive_read_support_format_iso9660.c b/libarchive/archive_read_support_format_iso9660.c
index 247cdd7a..63ecd88a 100644
--- a/libarchive/archive_read_support_format_iso9660.c
+++ b/libarchive/archive_read_support_format_iso9660.c
@@ -305,8 +305,6 @@ struct file_info {
struct file_info *first;
struct file_info **last;
} rede_files;
- /* To check a ininity loop. */
- struct file_info *loop_by;
};
struct heap_queue {
@@ -1924,26 +1922,82 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
file->re = 0;
parent->subdirs--;
} else if (file->re) {
- /* This file's parent is not rr_moved, clear invalid
- * "RE" mark. */
- if (parent == NULL || parent->rr_moved == 0)
- file->re = 0;
- else if ((flags & 0x02) == 0) {
- file->rr_moved_has_re_only = 0;
- file->re = 0;
+ /*
+ * Sanity check: file's parent is rr_moved.
+ */
+ if (parent == NULL || parent->rr_moved == 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Invalid Rockridge RE");
+ return (NULL);
+ }
+ /*
+ * Sanity check: file does not have "CL" extension.
+ */
+ if (file->cl_offset) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Invalid Rockridge RE and CL");
+ return (NULL);
+ }
+ /*
+ * Sanity check: The file type must be a directory.
+ */
+ if ((flags & 0x02) == 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Invalid Rockridge RE");
+ return (NULL);
}
} else if (parent != NULL && parent->rr_moved)
file->rr_moved_has_re_only = 0;
else if (parent != NULL && (flags & 0x02) &&
(parent->re || parent->re_descendant))
file->re_descendant = 1;
- if (parent != NULL && file->cl_offset != 0) {
+ if (file->cl_offset) {
+ struct file_info *p;
+
+ if (parent == NULL || parent->parent == NULL) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Invalid Rockridge CL");
+ return (NULL);
+ }
+ /*
+ * Sanity check: The file type must be a regular file.
+ */
+ if ((flags & 0x02) != 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Invalid Rockridge CL");
+ return (NULL);
+ }
parent->subdirs++;
/* Overwrite an offset and a number of this "CL" entry
* to appear before other dirs. "+1" to those is to
* make sure to appear after "RE" entry which this
* "CL" entry should be connected with. */
file->offset = file->number = file->cl_offset + 1;
+
+ /*
+ * Sanity check: cl_offset does not point at its
+ * the parents or itself.
+ */
+ for (p = parent; p; p = p->parent) {
+ if (p->offset == file->cl_offset) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Invalid Rockridge CL");
+ return (NULL);
+ }
+ }
+ if (file->cl_offset == file->offset ||
+ parent->rr_moved) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Invalid Rockridge CL");
+ return (NULL);
+ }
}
}
@@ -2047,6 +2101,13 @@ parse_rockridge(struct archive_read *a, struct file_info *file,
*/
break;
}
+ if (p[0] == 'P' && p[1] == 'L') {
+ /*
+ * PL extension won't appear;
+ * contents are always ignored.
+ */
+ break;
+ }
if (p[0] == 'P' && p[1] == 'N') {
if (version == 1 && data_length == 16) {
file->rdev = toi(data,4);
@@ -2840,15 +2901,12 @@ rede_add_entry(struct file_info *file)
{
struct file_info *re;
+ /*
+ * Find "RE" entry.
+ */
re = file->parent;
- while (re != NULL && !re->re) {
- /* Sanity check to prevent a infinity loop
- * cause by a currupted iso file. */
- if (re->loop_by == file)
- return (-1);
- re->loop_by = file;
+ while (re != NULL && !re->re)
re = re->parent;
- }
if (re == NULL)
return (-1);