Commit 625700cc authored by Sascha Hauer's avatar Sascha Hauer Committed by Richard Weinberger
Browse files

ubfis: authentication: Authenticate master node



The master node contains hashes over the root index node and the LPT.
This patch adds a HMAC to authenticate the master node itself.

Signed-off-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
parent a1dc5814
Loading
Loading
Loading
Loading
+55 −6
Original line number Diff line number Diff line
@@ -24,6 +24,42 @@

#include "ubifs.h"

/**
 * ubifs_compare_master_node - compare two UBIFS master nodes
 * @c: UBIFS file-system description object
 * @m1: the first node
 * @m2: the second node
 *
 * This function compares two UBIFS master nodes. Returns 0 if they are equal
 * and nonzero if not.
 */
int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2)
{
	int ret;
	int behind;
	int hmac_offs = offsetof(struct ubifs_mst_node, hmac);

	/*
	 * Do not compare the common node header since the sequence number and
	 * hence the CRC are different.
	 */
	ret = memcmp(m1 + UBIFS_CH_SZ, m2 + UBIFS_CH_SZ,
		     hmac_offs - UBIFS_CH_SZ);
	if (ret)
		return ret;

	/*
	 * Do not compare the embedded HMAC aswell which also must be different
	 * due to the different common node header.
	 */
	behind = hmac_offs + UBIFS_MAX_HMAC_LEN;

	if (UBIFS_MST_NODE_SZ > behind)
		return memcmp(m1 + behind, m2 + behind, UBIFS_MST_NODE_SZ - behind);

	return 0;
}

/**
 * scan_for_master - search the valid master node.
 * @c: UBIFS file-system description object
@@ -37,7 +73,7 @@ static int scan_for_master(struct ubifs_info *c)
{
	struct ubifs_scan_leb *sleb;
	struct ubifs_scan_node *snod;
	int lnum, offs = 0, nodes_cnt;
	int lnum, offs = 0, nodes_cnt, err;

	lnum = UBIFS_MST_LNUM;

@@ -69,12 +105,23 @@ static int scan_for_master(struct ubifs_info *c)
		goto out_dump;
	if (snod->offs != offs)
		goto out;
	if (memcmp((void *)c->mst_node + UBIFS_CH_SZ,
		   (void *)snod->node + UBIFS_CH_SZ,
		   UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
	if (ubifs_compare_master_node(c, c->mst_node, snod->node))
		goto out;

	c->mst_offs = offs;
	ubifs_scan_destroy(sleb);

	if (!ubifs_authenticated(c))
		return 0;

	err = ubifs_node_verify_hmac(c, c->mst_node,
				     sizeof(struct ubifs_mst_node),
				     offsetof(struct ubifs_mst_node, hmac));
	if (err) {
		ubifs_err(c, "Failed to verify master node HMAC");
		return -EPERM;
	}

	return 0;

out:
@@ -381,7 +428,8 @@ int ubifs_write_master(struct ubifs_info *c)
	c->mst_node->highest_inum = cpu_to_le64(c->highest_inum);

	ubifs_copy_hash(c, c->zroot.hash, c->mst_node->hash_root_idx);
	err = ubifs_write_node(c, c->mst_node, len, lnum, offs);
	err = ubifs_write_node_hmac(c, c->mst_node, len, lnum, offs,
				    offsetof(struct ubifs_mst_node, hmac));
	if (err)
		return err;

@@ -392,7 +440,8 @@ int ubifs_write_master(struct ubifs_info *c)
		if (err)
			return err;
	}
	err = ubifs_write_node(c, c->mst_node, len, lnum, offs);
	err = ubifs_write_node_hmac(c, c->mst_node, len, lnum, offs,
				    offsetof(struct ubifs_mst_node, hmac));

	return err;
}
+5 −4
Original line number Diff line number Diff line
@@ -212,7 +212,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c,
	save_flags = mst->flags;
	mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY);

	ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1);
	err = ubifs_prepare_node_hmac(c, mst, UBIFS_MST_NODE_SZ,
				      offsetof(struct ubifs_mst_node, hmac), 1);
	if (err)
		goto out;
	err = ubifs_leb_change(c, lnum, mst, sz);
	if (err)
		goto out;
@@ -264,9 +267,7 @@ int ubifs_recover_master_node(struct ubifs_info *c)
			offs2 = (void *)mst2 - buf2;
			if (offs1 == offs2) {
				/* Same offset, so must be the same */
				if (memcmp((void *)mst1 + UBIFS_CH_SZ,
					   (void *)mst2 + UBIFS_CH_SZ,
					   UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
				if (ubifs_compare_master_node(c, mst1, mst2))
					goto out_err;
				mst = mst1;
			} else if (offs2 + sz == offs1) {
+1 −0
Original line number Diff line number Diff line
@@ -1900,6 +1900,7 @@ int ubifs_gc_should_commit(struct ubifs_info *c);
void ubifs_wait_for_commit(struct ubifs_info *c);

/* master.c */
int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2);
int ubifs_read_master(struct ubifs_info *c);
int ubifs_write_master(struct ubifs_info *c);