]> Pileus Git - ~andy/linux/blobdiff - fs/udf/super.c
Linux 3.14
[~andy/linux] / fs / udf / super.c
index 91219385691d8f80d1db9aed3973183bb931a48d..3306b9f69bedbb5ba2cb4e11b180b2b75e947dd5 100644 (file)
@@ -76,6 +76,9 @@
 
 #define UDF_DEFAULT_BLOCKSIZE 2048
 
+#define VSD_FIRST_SECTOR_OFFSET                32768
+#define VSD_MAX_SECTOR_OFFSET          0x800000
+
 enum { UDF_MAX_LINKS = 0xffff };
 
 /* These are the "meat" - everything else is stuffing */
@@ -685,7 +688,7 @@ out_unlock:
 static loff_t udf_check_vsd(struct super_block *sb)
 {
        struct volStructDesc *vsd = NULL;
-       loff_t sector = 32768;
+       loff_t sector = VSD_FIRST_SECTOR_OFFSET;
        int sectorsize;
        struct buffer_head *bh = NULL;
        int nsr02 = 0;
@@ -703,8 +706,18 @@ static loff_t udf_check_vsd(struct super_block *sb)
        udf_debug("Starting at sector %u (%ld byte sectors)\n",
                  (unsigned int)(sector >> sb->s_blocksize_bits),
                  sb->s_blocksize);
-       /* Process the sequence (if applicable) */
-       for (; !nsr02 && !nsr03; sector += sectorsize) {
+       /* Process the sequence (if applicable). The hard limit on the sector
+        * offset is arbitrary, hopefully large enough so that all valid UDF
+        * filesystems will be recognised. There is no mention of an upper
+        * bound to the size of the volume recognition area in the standard.
+        *  The limit will prevent the code to read all the sectors of a
+        * specially crafted image (like a bluray disc full of CD001 sectors),
+        * potentially causing minutes or even hours of uninterruptible I/O
+        * activity. This actually happened with uninitialised SSD partitions
+        * (all 0xFF) before the check for the limit and all valid IDs were
+        * added */
+       for (; !nsr02 && !nsr03 && sector < VSD_MAX_SECTOR_OFFSET;
+            sector += sectorsize) {
                /* Read a block */
                bh = udf_tread(sb, sector >> sb->s_blocksize_bits);
                if (!bh)
@@ -714,10 +727,7 @@ static loff_t udf_check_vsd(struct super_block *sb)
                vsd = (struct volStructDesc *)(bh->b_data +
                                              (sector & (sb->s_blocksize - 1)));
 
-               if (vsd->stdIdent[0] == 0) {
-                       brelse(bh);
-                       break;
-               } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001,
+               if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001,
                                    VSD_STD_ID_LEN)) {
                        switch (vsd->structType) {
                        case 0:
@@ -753,6 +763,17 @@ static loff_t udf_check_vsd(struct super_block *sb)
                else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR03,
                                    VSD_STD_ID_LEN))
                        nsr03 = sector;
+               else if (!strncmp(vsd->stdIdent, VSD_STD_ID_BOOT2,
+                                   VSD_STD_ID_LEN))
+                       ; /* nothing */
+               else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CDW02,
+                                   VSD_STD_ID_LEN))
+                       ; /* nothing */
+               else {
+                       /* invalid id : end of volume recognition area */
+                       brelse(bh);
+                       break;
+               }
                brelse(bh);
        }
 
@@ -760,7 +781,8 @@ static loff_t udf_check_vsd(struct super_block *sb)
                return nsr03;
        else if (nsr02)
                return nsr02;
-       else if (sector - (sbi->s_session << sb->s_blocksize_bits) == 32768)
+       else if (!bh && sector - (sbi->s_session << sb->s_blocksize_bits) ==
+                       VSD_FIRST_SECTOR_OFFSET)
                return -1;
        else
                return 0;
@@ -1270,6 +1292,9 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block)
         * PHYSICAL partitions are already set up
         */
        type1_idx = i;
+#ifdef UDFFS_DEBUG
+       map = NULL; /* supress 'maybe used uninitialized' warning */
+#endif
        for (i = 0; i < sbi->s_partitions; i++) {
                map = &sbi->s_partmaps[i];
 
@@ -1891,7 +1916,9 @@ static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt,
                        return 0;
                }
                if (nsr_off == -1)
-                       udf_debug("Failed to read byte 32768. Assuming open disc. Skipping validity check\n");
+                       udf_debug("Failed to read sector at offset %d. "
+                                 "Assuming open disc. Skipping validity "
+                                 "check\n", VSD_FIRST_SECTOR_OFFSET);
                if (!sbi->s_last_block)
                        sbi->s_last_block = udf_get_last_block(sb);
        } else {