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

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
...@@ -24,6 +24,42 @@ ...@@ -24,6 +24,42 @@
#include "ubifs.h" #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. * scan_for_master - search the valid master node.
* @c: UBIFS file-system description object * @c: UBIFS file-system description object
...@@ -37,7 +73,7 @@ static int scan_for_master(struct ubifs_info *c) ...@@ -37,7 +73,7 @@ static int scan_for_master(struct ubifs_info *c)
{ {
struct ubifs_scan_leb *sleb; struct ubifs_scan_leb *sleb;
struct ubifs_scan_node *snod; struct ubifs_scan_node *snod;
int lnum, offs = 0, nodes_cnt; int lnum, offs = 0, nodes_cnt, err;
lnum = UBIFS_MST_LNUM; lnum = UBIFS_MST_LNUM;
...@@ -69,12 +105,23 @@ static int scan_for_master(struct ubifs_info *c) ...@@ -69,12 +105,23 @@ static int scan_for_master(struct ubifs_info *c)
goto out_dump; goto out_dump;
if (snod->offs != offs) if (snod->offs != offs)
goto out; goto out;
if (memcmp((void *)c->mst_node + UBIFS_CH_SZ, if (ubifs_compare_master_node(c, c->mst_node, snod->node))
(void *)snod->node + UBIFS_CH_SZ,
UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
goto out; goto out;
c->mst_offs = offs; c->mst_offs = offs;
ubifs_scan_destroy(sleb); 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; return 0;
out: out:
...@@ -381,7 +428,8 @@ int ubifs_write_master(struct ubifs_info *c) ...@@ -381,7 +428,8 @@ int ubifs_write_master(struct ubifs_info *c)
c->mst_node->highest_inum = cpu_to_le64(c->highest_inum); c->mst_node->highest_inum = cpu_to_le64(c->highest_inum);
ubifs_copy_hash(c, c->zroot.hash, c->mst_node->hash_root_idx); 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) if (err)
return err; return err;
...@@ -392,7 +440,8 @@ int ubifs_write_master(struct ubifs_info *c) ...@@ -392,7 +440,8 @@ int ubifs_write_master(struct ubifs_info *c)
if (err) if (err)
return 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; return err;
} }
...@@ -212,7 +212,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c, ...@@ -212,7 +212,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c,
save_flags = mst->flags; save_flags = mst->flags;
mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY); 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); err = ubifs_leb_change(c, lnum, mst, sz);
if (err) if (err)
goto out; goto out;
...@@ -264,9 +267,7 @@ int ubifs_recover_master_node(struct ubifs_info *c) ...@@ -264,9 +267,7 @@ int ubifs_recover_master_node(struct ubifs_info *c)
offs2 = (void *)mst2 - buf2; offs2 = (void *)mst2 - buf2;
if (offs1 == offs2) { if (offs1 == offs2) {
/* Same offset, so must be the same */ /* Same offset, so must be the same */
if (memcmp((void *)mst1 + UBIFS_CH_SZ, if (ubifs_compare_master_node(c, mst1, mst2))
(void *)mst2 + UBIFS_CH_SZ,
UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
goto out_err; goto out_err;
mst = mst1; mst = mst1;
} else if (offs2 + sz == offs1) { } else if (offs2 + sz == offs1) {
......
...@@ -1900,6 +1900,7 @@ int ubifs_gc_should_commit(struct ubifs_info *c); ...@@ -1900,6 +1900,7 @@ int ubifs_gc_should_commit(struct ubifs_info *c);
void ubifs_wait_for_commit(struct ubifs_info *c); void ubifs_wait_for_commit(struct ubifs_info *c);
/* master.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_read_master(struct ubifs_info *c);
int ubifs_write_master(struct ubifs_info *c); int ubifs_write_master(struct ubifs_info *c);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment