Skip to content

Commit a1dc581

Browse files
saschahauerrichardweinberger
authored andcommitted
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>
1 parent da8ef65 commit a1dc581

File tree

3 files changed

+134
-0
lines changed

3 files changed

+134
-0
lines changed

fs/ubifs/lpt.c

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1635,6 +1635,131 @@ struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum)
16351635
return &pnode->lprops[iip];
16361636
}
16371637

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+
16381763
/**
16391764
* lpt_init_rd - initialize the LPT for reading.
16401765
* @c: UBIFS file-system description object
@@ -1676,6 +1801,10 @@ static int lpt_init_rd(struct ubifs_info *c)
16761801
if (err)
16771802
return err;
16781803

1804+
err = lpt_check_hash(c);
1805+
if (err)
1806+
return err;
1807+
16791808
dbg_lp("space_bits %d", c->space_bits);
16801809
dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits);
16811810
dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits);

fs/ubifs/lpt_commit.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,10 @@ int ubifs_lpt_start_commit(struct ubifs_info *c)
12471247
if (err)
12481248
goto out;
12491249

1250+
err = ubifs_lpt_calc_hash(c, c->mst_node->hash_lpt);
1251+
if (err)
1252+
goto out;
1253+
12501254
/* Copy the LPT's own lprops for end commit to write */
12511255
memcpy(c->ltab_cmt, c->ltab,
12521256
sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs);

fs/ubifs/ubifs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1961,6 +1961,7 @@ struct ubifs_nnode *ubifs_first_nnode(struct ubifs_info *c, int *hght);
19611961
/* Needed only in debugging code in lpt_commit.c */
19621962
int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
19631963
struct ubifs_nnode *nnode);
1964+
int ubifs_lpt_calc_hash(struct ubifs_info *c, u8 *hash);
19641965

19651966
/* lpt_commit.c */
19661967
int ubifs_lpt_start_commit(struct ubifs_info *c);

0 commit comments

Comments
 (0)