| .. | .. | 
|---|
 | 1 | +// SPDX-License-Identifier: GPL-2.0-only  | 
|---|
| 1 | 2 |  /* | 
|---|
| 2 | 3 |   * This file is part of UBIFS. | 
|---|
| 3 | 4 |   * | 
|---|
| 4 | 5 |   * Copyright (C) 2006-2008 Nokia Corporation. | 
|---|
| 5 |  | - *  | 
|---|
| 6 |  | - * This program is free software; you can redistribute it and/or modify it  | 
|---|
| 7 |  | - * under the terms of the GNU General Public License version 2 as published by  | 
|---|
| 8 |  | - * the Free Software Foundation.  | 
|---|
| 9 |  | - *  | 
|---|
| 10 |  | - * This program is distributed in the hope that it will be useful, but WITHOUT  | 
|---|
| 11 |  | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or  | 
|---|
| 12 |  | - * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for  | 
|---|
| 13 |  | - * more details.  | 
|---|
| 14 |  | - *  | 
|---|
| 15 |  | - * You should have received a copy of the GNU General Public License along with  | 
|---|
| 16 |  | - * this program; if not, write to the Free Software Foundation, Inc., 51  | 
|---|
| 17 |  | - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA  | 
|---|
| 18 | 6 |   * | 
|---|
| 19 | 7 |   * Authors: Adrian Hunter | 
|---|
| 20 | 8 |   *          Artem Bityutskiy (Битюцкий Артём) | 
|---|
| .. | .. | 
|---|
| 287 | 275 |  	const int k = 32 - nrbits; | 
|---|
| 288 | 276 |  	uint8_t *p = *addr; | 
|---|
| 289 | 277 |  	int b = *pos; | 
|---|
| 290 |  | -	uint32_t uninitialized_var(val);  | 
|---|
 | 278 | +	uint32_t val;  | 
|---|
| 291 | 279 |  	const int bytes = (nrbits + b + 7) >> 3; | 
|---|
| 292 | 280 |   | 
|---|
| 293 | 281 |  	ubifs_assert(c, nrbits > 0); | 
|---|
| .. | .. | 
|---|
| 604 | 592 |   * @lpt_first: LEB number of first LPT LEB | 
|---|
| 605 | 593 |   * @lpt_lebs: number of LEBs for LPT is passed and returned here | 
|---|
| 606 | 594 |   * @big_lpt: use big LPT model is passed and returned here | 
|---|
 | 595 | + * @hash: hash of the LPT is returned here  | 
|---|
| 607 | 596 |   * | 
|---|
| 608 | 597 |   * This function returns %0 on success and a negative error code on failure. | 
|---|
| 609 | 598 |   */ | 
|---|
| 610 | 599 |  int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, | 
|---|
| 611 |  | -			  int *lpt_lebs, int *big_lpt)  | 
|---|
 | 600 | +			  int *lpt_lebs, int *big_lpt, u8 *hash)  | 
|---|
| 612 | 601 |  { | 
|---|
| 613 | 602 |  	int lnum, err = 0, node_sz, iopos, i, j, cnt, len, alen, row; | 
|---|
| 614 | 603 |  	int blnum, boffs, bsz, bcnt; | 
|---|
| .. | .. | 
|---|
| 617 | 606 |  	void *buf = NULL, *p; | 
|---|
| 618 | 607 |  	struct ubifs_lpt_lprops *ltab = NULL; | 
|---|
| 619 | 608 |  	int *lsave = NULL; | 
|---|
 | 609 | +	struct shash_desc *desc;  | 
|---|
| 620 | 610 |   | 
|---|
| 621 | 611 |  	err = calc_dflt_lpt_geom(c, main_lebs, big_lpt); | 
|---|
| 622 | 612 |  	if (err) | 
|---|
| .. | .. | 
|---|
| 629 | 619 |  	c->lpt_last = lpt_first + c->lpt_lebs - 1; | 
|---|
| 630 | 620 |  	/* Needed by 'ubifs_pack_lsave()' */ | 
|---|
| 631 | 621 |  	c->main_first = c->leb_cnt - *main_lebs; | 
|---|
 | 622 | +  | 
|---|
 | 623 | +	desc = ubifs_hash_get_desc(c);  | 
|---|
 | 624 | +	if (IS_ERR(desc))  | 
|---|
 | 625 | +		return PTR_ERR(desc);  | 
|---|
| 632 | 626 |   | 
|---|
| 633 | 627 |  	lsave = kmalloc_array(c->lsave_cnt, sizeof(int), GFP_KERNEL); | 
|---|
| 634 | 628 |  	pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_KERNEL); | 
|---|
| .. | .. | 
|---|
| 677 | 671 |   | 
|---|
| 678 | 672 |  	/* Add first pnode */ | 
|---|
| 679 | 673 |  	ubifs_pack_pnode(c, p, pnode); | 
|---|
 | 674 | +	err = ubifs_shash_update(c, desc, p, c->pnode_sz);  | 
|---|
 | 675 | +	if (err)  | 
|---|
 | 676 | +		goto out;  | 
|---|
 | 677 | +  | 
|---|
| 680 | 678 |  	p += c->pnode_sz; | 
|---|
| 681 | 679 |  	len = c->pnode_sz; | 
|---|
| 682 | 680 |  	pnode->num += 1; | 
|---|
| .. | .. | 
|---|
| 711 | 709 |  			len = 0; | 
|---|
| 712 | 710 |  		} | 
|---|
| 713 | 711 |  		ubifs_pack_pnode(c, p, pnode); | 
|---|
 | 712 | +		err = ubifs_shash_update(c, desc, p, c->pnode_sz);  | 
|---|
 | 713 | +		if (err)  | 
|---|
 | 714 | +			goto out;  | 
|---|
 | 715 | +  | 
|---|
| 714 | 716 |  		p += c->pnode_sz; | 
|---|
| 715 | 717 |  		len += c->pnode_sz; | 
|---|
| 716 | 718 |  		/* | 
|---|
| .. | .. | 
|---|
| 830 | 832 |  	if (err) | 
|---|
| 831 | 833 |  		goto out; | 
|---|
| 832 | 834 |   | 
|---|
 | 835 | +	err = ubifs_shash_final(c, desc, hash);  | 
|---|
 | 836 | +	if (err)  | 
|---|
 | 837 | +		goto out;  | 
|---|
 | 838 | +  | 
|---|
| 833 | 839 |  	c->nhead_lnum = lnum; | 
|---|
| 834 | 840 |  	c->nhead_offs = ALIGN(len, c->min_io_size); | 
|---|
| 835 | 841 |   | 
|---|
| .. | .. | 
|---|
| 853 | 859 |  		dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs); | 
|---|
| 854 | 860 |  out: | 
|---|
| 855 | 861 |  	c->ltab = NULL; | 
|---|
 | 862 | +	kfree(desc);  | 
|---|
| 856 | 863 |  	kfree(lsave); | 
|---|
| 857 | 864 |  	vfree(ltab); | 
|---|
| 858 | 865 |  	vfree(buf); | 
|---|
| .. | .. | 
|---|
| 1439 | 1446 |  } | 
|---|
| 1440 | 1447 |   | 
|---|
| 1441 | 1448 |  /** | 
|---|
| 1442 |  | - * ubifs_lpt_lookup - lookup LEB properties in the LPT.  | 
|---|
 | 1449 | + * ubifs_pnode_lookup - lookup a pnode in the LPT.  | 
|---|
| 1443 | 1450 |   * @c: UBIFS file-system description object | 
|---|
| 1444 |  | - * @lnum: LEB number to lookup  | 
|---|
 | 1451 | + * @i: pnode number (0 to (main_lebs - 1) / UBIFS_LPT_FANOUT)  | 
|---|
| 1445 | 1452 |   * | 
|---|
| 1446 |  | - * This function returns a pointer to the LEB properties on success or a  | 
|---|
| 1447 |  | - * negative error code on failure.  | 
|---|
 | 1453 | + * This function returns a pointer to the pnode on success or a negative  | 
|---|
 | 1454 | + * error code on failure.  | 
|---|
| 1448 | 1455 |   */ | 
|---|
| 1449 |  | -struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum)  | 
|---|
 | 1456 | +struct ubifs_pnode *ubifs_pnode_lookup(struct ubifs_info *c, int i)  | 
|---|
| 1450 | 1457 |  { | 
|---|
| 1451 |  | -	int err, i, h, iip, shft;  | 
|---|
 | 1458 | +	int err, h, iip, shft;  | 
|---|
| 1452 | 1459 |  	struct ubifs_nnode *nnode; | 
|---|
| 1453 |  | -	struct ubifs_pnode *pnode;  | 
|---|
| 1454 | 1460 |   | 
|---|
| 1455 | 1461 |  	if (!c->nroot) { | 
|---|
| 1456 | 1462 |  		err = ubifs_read_nnode(c, NULL, 0); | 
|---|
| 1457 | 1463 |  		if (err) | 
|---|
| 1458 | 1464 |  			return ERR_PTR(err); | 
|---|
| 1459 | 1465 |  	} | 
|---|
 | 1466 | +	i <<= UBIFS_LPT_FANOUT_SHIFT;  | 
|---|
| 1460 | 1467 |  	nnode = c->nroot; | 
|---|
| 1461 |  | -	i = lnum - c->main_first;  | 
|---|
| 1462 | 1468 |  	shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT; | 
|---|
| 1463 | 1469 |  	for (h = 1; h < c->lpt_hght; h++) { | 
|---|
| 1464 | 1470 |  		iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); | 
|---|
| .. | .. | 
|---|
| 1468 | 1474 |  			return ERR_CAST(nnode); | 
|---|
| 1469 | 1475 |  	} | 
|---|
| 1470 | 1476 |  	iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); | 
|---|
| 1471 |  | -	pnode = ubifs_get_pnode(c, nnode, iip);  | 
|---|
 | 1477 | +	return ubifs_get_pnode(c, nnode, iip);  | 
|---|
 | 1478 | +}  | 
|---|
 | 1479 | +  | 
|---|
 | 1480 | +/**  | 
|---|
 | 1481 | + * ubifs_lpt_lookup - lookup LEB properties in the LPT.  | 
|---|
 | 1482 | + * @c: UBIFS file-system description object  | 
|---|
 | 1483 | + * @lnum: LEB number to lookup  | 
|---|
 | 1484 | + *  | 
|---|
 | 1485 | + * This function returns a pointer to the LEB properties on success or a  | 
|---|
 | 1486 | + * negative error code on failure.  | 
|---|
 | 1487 | + */  | 
|---|
 | 1488 | +struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum)  | 
|---|
 | 1489 | +{  | 
|---|
 | 1490 | +	int i, iip;  | 
|---|
 | 1491 | +	struct ubifs_pnode *pnode;  | 
|---|
 | 1492 | +  | 
|---|
 | 1493 | +	i = lnum - c->main_first;  | 
|---|
 | 1494 | +	pnode = ubifs_pnode_lookup(c, i >> UBIFS_LPT_FANOUT_SHIFT);  | 
|---|
| 1472 | 1495 |  	if (IS_ERR(pnode)) | 
|---|
| 1473 | 1496 |  		return ERR_CAST(pnode); | 
|---|
| 1474 | 1497 |  	iip = (i & (UBIFS_LPT_FANOUT - 1)); | 
|---|
| .. | .. | 
|---|
| 1620 | 1643 |  } | 
|---|
| 1621 | 1644 |   | 
|---|
| 1622 | 1645 |  /** | 
|---|
 | 1646 | + * ubifs_lpt_calc_hash - Calculate hash of the LPT pnodes  | 
|---|
 | 1647 | + * @c: UBIFS file-system description object  | 
|---|
 | 1648 | + * @hash: the returned hash of the LPT pnodes  | 
|---|
 | 1649 | + *  | 
|---|
 | 1650 | + * This function iterates over the LPT pnodes and creates a hash over them.  | 
|---|
 | 1651 | + * Returns 0 for success or a negative error code otherwise.  | 
|---|
 | 1652 | + */  | 
|---|
 | 1653 | +int ubifs_lpt_calc_hash(struct ubifs_info *c, u8 *hash)  | 
|---|
 | 1654 | +{  | 
|---|
 | 1655 | +	struct ubifs_nnode *nnode, *nn;  | 
|---|
 | 1656 | +	struct ubifs_cnode *cnode;  | 
|---|
 | 1657 | +	struct shash_desc *desc;  | 
|---|
 | 1658 | +	int iip = 0, i;  | 
|---|
 | 1659 | +	int bufsiz = max_t(int, c->nnode_sz, c->pnode_sz);  | 
|---|
 | 1660 | +	void *buf;  | 
|---|
 | 1661 | +	int err;  | 
|---|
 | 1662 | +  | 
|---|
 | 1663 | +	if (!ubifs_authenticated(c))  | 
|---|
 | 1664 | +		return 0;  | 
|---|
 | 1665 | +  | 
|---|
 | 1666 | +	if (!c->nroot) {  | 
|---|
 | 1667 | +		err = ubifs_read_nnode(c, NULL, 0);  | 
|---|
 | 1668 | +		if (err)  | 
|---|
 | 1669 | +			return err;  | 
|---|
 | 1670 | +	}  | 
|---|
 | 1671 | +  | 
|---|
 | 1672 | +	desc = ubifs_hash_get_desc(c);  | 
|---|
 | 1673 | +	if (IS_ERR(desc))  | 
|---|
 | 1674 | +		return PTR_ERR(desc);  | 
|---|
 | 1675 | +  | 
|---|
 | 1676 | +	buf = kmalloc(bufsiz, GFP_NOFS);  | 
|---|
 | 1677 | +	if (!buf) {  | 
|---|
 | 1678 | +		err = -ENOMEM;  | 
|---|
 | 1679 | +		goto out;  | 
|---|
 | 1680 | +	}  | 
|---|
 | 1681 | +  | 
|---|
 | 1682 | +	cnode = (struct ubifs_cnode *)c->nroot;  | 
|---|
 | 1683 | +  | 
|---|
 | 1684 | +	while (cnode) {  | 
|---|
 | 1685 | +		nnode = cnode->parent;  | 
|---|
 | 1686 | +		nn = (struct ubifs_nnode *)cnode;  | 
|---|
 | 1687 | +		if (cnode->level > 1) {  | 
|---|
 | 1688 | +			while (iip < UBIFS_LPT_FANOUT) {  | 
|---|
 | 1689 | +				if (nn->nbranch[iip].lnum == 0) {  | 
|---|
 | 1690 | +					/* Go right */  | 
|---|
 | 1691 | +					iip++;  | 
|---|
 | 1692 | +					continue;  | 
|---|
 | 1693 | +				}  | 
|---|
 | 1694 | +  | 
|---|
 | 1695 | +				nnode = ubifs_get_nnode(c, nn, iip);  | 
|---|
 | 1696 | +				if (IS_ERR(nnode)) {  | 
|---|
 | 1697 | +					err = PTR_ERR(nnode);  | 
|---|
 | 1698 | +					goto out;  | 
|---|
 | 1699 | +				}  | 
|---|
 | 1700 | +  | 
|---|
 | 1701 | +				/* Go down */  | 
|---|
 | 1702 | +				iip = 0;  | 
|---|
 | 1703 | +				cnode = (struct ubifs_cnode *)nnode;  | 
|---|
 | 1704 | +				break;  | 
|---|
 | 1705 | +			}  | 
|---|
 | 1706 | +			if (iip < UBIFS_LPT_FANOUT)  | 
|---|
 | 1707 | +				continue;  | 
|---|
 | 1708 | +		} else {  | 
|---|
 | 1709 | +			struct ubifs_pnode *pnode;  | 
|---|
 | 1710 | +  | 
|---|
 | 1711 | +			for (i = 0; i < UBIFS_LPT_FANOUT; i++) {  | 
|---|
 | 1712 | +				if (nn->nbranch[i].lnum == 0)  | 
|---|
 | 1713 | +					continue;  | 
|---|
 | 1714 | +				pnode = ubifs_get_pnode(c, nn, i);  | 
|---|
 | 1715 | +				if (IS_ERR(pnode)) {  | 
|---|
 | 1716 | +					err = PTR_ERR(pnode);  | 
|---|
 | 1717 | +					goto out;  | 
|---|
 | 1718 | +				}  | 
|---|
 | 1719 | +  | 
|---|
 | 1720 | +				ubifs_pack_pnode(c, buf, pnode);  | 
|---|
 | 1721 | +				err = ubifs_shash_update(c, desc, buf,  | 
|---|
 | 1722 | +							 c->pnode_sz);  | 
|---|
 | 1723 | +				if (err)  | 
|---|
 | 1724 | +					goto out;  | 
|---|
 | 1725 | +			}  | 
|---|
 | 1726 | +		}  | 
|---|
 | 1727 | +		/* Go up and to the right */  | 
|---|
 | 1728 | +		iip = cnode->iip + 1;  | 
|---|
 | 1729 | +		cnode = (struct ubifs_cnode *)nnode;  | 
|---|
 | 1730 | +	}  | 
|---|
 | 1731 | +  | 
|---|
 | 1732 | +	err = ubifs_shash_final(c, desc, hash);  | 
|---|
 | 1733 | +out:  | 
|---|
 | 1734 | +	kfree(desc);  | 
|---|
 | 1735 | +	kfree(buf);  | 
|---|
 | 1736 | +  | 
|---|
 | 1737 | +	return err;  | 
|---|
 | 1738 | +}  | 
|---|
 | 1739 | +  | 
|---|
 | 1740 | +/**  | 
|---|
 | 1741 | + * lpt_check_hash - check the hash of the LPT.  | 
|---|
 | 1742 | + * @c: UBIFS file-system description object  | 
|---|
 | 1743 | + *  | 
|---|
 | 1744 | + * This function calculates a hash over all pnodes in the LPT and compares it with  | 
|---|
 | 1745 | + * the hash stored in the master node. Returns %0 on success and a negative error  | 
|---|
 | 1746 | + * code on failure.  | 
|---|
 | 1747 | + */  | 
|---|
 | 1748 | +static int lpt_check_hash(struct ubifs_info *c)  | 
|---|
 | 1749 | +{  | 
|---|
 | 1750 | +	int err;  | 
|---|
 | 1751 | +	u8 hash[UBIFS_HASH_ARR_SZ];  | 
|---|
 | 1752 | +  | 
|---|
 | 1753 | +	if (!ubifs_authenticated(c))  | 
|---|
 | 1754 | +		return 0;  | 
|---|
 | 1755 | +  | 
|---|
 | 1756 | +	err = ubifs_lpt_calc_hash(c, hash);  | 
|---|
 | 1757 | +	if (err)  | 
|---|
 | 1758 | +		return err;  | 
|---|
 | 1759 | +  | 
|---|
 | 1760 | +	if (ubifs_check_hash(c, c->mst_node->hash_lpt, hash)) {  | 
|---|
 | 1761 | +		err = -EPERM;  | 
|---|
 | 1762 | +		ubifs_err(c, "Failed to authenticate LPT");  | 
|---|
 | 1763 | +	} else {  | 
|---|
 | 1764 | +		err = 0;  | 
|---|
 | 1765 | +	}  | 
|---|
 | 1766 | +  | 
|---|
 | 1767 | +	return err;  | 
|---|
 | 1768 | +}  | 
|---|
 | 1769 | +  | 
|---|
 | 1770 | +/**  | 
|---|
| 1623 | 1771 |   * lpt_init_rd - initialize the LPT for reading. | 
|---|
| 1624 | 1772 |   * @c: UBIFS file-system description object | 
|---|
| 1625 | 1773 |   * | 
|---|
| .. | .. | 
|---|
| 1660 | 1808 |  	if (err) | 
|---|
| 1661 | 1809 |  		return err; | 
|---|
| 1662 | 1810 |   | 
|---|
 | 1811 | +	err = lpt_check_hash(c);  | 
|---|
 | 1812 | +	if (err)  | 
|---|
 | 1813 | +		return err;  | 
|---|
 | 1814 | +  | 
|---|
| 1663 | 1815 |  	dbg_lp("space_bits %d", c->space_bits); | 
|---|
| 1664 | 1816 |  	dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits); | 
|---|
| 1665 | 1817 |  	dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits); | 
|---|