Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

udf: Fix handling of Partition Descriptors

Current handling of Partition Descriptors in Volume Descriptor Sequence
is buggy in several ways. Firstly, it does not take descriptor sequence
numbers into account at all, thus any volume making serious use of them
would be unmountable. Secondly, it does not handle Volume Descriptor
Pointers or Volume Descriptor Sequence without Terminating Descriptor.

Fix these problems by properly remembering all Partition Descriptors in
the Volume Descriptor Sequence and their sequence numbers. This is made
more complicated by the fact that we don't know number of partitions in
advance and sequence numbers have to be tracked on per-partition basis.

Reported-by: Pali Rohár <pali.rohar@gmail.com>
Acked-by: Pali Rohár <pali.rohar@gmail.com>
Signed-off-by: Jan Kara <jack@suse.cz>

Jan Kara 7b78fd02 18cf4781

+72 -31
+72 -31
fs/udf/super.c
··· 68 68 VDS_POS_PRIMARY_VOL_DESC, 69 69 VDS_POS_UNALLOC_SPACE_DESC, 70 70 VDS_POS_LOGICAL_VOL_DESC, 71 - VDS_POS_PARTITION_DESC, 72 71 VDS_POS_IMP_USE_VOL_DESC, 73 - VDS_POS_TERMINATING_DESC, 74 72 VDS_POS_LENGTH 75 73 }; 76 74 ··· 1591 1593 sbi->s_lvid_bh = NULL; 1592 1594 } 1593 1595 1594 - static struct udf_vds_record *get_volume_descriptor_record( 1595 - struct udf_vds_record *vds, uint16_t ident) 1596 + /* 1597 + * Step for reallocation of table of partition descriptor sequence numbers. 1598 + * Must be power of 2. 1599 + */ 1600 + #define PART_DESC_ALLOC_STEP 32 1601 + 1602 + struct desc_seq_scan_data { 1603 + struct udf_vds_record vds[VDS_POS_LENGTH]; 1604 + unsigned int size_part_descs; 1605 + struct udf_vds_record *part_descs_loc; 1606 + }; 1607 + 1608 + static struct udf_vds_record *handle_partition_descriptor( 1609 + struct buffer_head *bh, 1610 + struct desc_seq_scan_data *data) 1611 + { 1612 + struct partitionDesc *desc = (struct partitionDesc *)bh->b_data; 1613 + int partnum; 1614 + 1615 + partnum = le16_to_cpu(desc->partitionNumber); 1616 + if (partnum >= data->size_part_descs) { 1617 + struct udf_vds_record *new_loc; 1618 + unsigned int new_size = ALIGN(partnum, PART_DESC_ALLOC_STEP); 1619 + 1620 + new_loc = kzalloc(sizeof(*new_loc) * new_size, GFP_KERNEL); 1621 + if (!new_loc) 1622 + return ERR_PTR(-ENOMEM); 1623 + memcpy(new_loc, data->part_descs_loc, 1624 + data->size_part_descs * sizeof(*new_loc)); 1625 + kfree(data->part_descs_loc); 1626 + data->part_descs_loc = new_loc; 1627 + data->size_part_descs = new_size; 1628 + } 1629 + return &(data->part_descs_loc[partnum]); 1630 + } 1631 + 1632 + 1633 + static struct udf_vds_record *get_volume_descriptor_record(uint16_t ident, 1634 + struct buffer_head *bh, struct desc_seq_scan_data *data) 1596 1635 { 1597 1636 switch (ident) { 1598 1637 case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */ 1599 - return &vds[VDS_POS_PRIMARY_VOL_DESC]; 1638 + return &(data->vds[VDS_POS_PRIMARY_VOL_DESC]); 1600 1639 case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */ 1601 - return &vds[VDS_POS_IMP_USE_VOL_DESC]; 1640 + return &(data->vds[VDS_POS_IMP_USE_VOL_DESC]); 1602 1641 case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */ 1603 - return &vds[VDS_POS_LOGICAL_VOL_DESC]; 1642 + return &(data->vds[VDS_POS_LOGICAL_VOL_DESC]); 1604 1643 case TAG_IDENT_USD: /* ISO 13346 3/10.8 */ 1605 - return &vds[VDS_POS_UNALLOC_SPACE_DESC]; 1644 + return &(data->vds[VDS_POS_UNALLOC_SPACE_DESC]); 1645 + case TAG_IDENT_PD: /* ISO 13346 3/10.5 */ 1646 + return handle_partition_descriptor(bh, data); 1606 1647 } 1607 1648 return NULL; 1608 1649 } ··· 1661 1624 struct kernel_lb_addr *fileset) 1662 1625 { 1663 1626 struct buffer_head *bh = NULL; 1664 - struct udf_vds_record vds[VDS_POS_LENGTH]; 1665 1627 struct udf_vds_record *curr; 1666 1628 struct generic_desc *gd; 1667 1629 struct volDescPtr *vdp; ··· 1669 1633 uint16_t ident; 1670 1634 int ret; 1671 1635 unsigned int indirections = 0; 1636 + struct desc_seq_scan_data data; 1637 + unsigned int i; 1672 1638 1673 - memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); 1639 + memset(data.vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); 1640 + data.size_part_descs = PART_DESC_ALLOC_STEP; 1641 + data.part_descs_loc = kzalloc(sizeof(*data.part_descs_loc) * 1642 + data.size_part_descs, GFP_KERNEL); 1643 + if (!data.part_descs_loc) 1644 + return -ENOMEM; 1674 1645 1675 1646 /* 1676 1647 * Read the main descriptor sequence and find which descriptors ··· 1715 1672 case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */ 1716 1673 case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */ 1717 1674 case TAG_IDENT_USD: /* ISO 13346 3/10.8 */ 1718 - curr = get_volume_descriptor_record(vds, ident); 1675 + case TAG_IDENT_PD: /* ISO 13346 3/10.5 */ 1676 + curr = get_volume_descriptor_record(ident, bh, &data); 1677 + if (IS_ERR(curr)) { 1678 + brelse(bh); 1679 + return PTR_ERR(curr); 1680 + } 1681 + /* Descriptor we don't care about? */ 1682 + if (!curr) 1683 + break; 1719 1684 if (vdsn >= curr->volDescSeqNum) { 1720 1685 curr->volDescSeqNum = vdsn; 1721 1686 curr->block = block; 1722 1687 } 1723 1688 break; 1724 - case TAG_IDENT_PD: /* ISO 13346 3/10.5 */ 1725 - curr = &vds[VDS_POS_PARTITION_DESC]; 1726 - if (!curr->block) 1727 - curr->block = block; 1728 - break; 1729 1689 case TAG_IDENT_TD: /* ISO 13346 3/10.9 */ 1730 - vds[VDS_POS_TERMINATING_DESC].block = block; 1731 1690 done = true; 1732 1691 break; 1733 1692 } ··· 1739 1694 * Now read interesting descriptors again and process them 1740 1695 * in a suitable order 1741 1696 */ 1742 - if (!vds[VDS_POS_PRIMARY_VOL_DESC].block) { 1697 + if (!data.vds[VDS_POS_PRIMARY_VOL_DESC].block) { 1743 1698 udf_err(sb, "Primary Volume Descriptor not found!\n"); 1744 1699 return -EAGAIN; 1745 1700 } 1746 - ret = udf_load_pvoldesc(sb, vds[VDS_POS_PRIMARY_VOL_DESC].block); 1701 + ret = udf_load_pvoldesc(sb, data.vds[VDS_POS_PRIMARY_VOL_DESC].block); 1747 1702 if (ret < 0) 1748 1703 return ret; 1749 1704 1750 - if (vds[VDS_POS_LOGICAL_VOL_DESC].block) { 1705 + if (data.vds[VDS_POS_LOGICAL_VOL_DESC].block) { 1751 1706 ret = udf_load_logicalvol(sb, 1752 - vds[VDS_POS_LOGICAL_VOL_DESC].block, 1753 - fileset); 1707 + data.vds[VDS_POS_LOGICAL_VOL_DESC].block, 1708 + fileset); 1754 1709 if (ret < 0) 1755 1710 return ret; 1756 1711 } 1757 1712 1758 - if (vds[VDS_POS_PARTITION_DESC].block) { 1759 - /* 1760 - * We rescan the whole descriptor sequence to find 1761 - * partition descriptor blocks and process them. 1762 - */ 1763 - for (block = vds[VDS_POS_PARTITION_DESC].block; 1764 - block < vds[VDS_POS_TERMINATING_DESC].block; 1765 - block++) { 1766 - ret = udf_load_partdesc(sb, block); 1713 + /* Now handle prevailing Partition Descriptors */ 1714 + for (i = 0; i < data.size_part_descs; i++) { 1715 + if (data.part_descs_loc[i].block) { 1716 + ret = udf_load_partdesc(sb, 1717 + data.part_descs_loc[i].block); 1767 1718 if (ret < 0) 1768 1719 return ret; 1769 1720 }