diff options
author | Vegard Nossum <vegard.nossum@oracle.com> | 2015-12-10 11:13:41 -0500 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2015-12-14 14:13:36 -0500 |
commit | e7a4eb861203b605c6428ec29e0b5e3c3f4f537f (patch) | |
tree | 0ce3fe22c7c0013f7ba9b7b9308bfb2f91cb4dc1 /fs/udf | |
parent | 331221fac721788615dd9d5b27f710f7c758d60a (diff) |
udf: limit the maximum number of TD redirections
Filesystem fuzzing revealed that we could get stuck in the
udf_process_sequence() loop.
The maximum limit was chosen arbitrarily but fixes the problem I saw.
Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/udf')
-rw-r--r-- | fs/udf/super.c | 14 |
1 files changed, 14 insertions, 0 deletions
diff --git a/fs/udf/super.c b/fs/udf/super.c index 81155b9b445b..fd45537eaa01 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c | |||
@@ -1586,6 +1586,13 @@ static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_ | |||
1586 | } | 1586 | } |
1587 | 1587 | ||
1588 | /* | 1588 | /* |
1589 | * Maximum number of Terminating Descriptor redirections. The chosen number is | ||
1590 | * arbitrary - just that we hopefully don't limit any real use of rewritten | ||
1591 | * inode on write-once media but avoid looping for too long on corrupted media. | ||
1592 | */ | ||
1593 | #define UDF_MAX_TD_NESTING 64 | ||
1594 | |||
1595 | /* | ||
1589 | * Process a main/reserve volume descriptor sequence. | 1596 | * Process a main/reserve volume descriptor sequence. |
1590 | * @block First block of first extent of the sequence. | 1597 | * @block First block of first extent of the sequence. |
1591 | * @lastblock Lastblock of first extent of the sequence. | 1598 | * @lastblock Lastblock of first extent of the sequence. |
@@ -1609,6 +1616,7 @@ static noinline int udf_process_sequence( | |||
1609 | uint16_t ident; | 1616 | uint16_t ident; |
1610 | long next_s = 0, next_e = 0; | 1617 | long next_s = 0, next_e = 0; |
1611 | int ret; | 1618 | int ret; |
1619 | unsigned int indirections = 0; | ||
1612 | 1620 | ||
1613 | memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); | 1621 | memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); |
1614 | 1622 | ||
@@ -1679,6 +1687,12 @@ static noinline int udf_process_sequence( | |||
1679 | } | 1687 | } |
1680 | break; | 1688 | break; |
1681 | case TAG_IDENT_TD: /* ISO 13346 3/10.9 */ | 1689 | case TAG_IDENT_TD: /* ISO 13346 3/10.9 */ |
1690 | if (++indirections > UDF_MAX_TD_NESTING) { | ||
1691 | udf_err(sb, "too many TDs (max %u supported)\n", UDF_MAX_TD_NESTING); | ||
1692 | brelse(bh); | ||
1693 | return -EIO; | ||
1694 | } | ||
1695 | |||
1682 | vds[VDS_POS_TERMINATING_DESC].block = block; | 1696 | vds[VDS_POS_TERMINATING_DESC].block = block; |
1683 | if (next_e) { | 1697 | if (next_e) { |
1684 | block = next_s; | 1698 | block = next_s; |