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