Skip to content

Commit 16a26b2

Browse files
saschahauerrichardweinberger
authored andcommitted
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>
1 parent 823838a commit 16a26b2

File tree

7 files changed

+81
-14
lines changed

7 files changed

+81
-14
lines changed

fs/ubifs/master.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,8 @@ int ubifs_read_master(struct ubifs_info *c)
305305
c->lst.total_dead = le64_to_cpu(c->mst_node->total_dead);
306306
c->lst.total_dark = le64_to_cpu(c->mst_node->total_dark);
307307

308+
ubifs_copy_hash(c, c->mst_node->hash_root_idx, c->zroot.hash);
309+
308310
c->calc_idx_sz = c->bi.old_idx_sz;
309311

310312
if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS))
@@ -378,6 +380,7 @@ int ubifs_write_master(struct ubifs_info *c)
378380
c->mst_offs = offs;
379381
c->mst_node->highest_inum = cpu_to_le64(c->highest_inum);
380382

383+
ubifs_copy_hash(c, c->zroot.hash, c->mst_node->hash_root_idx);
381384
err = ubifs_write_node(c, c->mst_node, len, lnum, offs);
382385
if (err)
383386
return err;

fs/ubifs/misc.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ static inline int ubifs_return_leb(struct ubifs_info *c, int lnum)
197197
*/
198198
static inline int ubifs_idx_node_sz(const struct ubifs_info *c, int child_cnt)
199199
{
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;
201202
}
202203

203204
/**
@@ -212,7 +213,7 @@ struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c,
212213
int bnum)
213214
{
214215
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);
216217
}
217218

218219
/**

fs/ubifs/replay.c

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ struct replay_entry {
5656
int lnum;
5757
int offs;
5858
int len;
59+
u8 hash[UBIFS_HASH_ARR_SZ];
5960
unsigned int deletion:1;
6061
unsigned long long sqnum;
6162
struct list_head list;
@@ -228,7 +229,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
228229
err = ubifs_tnc_remove_nm(c, &r->key, &r->nm);
229230
else
230231
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);
232233
} else {
233234
if (r->deletion)
234235
switch (key_type(c, &r->key)) {
@@ -248,7 +249,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
248249
}
249250
else
250251
err = ubifs_tnc_add(c, &r->key, r->lnum, r->offs,
251-
r->len, NULL);
252+
r->len, r->hash);
252253
if (err)
253254
return err;
254255

@@ -352,9 +353,9 @@ static void destroy_replay_list(struct ubifs_info *c)
352353
* in case of success and a negative error code in case of failure.
353354
*/
354355
static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
355-
union ubifs_key *key, unsigned long long sqnum,
356-
int deletion, int *used, loff_t old_size,
357-
loff_t new_size)
356+
const u8 *hash, union ubifs_key *key,
357+
unsigned long long sqnum, int deletion, int *used,
358+
loff_t old_size, loff_t new_size)
358359
{
359360
struct replay_entry *r;
360361

@@ -372,6 +373,7 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
372373
r->lnum = lnum;
373374
r->offs = offs;
374375
r->len = len;
376+
ubifs_copy_hash(c, hash, r->hash);
375377
r->deletion = !!deletion;
376378
r->sqnum = sqnum;
377379
key_copy(c, key, &r->key);
@@ -400,8 +402,9 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len,
400402
* negative error code in case of failure.
401403
*/
402404
static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
403-
union ubifs_key *key, const char *name, int nlen,
404-
unsigned long long sqnum, int deletion, int *used)
405+
const u8 *hash, union ubifs_key *key,
406+
const char *name, int nlen, unsigned long long sqnum,
407+
int deletion, int *used)
405408
{
406409
struct replay_entry *r;
407410
char *nbuf;
@@ -425,6 +428,7 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
425428
r->lnum = lnum;
426429
r->offs = offs;
427430
r->len = len;
431+
ubifs_copy_hash(c, hash, r->hash);
428432
r->deletion = !!deletion;
429433
r->sqnum = sqnum;
430434
key_copy(c, key, &r->key);
@@ -582,6 +586,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
582586
*/
583587

584588
list_for_each_entry(snod, &sleb->nodes, list) {
589+
u8 hash[UBIFS_HASH_ARR_SZ];
585590
int deletion = 0;
586591

587592
cond_resched();
@@ -591,6 +596,8 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
591596
goto out_dump;
592597
}
593598

599+
ubifs_node_calc_hash(c, snod->node, hash);
600+
594601
if (snod->sqnum > c->max_sqnum)
595602
c->max_sqnum = snod->sqnum;
596603

@@ -602,7 +609,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
602609

603610
if (le32_to_cpu(ino->nlink) == 0)
604611
deletion = 1;
605-
err = insert_node(c, lnum, snod->offs, snod->len,
612+
err = insert_node(c, lnum, snod->offs, snod->len, hash,
606613
&snod->key, snod->sqnum, deletion,
607614
&used, 0, new_size);
608615
break;
@@ -614,7 +621,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
614621
key_block(c, &snod->key) *
615622
UBIFS_BLOCK_SIZE;
616623

617-
err = insert_node(c, lnum, snod->offs, snod->len,
624+
err = insert_node(c, lnum, snod->offs, snod->len, hash,
618625
&snod->key, snod->sqnum, deletion,
619626
&used, 0, new_size);
620627
break;
@@ -628,7 +635,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
628635
if (err)
629636
goto out_dump;
630637

631-
err = insert_dent(c, lnum, snod->offs, snod->len,
638+
err = insert_dent(c, lnum, snod->offs, snod->len, hash,
632639
&snod->key, dent->name,
633640
le16_to_cpu(dent->nlen), snod->sqnum,
634641
!le64_to_cpu(dent->inum), &used);
@@ -654,7 +661,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
654661
* functions which expect nodes to have keys.
655662
*/
656663
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,
658665
&key, snod->sqnum, 1, &used,
659666
old_size, new_size);
660667
break;

fs/ubifs/tnc.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,12 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type,
488488
if (crc != node_crc)
489489
return 0;
490490

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+
491497
return 1;
492498
}
493499

@@ -1713,6 +1719,12 @@ static int validate_data_node(struct ubifs_info *c, void *buf,
17131719
goto out;
17141720
}
17151721

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+
17161728
len = le32_to_cpu(ch->len);
17171729
if (len != zbr->len) {
17181730
ubifs_err(c, "bad node length %d, expected %d", len, zbr->len);

fs/ubifs/tnc_commit.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
3838
struct ubifs_znode *znode, int lnum, int offs, int len)
3939
{
4040
struct ubifs_znode *zp;
41+
u8 hash[UBIFS_HASH_ARR_SZ];
4142
int i, err;
4243

4344
/* Make index node */
@@ -52,6 +53,7 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
5253
br->lnum = cpu_to_le32(zbr->lnum);
5354
br->offs = cpu_to_le32(zbr->offs);
5455
br->len = cpu_to_le32(zbr->len);
56+
ubifs_copy_hash(c, zbr->hash, ubifs_branch_hash(c, br));
5557
if (!zbr->lnum || !zbr->len) {
5658
ubifs_err(c, "bad ref in znode");
5759
ubifs_dump_znode(c, znode);
@@ -62,6 +64,7 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
6264
}
6365
}
6466
ubifs_prepare_node(c, idx, len, 0);
67+
ubifs_node_calc_hash(c, idx, hash);
6568

6669
znode->lnum = lnum;
6770
znode->offs = offs;
@@ -78,10 +81,12 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
7881
zbr->lnum = lnum;
7982
zbr->offs = offs;
8083
zbr->len = len;
84+
ubifs_copy_hash(c, hash, zbr->hash);
8185
} else {
8286
c->zroot.lnum = lnum;
8387
c->zroot.offs = offs;
8488
c->zroot.len = len;
89+
ubifs_copy_hash(c, hash, c->zroot.hash);
8590
}
8691
c->calc_idx_sz += ALIGN(len, 8);
8792

@@ -647,6 +652,8 @@ static int get_znodes_to_commit(struct ubifs_info *c)
647652
znode->cnext = c->cnext;
648653
break;
649654
}
655+
znode->cparent = znode->parent;
656+
znode->ciip = znode->iip;
650657
znode->cnext = cnext;
651658
znode = cnext;
652659
cnt += 1;
@@ -840,6 +847,8 @@ static int write_index(struct ubifs_info *c)
840847
}
841848

842849
while (1) {
850+
u8 hash[UBIFS_HASH_ARR_SZ];
851+
843852
cond_resched();
844853

845854
znode = cnext;
@@ -857,6 +866,7 @@ static int write_index(struct ubifs_info *c)
857866
br->lnum = cpu_to_le32(zbr->lnum);
858867
br->offs = cpu_to_le32(zbr->offs);
859868
br->len = cpu_to_le32(zbr->len);
869+
ubifs_copy_hash(c, zbr->hash, ubifs_branch_hash(c, br));
860870
if (!zbr->lnum || !zbr->len) {
861871
ubifs_err(c, "bad ref in znode");
862872
ubifs_dump_znode(c, znode);
@@ -868,6 +878,23 @@ static int write_index(struct ubifs_info *c)
868878
}
869879
len = ubifs_idx_node_sz(c, znode->child_cnt);
870880
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);
871898

872899
/* Determine the index node position */
873900
if (lnum == -1) {

fs/ubifs/tnc_misc.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,12 @@ static int read_znode(struct ubifs_info *c, struct ubifs_zbranch *zzbr,
293293
return err;
294294
}
295295

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+
296302
znode->child_cnt = le16_to_cpu(idx->child_cnt);
297303
znode->level = le16_to_cpu(idx->level);
298304

@@ -309,13 +315,14 @@ static int read_znode(struct ubifs_info *c, struct ubifs_zbranch *zzbr,
309315
}
310316

311317
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);
313319
struct ubifs_zbranch *zbr = &znode->zbranch[i];
314320

315321
key_read(c, &br->key, &zbr->key);
316322
zbr->lnum = le32_to_cpu(br->lnum);
317323
zbr->offs = le32_to_cpu(br->offs);
318324
zbr->len = le32_to_cpu(br->len);
325+
ubifs_copy_hash(c, ubifs_branch_hash(c, br), zbr->hash);
319326
zbr->znode = NULL;
320327

321328
/* Validate branch */
@@ -497,5 +504,11 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
497504
return -EINVAL;
498505
}
499506

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+
500513
return 0;
501514
}

fs/ubifs/ubifs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,8 @@ struct ubifs_zbranch {
765765
* struct ubifs_znode - in-memory representation of an indexing node.
766766
* @parent: parent znode or NULL if it is the root
767767
* @cnext: next znode to commit
768+
* @cparent: parent node for this commit
769+
* @ciip: index in cparent's zbranch array
768770
* @flags: znode flags (%DIRTY_ZNODE, %COW_ZNODE or %OBSOLETE_ZNODE)
769771
* @time: last access time (seconds)
770772
* @level: level of the entry in the TNC tree
@@ -782,6 +784,8 @@ struct ubifs_zbranch {
782784
struct ubifs_znode {
783785
struct ubifs_znode *parent;
784786
struct ubifs_znode *cnext;
787+
struct ubifs_znode *cparent;
788+
int ciip;
785789
unsigned long flags;
786790
time64_t time;
787791
int level;

0 commit comments

Comments
 (0)