.. | .. |
---|
| 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: Artem Bityutskiy (Битюцкий Артём) |
---|
20 | 8 | * Adrian Hunter |
---|
.. | .. |
---|
23 | 11 | /* This file implements reading and writing the master node */ |
---|
24 | 12 | |
---|
25 | 13 | #include "ubifs.h" |
---|
| 14 | + |
---|
| 15 | +/** |
---|
| 16 | + * ubifs_compare_master_node - compare two UBIFS master nodes |
---|
| 17 | + * @c: UBIFS file-system description object |
---|
| 18 | + * @m1: the first node |
---|
| 19 | + * @m2: the second node |
---|
| 20 | + * |
---|
| 21 | + * This function compares two UBIFS master nodes. Returns 0 if they are equal |
---|
| 22 | + * and nonzero if not. |
---|
| 23 | + */ |
---|
| 24 | +int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2) |
---|
| 25 | +{ |
---|
| 26 | + int ret; |
---|
| 27 | + int behind; |
---|
| 28 | + int hmac_offs = offsetof(struct ubifs_mst_node, hmac); |
---|
| 29 | + |
---|
| 30 | + /* |
---|
| 31 | + * Do not compare the common node header since the sequence number and |
---|
| 32 | + * hence the CRC are different. |
---|
| 33 | + */ |
---|
| 34 | + ret = memcmp(m1 + UBIFS_CH_SZ, m2 + UBIFS_CH_SZ, |
---|
| 35 | + hmac_offs - UBIFS_CH_SZ); |
---|
| 36 | + if (ret) |
---|
| 37 | + return ret; |
---|
| 38 | + |
---|
| 39 | + /* |
---|
| 40 | + * Do not compare the embedded HMAC aswell which also must be different |
---|
| 41 | + * due to the different common node header. |
---|
| 42 | + */ |
---|
| 43 | + behind = hmac_offs + UBIFS_MAX_HMAC_LEN; |
---|
| 44 | + |
---|
| 45 | + if (UBIFS_MST_NODE_SZ > behind) |
---|
| 46 | + return memcmp(m1 + behind, m2 + behind, UBIFS_MST_NODE_SZ - behind); |
---|
| 47 | + |
---|
| 48 | + return 0; |
---|
| 49 | +} |
---|
| 50 | + |
---|
| 51 | +/* mst_node_check_hash - Check hash of a master node |
---|
| 52 | + * @c: UBIFS file-system description object |
---|
| 53 | + * @mst: The master node |
---|
| 54 | + * @expected: The expected hash of the master node |
---|
| 55 | + * |
---|
| 56 | + * This checks the hash of a master node against a given expected hash. |
---|
| 57 | + * Note that we have two master nodes on a UBIFS image which have different |
---|
| 58 | + * sequence numbers and consequently different CRCs. To be able to match |
---|
| 59 | + * both master nodes we exclude the common node header containing the sequence |
---|
| 60 | + * number and CRC from the hash. |
---|
| 61 | + * |
---|
| 62 | + * Returns 0 if the hashes are equal, a negative error code otherwise. |
---|
| 63 | + */ |
---|
| 64 | +static int mst_node_check_hash(const struct ubifs_info *c, |
---|
| 65 | + const struct ubifs_mst_node *mst, |
---|
| 66 | + const u8 *expected) |
---|
| 67 | +{ |
---|
| 68 | + u8 calc[UBIFS_MAX_HASH_LEN]; |
---|
| 69 | + const void *node = mst; |
---|
| 70 | + |
---|
| 71 | + crypto_shash_tfm_digest(c->hash_tfm, node + sizeof(struct ubifs_ch), |
---|
| 72 | + UBIFS_MST_NODE_SZ - sizeof(struct ubifs_ch), |
---|
| 73 | + calc); |
---|
| 74 | + |
---|
| 75 | + if (ubifs_check_hash(c, expected, calc)) |
---|
| 76 | + return -EPERM; |
---|
| 77 | + |
---|
| 78 | + return 0; |
---|
| 79 | +} |
---|
26 | 80 | |
---|
27 | 81 | /** |
---|
28 | 82 | * scan_for_master - search the valid master node. |
---|
.. | .. |
---|
37 | 91 | { |
---|
38 | 92 | struct ubifs_scan_leb *sleb; |
---|
39 | 93 | struct ubifs_scan_node *snod; |
---|
40 | | - int lnum, offs = 0, nodes_cnt; |
---|
| 94 | + int lnum, offs = 0, nodes_cnt, err; |
---|
41 | 95 | |
---|
42 | 96 | lnum = UBIFS_MST_LNUM; |
---|
43 | 97 | |
---|
.. | .. |
---|
69 | 123 | goto out_dump; |
---|
70 | 124 | if (snod->offs != offs) |
---|
71 | 125 | goto out; |
---|
72 | | - if (memcmp((void *)c->mst_node + UBIFS_CH_SZ, |
---|
73 | | - (void *)snod->node + UBIFS_CH_SZ, |
---|
74 | | - UBIFS_MST_NODE_SZ - UBIFS_CH_SZ)) |
---|
| 126 | + if (ubifs_compare_master_node(c, c->mst_node, snod->node)) |
---|
75 | 127 | goto out; |
---|
| 128 | + |
---|
76 | 129 | c->mst_offs = offs; |
---|
77 | 130 | ubifs_scan_destroy(sleb); |
---|
| 131 | + |
---|
| 132 | + if (!ubifs_authenticated(c)) |
---|
| 133 | + return 0; |
---|
| 134 | + |
---|
| 135 | + if (ubifs_hmac_zero(c, c->mst_node->hmac)) { |
---|
| 136 | + err = mst_node_check_hash(c, c->mst_node, |
---|
| 137 | + c->sup_node->hash_mst); |
---|
| 138 | + if (err) |
---|
| 139 | + ubifs_err(c, "Failed to verify master node hash"); |
---|
| 140 | + } else { |
---|
| 141 | + err = ubifs_node_verify_hmac(c, c->mst_node, |
---|
| 142 | + sizeof(struct ubifs_mst_node), |
---|
| 143 | + offsetof(struct ubifs_mst_node, hmac)); |
---|
| 144 | + if (err) |
---|
| 145 | + ubifs_err(c, "Failed to verify master node HMAC"); |
---|
| 146 | + } |
---|
| 147 | + |
---|
| 148 | + if (err) |
---|
| 149 | + return -EPERM; |
---|
| 150 | + |
---|
78 | 151 | return 0; |
---|
79 | 152 | |
---|
80 | 153 | out: |
---|
.. | .. |
---|
305 | 378 | c->lst.total_dead = le64_to_cpu(c->mst_node->total_dead); |
---|
306 | 379 | c->lst.total_dark = le64_to_cpu(c->mst_node->total_dark); |
---|
307 | 380 | |
---|
| 381 | + ubifs_copy_hash(c, c->mst_node->hash_root_idx, c->zroot.hash); |
---|
| 382 | + |
---|
308 | 383 | c->calc_idx_sz = c->bi.old_idx_sz; |
---|
309 | 384 | |
---|
310 | 385 | if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS)) |
---|
.. | .. |
---|
378 | 453 | c->mst_offs = offs; |
---|
379 | 454 | c->mst_node->highest_inum = cpu_to_le64(c->highest_inum); |
---|
380 | 455 | |
---|
381 | | - err = ubifs_write_node(c, c->mst_node, len, lnum, offs); |
---|
| 456 | + ubifs_copy_hash(c, c->zroot.hash, c->mst_node->hash_root_idx); |
---|
| 457 | + err = ubifs_write_node_hmac(c, c->mst_node, len, lnum, offs, |
---|
| 458 | + offsetof(struct ubifs_mst_node, hmac)); |
---|
382 | 459 | if (err) |
---|
383 | 460 | return err; |
---|
384 | 461 | |
---|
.. | .. |
---|
389 | 466 | if (err) |
---|
390 | 467 | return err; |
---|
391 | 468 | } |
---|
392 | | - err = ubifs_write_node(c, c->mst_node, len, lnum, offs); |
---|
| 469 | + err = ubifs_write_node_hmac(c, c->mst_node, len, lnum, offs, |
---|
| 470 | + offsetof(struct ubifs_mst_node, hmac)); |
---|
393 | 471 | |
---|
394 | 472 | return err; |
---|
395 | 473 | } |
---|