From: Michihiro NAKAJIMA Date: Thu, 24 Nov 2011 04:03:55 +0000 (-0500) Subject: Issue 199: Improve robustness against corrupted ISO images. X-Git-Tag: v3.0.1b~22 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=60ce19ccace48cd7a20fd1e1fc54b1b674de427f;p=thirdparty%2Flibarchive.git 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 --- diff --git a/libarchive/archive_read_support_format_iso9660.c b/libarchive/archive_read_support_format_iso9660.c index 247cdd7aa..63ecd88ab 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);