Skip to content

Commit 625700c

Browse files
saschahauerrichardweinberger
authored andcommitted
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>
1 parent a1dc581 commit 625700c

File tree

3 files changed

+61
-10
lines changed

3 files changed

+61
-10
lines changed

fs/ubifs/master.c

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,42 @@
2424

2525
#include "ubifs.h"
2626

27+
/**
28+
* ubifs_compare_master_node - compare two UBIFS master nodes
29+
* @c: UBIFS file-system description object
30+
* @m1: the first node
31+
* @m2: the second node
32+
*
33+
* This function compares two UBIFS master nodes. Returns 0 if they are equal
34+
* and nonzero if not.
35+
*/
36+
int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2)
37+
{
38+
int ret;
39+
int behind;
40+
int hmac_offs = offsetof(struct ubifs_mst_node, hmac);
41+
42+
/*
43+
* Do not compare the common node header since the sequence number and
44+
* hence the CRC are different.
45+
*/
46+
ret = memcmp(m1 + UBIFS_CH_SZ, m2 + UBIFS_CH_SZ,
47+
hmac_offs - UBIFS_CH_SZ);
48+
if (ret)
49+
return ret;
50+
51+
/*
52+
* Do not compare the embedded HMAC aswell which also must be different
53+
* due to the different common node header.
54+
*/
55+
behind = hmac_offs + UBIFS_MAX_HMAC_LEN;
56+
57+
if (UBIFS_MST_NODE_SZ > behind)
58+
return memcmp(m1 + behind, m2 + behind, UBIFS_MST_NODE_SZ - behind);
59+
60+
return 0;
61+
}
62+
2763
/**
2864
* scan_for_master - search the valid master node.
2965
* @c: UBIFS file-system description object
@@ -37,7 +73,7 @@ static int scan_for_master(struct ubifs_info *c)
3773
{
3874
struct ubifs_scan_leb *sleb;
3975
struct ubifs_scan_node *snod;
40-
int lnum, offs = 0, nodes_cnt;
76+
int lnum, offs = 0, nodes_cnt, err;
4177

4278
lnum = UBIFS_MST_LNUM;
4379

@@ -69,12 +105,23 @@ static int scan_for_master(struct ubifs_info *c)
69105
goto out_dump;
70106
if (snod->offs != offs)
71107
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))
108+
if (ubifs_compare_master_node(c, c->mst_node, snod->node))
75109
goto out;
110+
76111
c->mst_offs = offs;
77112
ubifs_scan_destroy(sleb);
113+
114+
if (!ubifs_authenticated(c))
115+
return 0;
116+
117+
err = ubifs_node_verify_hmac(c, c->mst_node,
118+
sizeof(struct ubifs_mst_node),
119+
offsetof(struct ubifs_mst_node, hmac));
120+
if (err) {
121+
ubifs_err(c, "Failed to verify master node HMAC");
122+
return -EPERM;
123+
}
124+
78125
return 0;
79126

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

383430
ubifs_copy_hash(c, c->zroot.hash, c->mst_node->hash_root_idx);
384-
err = ubifs_write_node(c, c->mst_node, len, lnum, offs);
431+
err = ubifs_write_node_hmac(c, c->mst_node, len, lnum, offs,
432+
offsetof(struct ubifs_mst_node, hmac));
385433
if (err)
386434
return err;
387435

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

397446
return err;
398447
}

fs/ubifs/recovery.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c,
212212
save_flags = mst->flags;
213213
mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY);
214214

215-
ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1);
215+
err = ubifs_prepare_node_hmac(c, mst, UBIFS_MST_NODE_SZ,
216+
offsetof(struct ubifs_mst_node, hmac), 1);
217+
if (err)
218+
goto out;
216219
err = ubifs_leb_change(c, lnum, mst, sz);
217220
if (err)
218221
goto out;
@@ -264,9 +267,7 @@ int ubifs_recover_master_node(struct ubifs_info *c)
264267
offs2 = (void *)mst2 - buf2;
265268
if (offs1 == offs2) {
266269
/* Same offset, so must be the same */
267-
if (memcmp((void *)mst1 + UBIFS_CH_SZ,
268-
(void *)mst2 + UBIFS_CH_SZ,
269-
UBIFS_MST_NODE_SZ - UBIFS_CH_SZ))
270+
if (ubifs_compare_master_node(c, mst1, mst2))
270271
goto out_err;
271272
mst = mst1;
272273
} else if (offs2 + sz == offs1) {

fs/ubifs/ubifs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,6 +1900,7 @@ int ubifs_gc_should_commit(struct ubifs_info *c);
19001900
void ubifs_wait_for_commit(struct ubifs_info *c);
19011901

19021902
/* master.c */
1903+
int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2);
19031904
int ubifs_read_master(struct ubifs_info *c);
19041905
int ubifs_write_master(struct ubifs_info *c);
19051906

0 commit comments

Comments
 (0)