diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2018-09-07 08:36:40 -0400 |
---|---|---|
committer | Richard Weinberger <richard@nod.at> | 2018-10-23 07:48:52 -0400 |
commit | 625700ccb5069ec81d15aae3b47282ecc59d63b5 (patch) | |
tree | f0c25183cc69de8ab9377aeb143006ee67d2a5e9 | |
parent | a1dc58140f7e63e3b23050eb43b4e5581cb28c88 (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>
-rw-r--r-- | fs/ubifs/master.c | 61 | ||||
-rw-r--r-- | fs/ubifs/recovery.c | 9 | ||||
-rw-r--r-- | fs/ubifs/ubifs.h | 1 |
3 files changed, 61 insertions, 10 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 @@ | |||
25 | #include "ubifs.h" | 25 | #include "ubifs.h" |
26 | 26 | ||
27 | /** | 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 | |||
63 | /** | ||
28 | * scan_for_master - search the valid master node. | 64 | * scan_for_master - search the valid master node. |
29 | * @c: UBIFS file-system description object | 65 | * @c: UBIFS file-system description object |
30 | * | 66 | * |
@@ -37,7 +73,7 @@ static int scan_for_master(struct ubifs_info *c) | |||
37 | { | 73 | { |
38 | struct ubifs_scan_leb *sleb; | 74 | struct ubifs_scan_leb *sleb; |
39 | struct ubifs_scan_node *snod; | 75 | struct ubifs_scan_node *snod; |
40 | int lnum, offs = 0, nodes_cnt; | 76 | int lnum, offs = 0, nodes_cnt, err; |
41 | 77 | ||
42 | lnum = UBIFS_MST_LNUM; | 78 | lnum = UBIFS_MST_LNUM; |
43 | 79 | ||
@@ -69,12 +105,23 @@ static int scan_for_master(struct ubifs_info *c) | |||
69 | goto out_dump; | 105 | goto out_dump; |
70 | if (snod->offs != offs) | 106 | if (snod->offs != offs) |
71 | goto out; | 107 | goto out; |
72 | if (memcmp((void *)c->mst_node + UBIFS_CH_SZ, | 108 | if (ubifs_compare_master_node(c, c->mst_node, snod->node)) |
73 | (void *)snod->node + UBIFS_CH_SZ, | ||
74 | UBIFS_MST_NODE_SZ - UBIFS_CH_SZ)) | ||
75 | goto out; | 109 | goto out; |
110 | |||
76 | c->mst_offs = offs; | 111 | c->mst_offs = offs; |
77 | ubifs_scan_destroy(sleb); | 112 | 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 | |||
78 | return 0; | 125 | return 0; |
79 | 126 | ||
80 | out: | 127 | out: |
@@ -381,7 +428,8 @@ int ubifs_write_master(struct ubifs_info *c) | |||
381 | c->mst_node->highest_inum = cpu_to_le64(c->highest_inum); | 428 | c->mst_node->highest_inum = cpu_to_le64(c->highest_inum); |
382 | 429 | ||
383 | ubifs_copy_hash(c, c->zroot.hash, c->mst_node->hash_root_idx); | 430 | 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)); | ||
385 | if (err) | 433 | if (err) |
386 | return err; | 434 | return err; |
387 | 435 | ||
@@ -392,7 +440,8 @@ int ubifs_write_master(struct ubifs_info *c) | |||
392 | if (err) | 440 | if (err) |
393 | return err; | 441 | return err; |
394 | } | 442 | } |
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)); | ||
396 | 445 | ||
397 | return err; | 446 | return err; |
398 | } | 447 | } |
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c index 984e30e83c0b..5c1334e6bc81 100644 --- a/fs/ubifs/recovery.c +++ b/fs/ubifs/recovery.c | |||
@@ -212,7 +212,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c, | |||
212 | save_flags = mst->flags; | 212 | save_flags = mst->flags; |
213 | mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY); | 213 | mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY); |
214 | 214 | ||
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; | ||
216 | err = ubifs_leb_change(c, lnum, mst, sz); | 219 | err = ubifs_leb_change(c, lnum, mst, sz); |
217 | if (err) | 220 | if (err) |
218 | goto out; | 221 | goto out; |
@@ -264,9 +267,7 @@ int ubifs_recover_master_node(struct ubifs_info *c) | |||
264 | offs2 = (void *)mst2 - buf2; | 267 | offs2 = (void *)mst2 - buf2; |
265 | if (offs1 == offs2) { | 268 | if (offs1 == offs2) { |
266 | /* Same offset, so must be the same */ | 269 | /* Same offset, so must be the same */ |
267 | if (memcmp((void *)mst1 + UBIFS_CH_SZ, | 270 | if (ubifs_compare_master_node(c, mst1, mst2)) |
268 | (void *)mst2 + UBIFS_CH_SZ, | ||
269 | UBIFS_MST_NODE_SZ - UBIFS_CH_SZ)) | ||
270 | goto out_err; | 271 | goto out_err; |
271 | mst = mst1; | 272 | mst = mst1; |
272 | } else if (offs2 + sz == offs1) { | 273 | } else if (offs2 + sz == offs1) { |
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 7e519a4885a8..c26d3c600e4d 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h | |||
@@ -1900,6 +1900,7 @@ int ubifs_gc_should_commit(struct ubifs_info *c); | |||
1900 | void ubifs_wait_for_commit(struct ubifs_info *c); | 1900 | void ubifs_wait_for_commit(struct ubifs_info *c); |
1901 | 1901 | ||
1902 | /* master.c */ | 1902 | /* master.c */ |
1903 | int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2); | ||
1903 | int ubifs_read_master(struct ubifs_info *c); | 1904 | int ubifs_read_master(struct ubifs_info *c); |
1904 | int ubifs_write_master(struct ubifs_info *c); | 1905 | int ubifs_write_master(struct ubifs_info *c); |
1905 | 1906 | ||