summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ubifs/lpt.c129
-rw-r--r--fs/ubifs/lpt_commit.c4
-rw-r--r--fs/ubifs/ubifs.h1
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 */
1646int 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);
1726out:
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 */
1741static 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 */
1962int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf, 1962int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
1963 struct ubifs_nnode *nnode); 1963 struct ubifs_nnode *nnode);
1964int ubifs_lpt_calc_hash(struct ubifs_info *c, u8 *hash);
1964 1965
1965/* lpt_commit.c */ 1966/* lpt_commit.c */
1966int ubifs_lpt_start_commit(struct ubifs_info *c); 1967int ubifs_lpt_start_commit(struct ubifs_info *c);