static int isSVD(struct iso9660 *, const unsigned char *);
static int isEVD(struct iso9660 *, const unsigned char *);
static int isPVD(struct iso9660 *, const unsigned char *);
+static int isRootDirectoryRecord(const unsigned char *);
+static int isValid723Integer(const unsigned char *);
+static int isValid733Integer(const unsigned char *);
static int next_cache_entry(struct archive_read *, struct iso9660 *,
struct file_info **);
static int next_entry_seek(struct archive_read *, struct iso9660 *,
/* Read Root Directory Record in Volume Descriptor. */
p = h + SVD_root_directory_record_offset;
- if (p[DR_length_offset] != 34)
+ if (!isRootDirectoryRecord(p)) {
return (0);
+ }
return (48);
}
/* Read Root Directory Record in Volume Descriptor. */
p = h + PVD_root_directory_record_offset;
- if (p[DR_length_offset] != 34)
+ if (!isRootDirectoryRecord(p)) {
return (0);
+ }
return (48);
}
if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))
return (0);
+ /* Volume space size must be encoded according to 7.3.3 */
+ if (!isValid733Integer(h + PVD_volume_space_size_offset)) {
+ return (0);
+ }
+ volume_block = archive_le32dec(h + PVD_volume_space_size_offset);
+ if (volume_block <= SYSTEM_AREA_BLOCK+4)
+ return (0);
+
/* Reserved field must be 0. */
if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))
return (0);
+ /* Volume set size must be encoded according to 7.2.3 */
+ if (!isValid723Integer(h + PVD_volume_set_size_offset)) {
+ return (0);
+ }
+
+ /* Volume sequence number must be encoded according to 7.2.3 */
+ if (!isValid723Integer(h + PVD_volume_sequence_number_offset)) {
+ return (0);
+ }
+
/* Logical block size must be > 0. */
/* I've looked at Ecma 119 and can't find any stronger
* restriction on this field. */
+ if (!isValid723Integer(h + PVD_logical_block_size_offset)) {
+ return (0);
+ }
logical_block_size =
archive_le16dec(h + PVD_logical_block_size_offset);
if (logical_block_size <= 0)
return (0);
- volume_block = archive_le32dec(h + PVD_volume_space_size_offset);
- if (volume_block <= SYSTEM_AREA_BLOCK+4)
+ /* Path Table size must be encoded according to 7.3.3 */
+ if (!isValid733Integer(h + PVD_path_table_size_offset)) {
return (0);
+ }
/* File structure version must be 1 for ISO9660/ECMA119. */
if (h[PVD_file_structure_version_offset] != 1)
/* Read Root Directory Record in Volume Descriptor. */
p = h + PVD_root_directory_record_offset;
- if (p[DR_length_offset] != 34)
+ if (!isRootDirectoryRecord(p)) {
return (0);
+ }
if (!iso9660->primary.location) {
iso9660->logical_block_size = logical_block_size;
return (48);
}
+static int
+isRootDirectoryRecord(const unsigned char *p) {
+ int flags;
+
+ /* ECMA119/ISO9660 requires that the root directory record be _exactly_ 34 bytes.
+ * However, we've seen images that have root directory records up to 68 bytes. */
+ if (p[DR_length_offset] < 34 || p[DR_length_offset] > 68) {
+ return (0);
+ }
+
+ /* The root directory location must be a 7.3.3 32-bit integer. */
+ if (!isValid733Integer(p + DR_extent_offset)) {
+ return (0);
+ }
+
+ /* The root directory size must be a 7.3.3 integer. */
+ if (!isValid733Integer(p + DR_size_offset)) {
+ return (0);
+ }
+
+ /* According to the standard, certain bits must be one or zero:
+ * Bit 1: must be 1 (this is a directory)
+ * Bit 2: must be 0 (not an associated file)
+ * Bit 3: must be 0 (doesn't use extended attribute record)
+ * Bit 7: must be 0 (final directory record for this file)
+ */
+ flags = p[DR_flags_offset];
+ if ((flags & 0x8E) != 0x02) {
+ return (0);
+ }
+
+ /* Volume sequence number must be a 7.2.3 integer. */
+ if (!isValid723Integer(p + DR_volume_sequence_number_offset)) {
+ return (0);
+ }
+
+ /* Root directory name is a single zero byte... */
+ if (p[DR_name_len_offset] != 1 || p[DR_name_offset] != 0) {
+ return (0);
+ }
+
+ /* Nothing looked wrong, so let's accept it. */
+ return (1);
+}
+
static int
read_children(struct archive_read *a, struct file_info *parent)
{
return (0);
}
+/*
+ * ECMA119/ISO9660 stores multi-byte integers in one of
+ * three different formats:
+ * * Little-endian (specified in section 7.2.1 and 7.3.1)
+ * * Big-endian (specified in section 7.2.2 and 7.3.2)
+ * * Both (specified in section 7.2.3 and 7.3.3)
+ *
+ * For values that follow section 7.2.3 (16-bit) or 7.3.3 (32-bit), we
+ * can check that the little-endian and big-endian forms agree with
+ * each other. This helps us avoid trying to decode files that are
+ * not really ISO images.
+ */
+static int
+isValid723Integer(const unsigned char *p) {
+ return (p[0] == p[3] && p[1] == p[2]);
+}
+
+static int
+isValid733Integer(const unsigned char *p)
+{
+ return (p[0] == p[7]
+ && p[1] == p[6]
+ && p[2] == p[5]
+ && p[3] == p[4]);
+}
+
static time_t
isodate7(const unsigned char *v)
{
--- /dev/null
+Same as test_read_format_iso_2.iso.Z except that the root directory record
+size in the PVD has been changed to 68 bytes (instead of the 34 required
+by the standard). This non-standard value was seen in the wild.
+
+begin 644 test_read_format_iso_3.iso.Z
+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
+".`$`
+`
+end