diff options
-rw-r--r-- | fs/ubifs/lpt.c | 129 | ||||
-rw-r--r-- | fs/ubifs/lpt_commit.c | 4 | ||||
-rw-r--r-- | fs/ubifs/ubifs.h | 1 |
3 files changed, 134 insertions, 0 deletions
diff --git a/fs/ubifs/lpt.c b/fs/ubifs/lpt.c index 5f57af224b8f..ee18305a6152 100644 --- a/fs/ubifs/lpt.c +++ b/fs/ubifs/lpt.c | |||
@@ -1636,6 +1636,131 @@ struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum) | |||
1636 | } | 1636 | } |
1637 | 1637 | ||
1638 | /** | 1638 | /** |
1639 | * ubifs_lpt_calc_hash - Calculate hash of the LPT pnodes | ||
1640 | * @c: UBIFS file-system description object | ||
1641 | * @hash: the returned hash of the LPT pnodes | ||
1642 | * | ||
1643 | * This function iterates over the LPT pnodes and creates a hash over them. | ||
1644 | * Returns 0 for success or a negative error code otherwise. | ||
1645 | */ | ||
1646 | int ubifs_lpt_calc_hash(struct ubifs_info *c, u8 *hash) | ||
1647 | { | ||
1648 | struct ubifs_nnode *nnode, *nn; | ||
1649 | struct ubifs_cnode *cnode; | ||
1650 | struct shash_desc *desc; | ||
1651 | int iip = 0, i; | ||
1652 | int bufsiz = max_t(int, c->nnode_sz, c->pnode_sz); | ||
1653 | void *buf; | ||
1654 | int err; | ||
1655 | |||
1656 | if (!ubifs_authenticated(c)) | ||
1657 | return 0; | ||
1658 | |||
1659 | desc = ubifs_hash_get_desc(c); | ||
1660 | if (IS_ERR(desc)) | ||
1661 | return PTR_ERR(desc); | ||
1662 | |||
1663 | buf = kmalloc(bufsiz, GFP_NOFS); | ||
1664 | if (!buf) { | ||
1665 | err = -ENOMEM; | ||
1666 | goto out; | ||
1667 | } | ||
1668 | |||
1669 | if (!c->nroot) { | ||
1670 | err = ubifs_read_nnode(c, NULL, 0); | ||
1671 | if (err) | ||
1672 | return err; | ||
1673 | } | ||
1674 | |||
1675 | cnode = (struct ubifs_cnode *)c->nroot; | ||
1676 | |||
1677 | while (cnode) { | ||
1678 | nnode = cnode->parent; | ||
1679 | nn = (struct ubifs_nnode *)cnode; | ||
1680 | if (cnode->level > 1) { | ||
1681 | while (iip < UBIFS_LPT_FANOUT) { | ||
1682 | if (nn->nbranch[iip].lnum == 0) { | ||
1683 | /* Go right */ | ||
1684 | iip++; | ||
1685 | continue; | ||
1686 | } | ||
1687 | |||
1688 | nnode = ubifs_get_nnode(c, nn, iip); | ||
1689 | if (IS_ERR(nnode)) { | ||
1690 | err = PTR_ERR(nnode); | ||
1691 | goto out; | ||
1692 | } | ||
1693 | |||
1694 | /* Go down */ | ||
1695 | iip = 0; | ||
1696 | cnode = (struct ubifs_cnode *)nnode; | ||
1697 | break; | ||
1698 | } | ||
1699 | if (iip < UBIFS_LPT_FANOUT) | ||
1700 | continue; | ||
1701 | } else { | ||
1702 | struct ubifs_pnode *pnode; | ||
1703 | |||
1704 | for (i = 0; i < UBIFS_LPT_FANOUT; i++) { | ||
1705 | if (nn->nbranch[i].lnum == 0) | ||
1706 | continue; | ||
1707 | pnode = ubifs_get_pnode(c, nn, i); | ||
1708 | if (IS_ERR(pnode)) { | ||
1709 | err = PTR_ERR(pnode); | ||
1710 | goto out; | ||
1711 | } | ||
1712 | |||
1713 | ubifs_pack_pnode(c, buf, pnode); | ||
1714 | err = ubifs_shash_update(c, desc, buf, | ||
1715 | c->pnode_sz); | ||
1716 | if (err) | ||
1717 | goto out; | ||
1718 | } | ||
1719 | } | ||
1720 | /* Go up and to the right */ | ||
1721 | iip = cnode->iip + 1; | ||
1722 | cnode = (struct ubifs_cnode *)nnode; | ||
1723 | } | ||
1724 | |||
1725 | err = ubifs_shash_final(c, desc, hash); | ||
1726 | out: | ||
1727 | kfree(desc); | ||
1728 | kfree(buf); | ||
1729 | |||
1730 | return err; | ||
1731 | } | ||
1732 | |||
1733 | /** | ||
1734 | * lpt_check_hash - check the hash of the LPT. | ||
1735 | * @c: UBIFS file-system description object | ||
1736 | * | ||
1737 | * This function calculates a hash over all pnodes in the LPT and compares it with | ||
1738 | * the hash stored in the master node. Returns %0 on success and a negative error | ||
1739 | * code on failure. | ||
1740 | */ | ||
1741 | static int lpt_check_hash(struct ubifs_info *c) | ||
1742 | { | ||
1743 | int err; | ||
1744 | u8 hash[UBIFS_HASH_ARR_SZ]; | ||
1745 | |||
1746 | if (!ubifs_authenticated(c)) | ||
1747 | return 0; | ||
1748 | |||
1749 | err = ubifs_lpt_calc_hash(c, hash); | ||
1750 | if (err) | ||
1751 | return err; | ||
1752 | |||
1753 | if (ubifs_check_hash(c, c->mst_node->hash_lpt, hash)) { | ||
1754 | err = -EPERM; | ||
1755 | ubifs_err(c, "Failed to authenticate LPT"); | ||
1756 | } else { | ||
1757 | err = 0; | ||
1758 | } | ||
1759 | |||
1760 | return err; | ||
1761 | } | ||
1762 | |||
1763 | /** | ||
1639 | * lpt_init_rd - initialize the LPT for reading. | 1764 | * lpt_init_rd - initialize the LPT for reading. |
1640 | * @c: UBIFS file-system description object | 1765 | * @c: UBIFS file-system description object |
1641 | * | 1766 | * |
@@ -1676,6 +1801,10 @@ static int lpt_init_rd(struct ubifs_info *c) | |||
1676 | if (err) | 1801 | if (err) |
1677 | return err; | 1802 | return err; |
1678 | 1803 | ||
1804 | err = lpt_check_hash(c); | ||
1805 | if (err) | ||
1806 | return err; | ||
1807 | |||
1679 | dbg_lp("space_bits %d", c->space_bits); | 1808 | dbg_lp("space_bits %d", c->space_bits); |
1680 | dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits); | 1809 | dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits); |
1681 | dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits); | 1810 | dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits); |
diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c index 62d6a87d4f5d..1f88caffdf2a 100644 --- a/fs/ubifs/lpt_commit.c +++ b/fs/ubifs/lpt_commit.c | |||
@@ -1247,6 +1247,10 @@ int ubifs_lpt_start_commit(struct ubifs_info *c) | |||
1247 | if (err) | 1247 | if (err) |
1248 | goto out; | 1248 | goto out; |
1249 | 1249 | ||
1250 | err = ubifs_lpt_calc_hash(c, c->mst_node->hash_lpt); | ||
1251 | if (err) | ||
1252 | goto out; | ||
1253 | |||
1250 | /* Copy the LPT's own lprops for end commit to write */ | 1254 | /* Copy the LPT's own lprops for end commit to write */ |
1251 | memcpy(c->ltab_cmt, c->ltab, | 1255 | memcpy(c->ltab_cmt, c->ltab, |
1252 | sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs); | 1256 | sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs); |
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 600a25b93a80..7e519a4885a8 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h | |||
@@ -1961,6 +1961,7 @@ struct ubifs_nnode *ubifs_first_nnode(struct ubifs_info *c, int *hght); | |||
1961 | /* Needed only in debugging code in lpt_commit.c */ | 1961 | /* Needed only in debugging code in lpt_commit.c */ |
1962 | int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf, | 1962 | int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf, |
1963 | struct ubifs_nnode *nnode); | 1963 | struct ubifs_nnode *nnode); |
1964 | int ubifs_lpt_calc_hash(struct ubifs_info *c, u8 *hash); | ||
1964 | 1965 | ||
1965 | /* lpt_commit.c */ | 1966 | /* lpt_commit.c */ |
1966 | int ubifs_lpt_start_commit(struct ubifs_info *c); | 1967 | int ubifs_lpt_start_commit(struct ubifs_info *c); |