[PATCH 18/25] ubfis: authentication: authenticate master node

2018-07-04 Thread Sascha Hauer
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 
---
 fs/ubifs/master.c   | 61 -
 fs/ubifs/recovery.c |  7 +++---
 fs/ubifs/ubifs.h|  1 +
 3 files changed, 59 insertions(+), 10 deletions(-)

diff --git a/fs/ubifs/master.c b/fs/ubifs/master.c
index f1a96b50ec68..1f633601e95b 100644
--- a/fs/ubifs/master.c
+++ b/fs/ubifs/master.c
@@ -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;
 }
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index 3af4472061cc..3fa7c2cd96b9 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -212,7 +212,8 @@ 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);
+   ubifs_prepare_node_hmac(c, mst, UBIFS_MST_NODE_SZ,
+   offsetof(struct ubifs_mst_node, hmac), 1);
err = ubifs_leb_change(c, lnum, mst, sz);
if (err)
goto out;
@@ -264,9 +265,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 

[PATCH 18/25] ubfis: authentication: authenticate master node

2018-07-04 Thread Sascha Hauer
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 
---
 fs/ubifs/master.c   | 61 -
 fs/ubifs/recovery.c |  7 +++---
 fs/ubifs/ubifs.h|  1 +
 3 files changed, 59 insertions(+), 10 deletions(-)

diff --git a/fs/ubifs/master.c b/fs/ubifs/master.c
index f1a96b50ec68..1f633601e95b 100644
--- a/fs/ubifs/master.c
+++ b/fs/ubifs/master.c
@@ -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;
 }
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index 3af4472061cc..3fa7c2cd96b9 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -212,7 +212,8 @@ 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);
+   ubifs_prepare_node_hmac(c, mst, UBIFS_MST_NODE_SZ,
+   offsetof(struct ubifs_mst_node, hmac), 1);
err = ubifs_leb_change(c, lnum, mst, sz);
if (err)
goto out;
@@ -264,9 +265,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