diff options
author | Michihiro NAKAJIMA <ggcueroad@gmail.com> | 2011-11-23 23:03:55 -0500 |
---|---|---|
committer | Michihiro NAKAJIMA <ggcueroad@gmail.com> | 2011-11-23 23:03:55 -0500 |
commit | 60ce19ccace48cd7a20fd1e1fc54b1b674de427f (patch) | |
tree | 320a1ae0955529c4983aedc79b5bf43ed546d62e /libarchive/archive_read_support_format_iso9660.c | |
parent | e01d746c3060b12aa8d001c4586ef0ca194f4074 (diff) | |
download | libarchive-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.c | 92 |
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); |