aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2018-09-07 08:36:39 -0400
committerRichard Weinberger <richard@nod.at>2018-10-23 07:48:47 -0400
commita1dc58140f7e63e3b23050eb43b4e5581cb28c88 (patch)
treeff4e138d447d33dfe7a7a0bdf2ac67fe3c62a141
parentda8ef65f9573952c717d86f8f501773daf29bd10 (diff)
ubifs: authentication: Authenticate LPT
The LPT needs to be authenticated aswell. Since the LPT is only written during commit it is enough to authenticate the whole LPT with a single hash which is stored in the master node. Only the leaf nodes (pnodes) are hashed which makes the implementation much simpler than it would be to hash the complete LPT. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Richard Weinberger <richard@nod.at>
-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);