| .. | .. |
|---|
| 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); |
|---|