aboutsummaryrefslogtreecommitdiff
path: root/fs/ubifs/master.c
diff options
context:
space:
mode:
authorSascha Hauer2018-09-07 14:36:40 +0200
committerRichard Weinberger2018-10-23 13:48:52 +0200
commit625700ccb5069ec81d15aae3b47282ecc59d63b5 (patch)
treef0c25183cc69de8ab9377aeb143006ee67d2a5e9 /fs/ubifs/master.c
parenta1dc58140f7e63e3b23050eb43b4e5581cb28c88 (diff)
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: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Richard Weinberger <richard@nod.at>
Diffstat (limited to 'fs/ubifs/master.c')
-rw-r--r--fs/ubifs/master.c61
1 files changed, 55 insertions, 6 deletions
diff --git a/fs/ubifs/master.c b/fs/ubifs/master.c
index 0ca9d3513b4d..5ea51bbd14c7 100644
--- a/fs/ubifs/master.c
+++ b/fs/ubifs/master.c
@@ -25,6 +25,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;
}