hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/fs/ubifs/lpt.c
....@@ -1,20 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * This file is part of UBIFS.
34 *
45 * 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
186 *
197 * Authors: Adrian Hunter
208 * Artem Bityutskiy (Битюцкий Артём)
....@@ -287,7 +275,7 @@
287275 const int k = 32 - nrbits;
288276 uint8_t *p = *addr;
289277 int b = *pos;
290
- uint32_t uninitialized_var(val);
278
+ uint32_t val;
291279 const int bytes = (nrbits + b + 7) >> 3;
292280
293281 ubifs_assert(c, nrbits > 0);
....@@ -604,11 +592,12 @@
604592 * @lpt_first: LEB number of first LPT LEB
605593 * @lpt_lebs: number of LEBs for LPT is passed and returned here
606594 * @big_lpt: use big LPT model is passed and returned here
595
+ * @hash: hash of the LPT is returned here
607596 *
608597 * This function returns %0 on success and a negative error code on failure.
609598 */
610599 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)
612601 {
613602 int lnum, err = 0, node_sz, iopos, i, j, cnt, len, alen, row;
614603 int blnum, boffs, bsz, bcnt;
....@@ -617,6 +606,7 @@
617606 void *buf = NULL, *p;
618607 struct ubifs_lpt_lprops *ltab = NULL;
619608 int *lsave = NULL;
609
+ struct shash_desc *desc;
620610
621611 err = calc_dflt_lpt_geom(c, main_lebs, big_lpt);
622612 if (err)
....@@ -629,6 +619,10 @@
629619 c->lpt_last = lpt_first + c->lpt_lebs - 1;
630620 /* Needed by 'ubifs_pack_lsave()' */
631621 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);
632626
633627 lsave = kmalloc_array(c->lsave_cnt, sizeof(int), GFP_KERNEL);
634628 pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_KERNEL);
....@@ -677,6 +671,10 @@
677671
678672 /* Add first pnode */
679673 ubifs_pack_pnode(c, p, pnode);
674
+ err = ubifs_shash_update(c, desc, p, c->pnode_sz);
675
+ if (err)
676
+ goto out;
677
+
680678 p += c->pnode_sz;
681679 len = c->pnode_sz;
682680 pnode->num += 1;
....@@ -711,6 +709,10 @@
711709 len = 0;
712710 }
713711 ubifs_pack_pnode(c, p, pnode);
712
+ err = ubifs_shash_update(c, desc, p, c->pnode_sz);
713
+ if (err)
714
+ goto out;
715
+
714716 p += c->pnode_sz;
715717 len += c->pnode_sz;
716718 /*
....@@ -830,6 +832,10 @@
830832 if (err)
831833 goto out;
832834
835
+ err = ubifs_shash_final(c, desc, hash);
836
+ if (err)
837
+ goto out;
838
+
833839 c->nhead_lnum = lnum;
834840 c->nhead_offs = ALIGN(len, c->min_io_size);
835841
....@@ -853,6 +859,7 @@
853859 dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs);
854860 out:
855861 c->ltab = NULL;
862
+ kfree(desc);
856863 kfree(lsave);
857864 vfree(ltab);
858865 vfree(buf);
....@@ -1439,26 +1446,25 @@
14391446 }
14401447
14411448 /**
1442
- * ubifs_lpt_lookup - lookup LEB properties in the LPT.
1449
+ * ubifs_pnode_lookup - lookup a pnode in the LPT.
14431450 * @c: UBIFS file-system description object
1444
- * @lnum: LEB number to lookup
1451
+ * @i: pnode number (0 to (main_lebs - 1) / UBIFS_LPT_FANOUT)
14451452 *
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.
14481455 */
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)
14501457 {
1451
- int err, i, h, iip, shft;
1458
+ int err, h, iip, shft;
14521459 struct ubifs_nnode *nnode;
1453
- struct ubifs_pnode *pnode;
14541460
14551461 if (!c->nroot) {
14561462 err = ubifs_read_nnode(c, NULL, 0);
14571463 if (err)
14581464 return ERR_PTR(err);
14591465 }
1466
+ i <<= UBIFS_LPT_FANOUT_SHIFT;
14601467 nnode = c->nroot;
1461
- i = lnum - c->main_first;
14621468 shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
14631469 for (h = 1; h < c->lpt_hght; h++) {
14641470 iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
....@@ -1468,7 +1474,24 @@
14681474 return ERR_CAST(nnode);
14691475 }
14701476 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);
14721495 if (IS_ERR(pnode))
14731496 return ERR_CAST(pnode);
14741497 iip = (i & (UBIFS_LPT_FANOUT - 1));
....@@ -1620,6 +1643,131 @@
16201643 }
16211644
16221645 /**
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
+/**
16231771 * lpt_init_rd - initialize the LPT for reading.
16241772 * @c: UBIFS file-system description object
16251773 *
....@@ -1660,6 +1808,10 @@
16601808 if (err)
16611809 return err;
16621810
1811
+ err = lpt_check_hash(c);
1812
+ if (err)
1813
+ return err;
1814
+
16631815 dbg_lp("space_bits %d", c->space_bits);
16641816 dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits);
16651817 dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits);