summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2018-09-07 08:36:35 -0400
committerRichard Weinberger <richard@nod.at>2018-10-23 07:48:39 -0400
commit16a26b20d2afd0cf063816725b45b12e78d5bb31 (patch)
tree3537a8eecd5da38204e443a887f4d1ed9f3cbcbe
parent823838a486888cf484e739ab37df14cb04dfddb5 (diff)
ubifs: authentication: Add hashes to index nodes
With this patch the hashes over the index nodes stored in the tree node cache are written to flash and are checked when read back from flash. The hash of the root index node is stored in the master node. During journal replay the hashes are regenerated from the read nodes and stored in the tree node cache. This means the nodes must previously be authenticated by other means. This is done in a later patch. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Richard Weinberger <richard@nod.at>
-rw-r--r--fs/ubifs/master.c3
-rw-r--r--fs/ubifs/misc.h5
-rw-r--r--fs/ubifs/replay.c29
-rw-r--r--fs/ubifs/tnc.c12
-rw-r--r--fs/ubifs/tnc_commit.c27
-rw-r--r--fs/ubifs/tnc_misc.c15
-rw-r--r--fs/ubifs/ubifs.h4
7 files changed, 81 insertions, 14 deletions
diff --git a/fs/ubifs/master.c b/fs/ubifs/master.c
index 9df4a41bba52..0ca9d3513b4d 100644
--- a/fs/ubifs/master.c
+++ b/fs/ubifs/master.c
@@ -305,6 +305,8 @@ int ubifs_read_master(struct ubifs_info *c)
305 c->lst.total_dead = le64_to_cpu(c->mst_node->total_dead); 305 c->lst.total_dead = le64_to_cpu(c->mst_node->total_dead);
306 c->lst.total_dark = le64_to_cpu(c->mst_node->total_dark); 306 c->lst.total_dark = le64_to_cpu(c->mst_node->total_dark);
307 307
308 ubifs_copy_hash(c, c->mst_node->hash_root_idx, c->zroot.hash);
309
308 c->calc_idx_sz = c->bi.old_idx_sz; 310 c->calc_idx_sz = c->bi.old_idx_sz;
309 311
310 if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS)) 312 if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS))
@@ -378,6 +380,7 @@ int ubifs_write_master(struct ubifs_info *c)
378 c->mst_offs = offs; 380 c->mst_offs = offs;
379 c->mst_node->highest_inum = cpu_to_le64(c->highest_inum); 381 c->mst_node->highest_inum = cpu_to_le64(c->highest_inum);
380 382
383 ubifs_copy_hash(c, c->zroot.hash, c->mst_node->hash_root_idx);
381 err = ubifs_write_node(c, c->mst_node, len, lnum, offs); 384 err = ubifs_write_node(c, c->mst_node, len, lnum, offs);
382 if (err) 385 if (err)
383 return err; 386 return err;
diff --git a/fs/ubifs/misc.h b/fs/ubifs/misc.h
index 21d35d7dd975..6f87237fdbf4 100644
--- a/fs/ubifs/misc.h
+++ b/fs/ubifs/misc.h
@@ -197,7 +197,8 @@ static inline int ubifs_return_leb(struct ubifs_info *c, int lnum)
197 */ 197 */
198static inline int ubifs_idx_node_sz(const struct ubifs_info *c, int child_cnt) 198static inline int ubifs_idx_node_sz(const struct ubifs_info *c, int child_cnt)
199{ 199{
200 return UBIFS_IDX_NODE_SZ + (UBIFS_BRANCH_SZ + c->key_len) * child_cnt; 200 return UBIFS_IDX_NODE_SZ + (UBIFS_BRANCH_SZ + c->key_len + c->hash_len)
201 * child_cnt;
201} 202}
202 203
203/** 204/**
@@ -212,7 +213,7 @@ struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c,
212 int bnum) 213 int bnum)
213{ 214{
214 return (struct ubifs_branch *)((void *)idx->branches + 215 return (struct ubifs_branch *)((void *)idx->branches +
215 (UBIFS_BRANCH_SZ + c->key_len) * bnum); 216 (UBIFS_BRANCH_SZ + c->key_len + c->hash_len) * bnum);
216} 217}
217 218
218/** 219/**
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index bccb35f72277..1c6ceb6265aa 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -56,6 +56,7 @@ struct replay_entry {
56 int lnum; 56 int lnum;
57 int offs; 57 int offs;
58 int len; 58 int len;
59 u8 hash[UBIFS_HASH_ARR_SZ];
59 unsigned int deletion:1; 60 unsigned int deletion:1;
60 unsigned long long sqnum; 61 unsigned long long sqnum;
61 struct list_head list; 62 struct list_head list;
@@ -228,7 +229,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
228 err = ubifs_tnc_remove_nm(c, &r->key, &r->nm); 229 err = ubifs_tnc_remove_nm(c, &r->key, &r->nm);
229 else 230 else
230 err = ubifs_tnc_add_nm(c, &r->key, r->lnum, r->offs, 231 err = ubifs_tnc_add_nm(c, &r->key, r->lnum, r->offs,
231 r->len, NULL, &r->nm); 232 r->len, r->hash, &r->nm);
232 } else { 233 } else {
233 if (r->deletion) 234 if (r->deletion)
234 switch (key_type(c, &r->key)) { 235 switch (key_type(c, &r->key)) {
@@ -248,7 +249,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
248 } 249 }
249 else 250 else
250 err = ubifs_tnc_add(c, &r->key, r->lnum, r->offs, 251 err = ubifs_tnc_add(c, &r->key, r->lnum, r->offs,
251 r->len, NULL); 252 r->len, r->hash);
252 if (err) 253 if (err)
253 return err; 254 return err;
254 255
@@ -352,9 +353,9 @@ static void destroy_replay_list(struct ubifs_info *c)
352 * in case of success and a negative error code in case of failure. 353 * in case of success and a negative error code in case of failure.
353 */ 354 */
354static int insert_node(struct ubifs_info *c, int lnum, int offs, int len, 355static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
355 union ubifs_key *key, unsigned long long sqnum, 356 const u8 *hash, union ubifs_key *key,
356 int deletion, int *used, loff_t old_size, 357 unsigned long long sqnum, int deletion, int *used,
357 loff_t new_size) 358 loff_t old_size, loff_t new_size)
358{ 359{
359 struct replay_entry *r; 360 struct replay_entry *r;
360 361
@@ -372,6 +373,7 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
372 r->lnum = lnum; 373 r->lnum = lnum;
373 r->offs = offs; 374 r->offs = offs;
374 r->len = len; 375 r->len = len;
376 ubifs_copy_hash(c, hash, r->hash);
375 r->deletion = !!deletion; 377 r->deletion = !!deletion;
376 r->sqnum = sqnum; 378 r->sqnum = sqnum;
377 key_copy(c, key, &r->key); 379 key_copy(c, key, &r->key);
@@ -400,8 +402,9 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
400 * negative error code in case of failure. 402 * negative error code in case of failure.
401 */ 403 */
402static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len, 404static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
403 union ubifs_key *key, const char *name, int nlen, 405 const u8 *hash, union ubifs_key *key,
404 unsigned long long sqnum, int deletion, int *used) 406 const char *name, int nlen, unsigned long long sqnum,
407 int deletion, int *used)
405{ 408{
406 struct replay_entry *r; 409 struct replay_entry *r;
407 char *nbuf; 410 char *nbuf;
@@ -425,6 +428,7 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
425 r->lnum = lnum; 428 r->lnum = lnum;
426 r->offs = offs; 429 r->offs = offs;
427 r->len = len; 430 r->len = len;
431 ubifs_copy_hash(c, hash, r->hash);
428 r->deletion = !!deletion; 432 r->deletion = !!deletion;
429 r->sqnum = sqnum; 433 r->sqnum = sqnum;
430 key_copy(c, key, &r->key); 434 key_copy(c, key, &r->key);
@@ -582,6 +586,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
582 */ 586 */
583 587
584 list_for_each_entry(snod, &sleb->nodes, list) { 588 list_for_each_entry(snod, &sleb->nodes, list) {
589 u8 hash[UBIFS_HASH_ARR_SZ];
585 int deletion = 0; 590 int deletion = 0;
586 591
587 cond_resched(); 592 cond_resched();
@@ -591,6 +596,8 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
591 goto out_dump; 596 goto out_dump;
592 } 597 }
593 598
599 ubifs_node_calc_hash(c, snod->node, hash);
600
594 if (snod->sqnum > c->max_sqnum) 601 if (snod->sqnum > c->max_sqnum)
595 c->max_sqnum = snod->sqnum; 602 c->max_sqnum = snod->sqnum;
596 603
@@ -602,7 +609,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
602 609
603 if (le32_to_cpu(ino->nlink) == 0) 610 if (le32_to_cpu(ino->nlink) == 0)
604 deletion = 1; 611 deletion = 1;
605 err = insert_node(c, lnum, snod->offs, snod->len, 612 err = insert_node(c, lnum, snod->offs, snod->len, hash,
606 &snod->key, snod->sqnum, deletion, 613 &snod->key, snod->sqnum, deletion,
607 &used, 0, new_size); 614 &used, 0, new_size);
608 break; 615 break;
@@ -614,7 +621,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
614 key_block(c, &snod->key) * 621 key_block(c, &snod->key) *
615 UBIFS_BLOCK_SIZE; 622 UBIFS_BLOCK_SIZE;
616 623
617 err = insert_node(c, lnum, snod->offs, snod->len, 624 err = insert_node(c, lnum, snod->offs, snod->len, hash,
618 &snod->key, snod->sqnum, deletion, 625 &snod->key, snod->sqnum, deletion,
619 &used, 0, new_size); 626 &used, 0, new_size);
620 break; 627 break;
@@ -628,7 +635,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
628 if (err) 635 if (err)
629 goto out_dump; 636 goto out_dump;
630 637
631 err = insert_dent(c, lnum, snod->offs, snod->len, 638 err = insert_dent(c, lnum, snod->offs, snod->len, hash,
632 &snod->key, dent->name, 639 &snod->key, dent->name,
633 le16_to_cpu(dent->nlen), snod->sqnum, 640 le16_to_cpu(dent->nlen), snod->sqnum,
634 !le64_to_cpu(dent->inum), &used); 641 !le64_to_cpu(dent->inum), &used);
@@ -654,7 +661,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
654 * functions which expect nodes to have keys. 661 * functions which expect nodes to have keys.
655 */ 662 */
656 trun_key_init(c, &key, le32_to_cpu(trun->inum)); 663 trun_key_init(c, &key, le32_to_cpu(trun->inum));
657 err = insert_node(c, lnum, snod->offs, snod->len, 664 err = insert_node(c, lnum, snod->offs, snod->len, hash,
658 &key, snod->sqnum, 1, &used, 665 &key, snod->sqnum, 1, &used,
659 old_size, new_size); 666 old_size, new_size);
660 break; 667 break;
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index bb5f989a6e06..25572ffea163 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -488,6 +488,12 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
488 if (crc != node_crc) 488 if (crc != node_crc)
489 return 0; 489 return 0;
490 490
491 err = ubifs_node_check_hash(c, buf, zbr->hash);
492 if (err) {
493 ubifs_bad_hash(c, buf, zbr->hash, lnum, offs);
494 return 0;
495 }
496
491 return 1; 497 return 1;
492} 498}
493 499
@@ -1713,6 +1719,12 @@ static int validate_data_node(struct ubifs_info *c, void *buf,
1713 goto out; 1719 goto out;
1714 } 1720 }
1715 1721
1722 err = ubifs_node_check_hash(c, buf, zbr->hash);
1723 if (err) {
1724 ubifs_bad_hash(c, buf, zbr->hash, zbr->lnum, zbr->offs);
1725 return err;
1726 }
1727
1716 len = le32_to_cpu(ch->len); 1728 len = le32_to_cpu(ch->len);
1717 if (len != zbr->len) { 1729 if (len != zbr->len) {
1718 ubifs_err(c, "bad node length %d, expected %d", len, zbr->len); 1730 ubifs_err(c, "bad node length %d, expected %d", len, zbr->len);
diff --git a/fs/ubifs/tnc_commit.c b/fs/ubifs/tnc_commit.c
index dba87d09b989..dbcd2c350b65 100644
--- a/fs/ubifs/tnc_commit.c
+++ b/fs/ubifs/tnc_commit.c
@@ -38,6 +38,7 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
38 struct ubifs_znode *znode, int lnum, int offs, int len) 38 struct ubifs_znode *znode, int lnum, int offs, int len)
39{ 39{
40 struct ubifs_znode *zp; 40 struct ubifs_znode *zp;
41 u8 hash[UBIFS_HASH_ARR_SZ];
41 int i, err; 42 int i, err;
42 43
43 /* Make index node */ 44 /* Make index node */
@@ -52,6 +53,7 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
52 br->lnum = cpu_to_le32(zbr->lnum); 53 br->lnum = cpu_to_le32(zbr->lnum);
53 br->offs = cpu_to_le32(zbr->offs); 54 br->offs = cpu_to_le32(zbr->offs);
54 br->len = cpu_to_le32(zbr->len); 55 br->len = cpu_to_le32(zbr->len);
56 ubifs_copy_hash(c, zbr->hash, ubifs_branch_hash(c, br));
55 if (!zbr->lnum || !zbr->len) { 57 if (!zbr->lnum || !zbr->len) {
56 ubifs_err(c, "bad ref in znode"); 58 ubifs_err(c, "bad ref in znode");
57 ubifs_dump_znode(c, znode); 59 ubifs_dump_znode(c, znode);
@@ -62,6 +64,7 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
62 } 64 }
63 } 65 }
64 ubifs_prepare_node(c, idx, len, 0); 66 ubifs_prepare_node(c, idx, len, 0);
67 ubifs_node_calc_hash(c, idx, hash);
65 68
66 znode->lnum = lnum; 69 znode->lnum = lnum;
67 znode->offs = offs; 70 znode->offs = offs;
@@ -78,10 +81,12 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
78 zbr->lnum = lnum; 81 zbr->lnum = lnum;
79 zbr->offs = offs; 82 zbr->offs = offs;
80 zbr->len = len; 83 zbr->len = len;
84 ubifs_copy_hash(c, hash, zbr->hash);
81 } else { 85 } else {
82 c->zroot.lnum = lnum; 86 c->zroot.lnum = lnum;
83 c->zroot.offs = offs; 87 c->zroot.offs = offs;
84 c->zroot.len = len; 88 c->zroot.len = len;
89 ubifs_copy_hash(c, hash, c->zroot.hash);
85 } 90 }
86 c->calc_idx_sz += ALIGN(len, 8); 91 c->calc_idx_sz += ALIGN(len, 8);
87 92
@@ -647,6 +652,8 @@ static int get_znodes_to_commit(struct ubifs_info *c)
647 znode->cnext = c->cnext; 652 znode->cnext = c->cnext;
648 break; 653 break;
649 } 654 }
655 znode->cparent = znode->parent;
656 znode->ciip = znode->iip;
650 znode->cnext = cnext; 657 znode->cnext = cnext;
651 znode = cnext; 658 znode = cnext;
652 cnt += 1; 659 cnt += 1;
@@ -840,6 +847,8 @@ static int write_index(struct ubifs_info *c)
840 } 847 }
841 848
842 while (1) { 849 while (1) {
850 u8 hash[UBIFS_HASH_ARR_SZ];
851
843 cond_resched(); 852 cond_resched();
844 853
845 znode = cnext; 854 znode = cnext;
@@ -857,6 +866,7 @@ static int write_index(struct ubifs_info *c)
857 br->lnum = cpu_to_le32(zbr->lnum); 866 br->lnum = cpu_to_le32(zbr->lnum);
858 br->offs = cpu_to_le32(zbr->offs); 867 br->offs = cpu_to_le32(zbr->offs);
859 br->len = cpu_to_le32(zbr->len); 868 br->len = cpu_to_le32(zbr->len);
869 ubifs_copy_hash(c, zbr->hash, ubifs_branch_hash(c, br));
860 if (!zbr->lnum || !zbr->len) { 870 if (!zbr->lnum || !zbr->len) {
861 ubifs_err(c, "bad ref in znode"); 871 ubifs_err(c, "bad ref in znode");
862 ubifs_dump_znode(c, znode); 872 ubifs_dump_znode(c, znode);
@@ -868,6 +878,23 @@ static int write_index(struct ubifs_info *c)
868 } 878 }
869 len = ubifs_idx_node_sz(c, znode->child_cnt); 879 len = ubifs_idx_node_sz(c, znode->child_cnt);
870 ubifs_prepare_node(c, idx, len, 0); 880 ubifs_prepare_node(c, idx, len, 0);
881 ubifs_node_calc_hash(c, idx, hash);
882
883 mutex_lock(&c->tnc_mutex);
884
885 if (znode->cparent)
886 ubifs_copy_hash(c, hash,
887 znode->cparent->zbranch[znode->ciip].hash);
888
889 if (znode->parent) {
890 if (!ubifs_zn_obsolete(znode))
891 ubifs_copy_hash(c, hash,
892 znode->parent->zbranch[znode->iip].hash);
893 } else {
894 ubifs_copy_hash(c, hash, c->zroot.hash);
895 }
896
897 mutex_unlock(&c->tnc_mutex);
871 898
872 /* Determine the index node position */ 899 /* Determine the index node position */
873 if (lnum == -1) { 900 if (lnum == -1) {
diff --git a/fs/ubifs/tnc_misc.c b/fs/ubifs/tnc_misc.c
index 6ce75999f273..d1815e959007 100644
--- a/fs/ubifs/tnc_misc.c
+++ b/fs/ubifs/tnc_misc.c
@@ -293,6 +293,12 @@ static int read_znode(struct ubifs_info *c, struct ubifs_zbranch *zzbr,
293 return err; 293 return err;
294 } 294 }
295 295
296 err = ubifs_node_check_hash(c, idx, zzbr->hash);
297 if (err) {
298 ubifs_bad_hash(c, idx, zzbr->hash, lnum, offs);
299 return err;
300 }
301
296 znode->child_cnt = le16_to_cpu(idx->child_cnt); 302 znode->child_cnt = le16_to_cpu(idx->child_cnt);
297 znode->level = le16_to_cpu(idx->level); 303 znode->level = le16_to_cpu(idx->level);
298 304
@@ -309,13 +315,14 @@ static int read_znode(struct ubifs_info *c, struct ubifs_zbranch *zzbr,
309 } 315 }
310 316
311 for (i = 0; i < znode->child_cnt; i++) { 317 for (i = 0; i < znode->child_cnt; i++) {
312 const struct ubifs_branch *br = ubifs_idx_branch(c, idx, i); 318 struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
313 struct ubifs_zbranch *zbr = &znode->zbranch[i]; 319 struct ubifs_zbranch *zbr = &znode->zbranch[i];
314 320
315 key_read(c, &br->key, &zbr->key); 321 key_read(c, &br->key, &zbr->key);
316 zbr->lnum = le32_to_cpu(br->lnum); 322 zbr->lnum = le32_to_cpu(br->lnum);
317 zbr->offs = le32_to_cpu(br->offs); 323 zbr->offs = le32_to_cpu(br->offs);
318 zbr->len = le32_to_cpu(br->len); 324 zbr->len = le32_to_cpu(br->len);
325 ubifs_copy_hash(c, ubifs_branch_hash(c, br), zbr->hash);
319 zbr->znode = NULL; 326 zbr->znode = NULL;
320 327
321 /* Validate branch */ 328 /* Validate branch */
@@ -497,5 +504,11 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
497 return -EINVAL; 504 return -EINVAL;
498 } 505 }
499 506
507 err = ubifs_node_check_hash(c, node, zbr->hash);
508 if (err) {
509 ubifs_bad_hash(c, node, zbr->hash, zbr->lnum, zbr->offs);
510 return err;
511 }
512
500 return 0; 513 return 0;
501} 514}
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index a7e423347e6d..67bfd58d28d4 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -765,6 +765,8 @@ struct ubifs_zbranch {
765 * struct ubifs_znode - in-memory representation of an indexing node. 765 * struct ubifs_znode - in-memory representation of an indexing node.
766 * @parent: parent znode or NULL if it is the root 766 * @parent: parent znode or NULL if it is the root
767 * @cnext: next znode to commit 767 * @cnext: next znode to commit
768 * @cparent: parent node for this commit
769 * @ciip: index in cparent's zbranch array
768 * @flags: znode flags (%DIRTY_ZNODE, %COW_ZNODE or %OBSOLETE_ZNODE) 770 * @flags: znode flags (%DIRTY_ZNODE, %COW_ZNODE or %OBSOLETE_ZNODE)
769 * @time: last access time (seconds) 771 * @time: last access time (seconds)
770 * @level: level of the entry in the TNC tree 772 * @level: level of the entry in the TNC tree
@@ -782,6 +784,8 @@ struct ubifs_zbranch {
782struct ubifs_znode { 784struct ubifs_znode {
783 struct ubifs_znode *parent; 785 struct ubifs_znode *parent;
784 struct ubifs_znode *cnext; 786 struct ubifs_znode *cnext;
787 struct ubifs_znode *cparent;
788 int ciip;
785 unsigned long flags; 789 unsigned long flags;
786 time64_t time; 790 time64_t time;
787 int level; 791 int level;