| .. | .. | 
|---|
 | 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 |  } | 
|---|