udf: Avoid invalid LVID used on mount
[linux-2.6-microblaze.git] / fs / udf / super.c
index 0a15ea4..14ed670 100644 (file)
@@ -1539,6 +1539,20 @@ out_bh:
        return ret;
 }
 
+static bool udf_lvid_valid(struct super_block *sb,
+                          struct logicalVolIntegrityDesc *lvid)
+{
+       u32 parts, impuselen;
+
+       parts = le32_to_cpu(lvid->numOfPartitions);
+       impuselen = le32_to_cpu(lvid->lengthOfImpUse);
+       if (parts >= sb->s_blocksize || impuselen >= sb->s_blocksize ||
+           sizeof(struct logicalVolIntegrityDesc) + impuselen +
+           2 * parts * sizeof(u32) > sb->s_blocksize)
+               return false;
+       return true;
+}
+
 /*
  * Find the prevailing Logical Volume Integrity Descriptor.
  */
@@ -1549,7 +1563,6 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_
        struct udf_sb_info *sbi = UDF_SB(sb);
        struct logicalVolIntegrityDesc *lvid;
        int indirections = 0;
-       u32 parts, impuselen;
 
        while (++indirections <= UDF_MAX_LVID_NESTING) {
                final_bh = NULL;
@@ -1571,32 +1584,27 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_
                if (!final_bh)
                        return;
 
-               brelse(sbi->s_lvid_bh);
-               sbi->s_lvid_bh = final_bh;
-
                lvid = (struct logicalVolIntegrityDesc *)final_bh->b_data;
+               if (udf_lvid_valid(sb, lvid)) {
+                       brelse(sbi->s_lvid_bh);
+                       sbi->s_lvid_bh = final_bh;
+               } else {
+                       udf_warn(sb, "Corrupted LVID (parts=%u, impuselen=%u), "
+                                "ignoring.\n",
+                                le32_to_cpu(lvid->numOfPartitions),
+                                le32_to_cpu(lvid->lengthOfImpUse));
+               }
+
                if (lvid->nextIntegrityExt.extLength == 0)
-                       goto check;
+                       return;
 
                loc = leea_to_cpu(lvid->nextIntegrityExt);
        }
 
        udf_warn(sb, "Too many LVID indirections (max %u), ignoring.\n",
                UDF_MAX_LVID_NESTING);
-out_err:
        brelse(sbi->s_lvid_bh);
        sbi->s_lvid_bh = NULL;
-       return;
-check:
-       parts = le32_to_cpu(lvid->numOfPartitions);
-       impuselen = le32_to_cpu(lvid->lengthOfImpUse);
-       if (parts >= sb->s_blocksize || impuselen >= sb->s_blocksize ||
-           sizeof(struct logicalVolIntegrityDesc) + impuselen +
-           2 * parts * sizeof(u32) > sb->s_blocksize) {
-               udf_warn(sb, "Corrupted LVID (parts=%u, impuselen=%u), "
-                        "ignoring.\n", parts, impuselen);
-               goto out_err;
-       }
 }
 
 /*