History

udf: Prevent stack overflow on corrupted filesystem mount

Presently, a corrupted or malicious UDF filesystem containing a very large number (or cycle) of Logical Volume Integrity Descriptor extent indirections may trigger a stack overflow and kernel panic in udf_load_logicalvolint() on mount. Replace the unnecessary recursion in udf_load_logicalvolint() with simple iteration. Set an arbitrary limit of 1000 indirections (which would have almost certainly overflowed the stack without this fix), and treat such cases as if there were no LVID.

Alden Tondettar committed 10 years ago

Commit a47241c1 parent c26f6c61 file · +43 −24Browse files

Unified · Split

fs/udf/super.c+43−24
@@ -78,6 +78,15 @@ · 77 unmodified lines
7878 #define VSD_FIRST_SECTOR_OFFSET 32768
7979 #define VSD_MAX_SECTOR_OFFSET 0x800000
8080
81+/*
82+ * Maximum number of Terminating Descriptor / Logical Volume Integrity
83+ * Descriptor redirections. The chosen numbers are arbitrary - just that we
84+ * hopefully don't limit any real use of rewritten inode on write-once media
85+ * but avoid looping for too long on corrupted media.
86+ */
87+#define UDF_MAX_TD_NESTING 64
88+#define UDF_MAX_LVID_NESTING 1000
89+
8190 enum { UDF_MAX_LINKS = 0xffff };
8291
8392 /* These are the "meat" - everything else is stuffing */
@@ -1541,42 +1550,52 @@ out_bh: · 1457 unmodified lines
15411550 }
15421551
15431552 /*
1544− * udf_load_logicalvolint
1545− *
1553+ * Find the prevailing Logical Volume Integrity Descriptor.
15461554 */
15471555 static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_ad loc)
15481556 {
1549− struct buffer_head *bh = NULL;
1557+ struct buffer_head *bh, *final_bh;
15501558 uint16_t ident;
15511559 struct udf_sb_info *sbi = UDF_SB(sb);
15521560 struct logicalVolIntegrityDesc *lvid;
1561+ int indirections = 0;
1562+
1563+ while (++indirections <= UDF_MAX_LVID_NESTING) {
1564+ final_bh = NULL;
1565+ while (loc.extLength > 0 &&
1566+ (bh = udf_read_tagged(sb, loc.extLocation,
1567+ loc.extLocation, &ident))) {
1568+ if (ident != TAG_IDENT_LVID) {
1569+ brelse(bh);
1570+ break;
1571+ }
1572+
1573+ brelse(final_bh);
1574+ final_bh = bh;
15531575
1554− while (loc.extLength > 0 &&
1555− (bh = udf_read_tagged(sb, loc.extLocation,
1556− loc.extLocation, &ident)) &&
1557− ident == TAG_IDENT_LVID) {
1558− sbi->s_lvid_bh = bh;
1559− lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
1576+ loc.extLength -= sb->s_blocksize;
1577+ loc.extLocation++;
1578+ }
15601579
1561− if (lvid->nextIntegrityExt.extLength)
1562− udf_load_logicalvolint(sb,
1563− leea_to_cpu(lvid->nextIntegrityExt));
1580+ if (!final_bh)
1581+ return;
15641582
1565− if (sbi->s_lvid_bh != bh)
1566− brelse(bh);
1567− loc.extLength -= sb->s_blocksize;
1568− loc.extLocation++;
1583+ brelse(sbi->s_lvid_bh);
1584+ sbi->s_lvid_bh = final_bh;
1585+
1586+ lvid = (struct logicalVolIntegrityDesc *)final_bh->b_data;
1587+ if (lvid->nextIntegrityExt.extLength == 0)
1588+ return;
1589+
1590+ loc = leea_to_cpu(lvid->nextIntegrityExt);
15691591 }
1570− if (sbi->s_lvid_bh != bh)
1571− brelse(bh);
1592+
1593+ udf_warn(sb, "Too many LVID indirections (max %u), ignoring.\n",
1594+ UDF_MAX_LVID_NESTING);
1595+ brelse(sbi->s_lvid_bh);
1596+ sbi->s_lvid_bh = NULL;
15721597 }
15731598
1574−/*
1575− * Maximum number of Terminating Descriptor redirections. The chosen number is
1576− * arbitrary - just that we hopefully don't limit any real use of rewritten
1577− * inode on write-once media but avoid looping for too long on corrupted media.
1578− */
1579−#define UDF_MAX_TD_NESTING 64
15801599
15811600 /*
15821601 * Process a main/reserve volume descriptor sequence.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t