Skip to content

Commit 6a98bc4

Browse files
saschahauerrichardweinberger
authored andcommitted
ubifs: Add authentication nodes to journal
Nodes that are written to flash can only be authenticated through the index after the next commit. When a journal replay is necessary the nodes are not yet referenced by the index and thus can't be authenticated. This patch overcomes this situation by creating a hash over all nodes beginning from the commit start node over the reference node(s) and the buds themselves. From time to time we insert authentication nodes. Authentication nodes contain a HMAC from the current hash state, so that they can be used to authenticate a journal replay up to the point where the authentication node is. The hash is continued afterwards so that theoretically we would only have to check the HMAC of the last authentication node we find. Overall we get this picture: ,,,,,,,, ,......,........................................... ,. CS , hash1.----. hash2.----. ,. | , . |hmac . |hmac ,. v , . v . v ,.REF#0,-> bud -> bud -> bud.-> auth -> bud -> bud.-> auth ... ,..|...,........................................... , | , , | ,,,,,,,,,,,,,,, . | hash3,----. , | , |hmac , v , v , REF#1 -> bud -> bud,-> auth ... ,,,|,,,,,,,,,,,,,,,,,, v REF#2 -> ... | V ... Note how hash3 covers CS, REF#0 and REF#1 so that it is not possible to exchange or skip any reference nodes. Unlike the picture suggests the auth nodes themselves are not hashed. With this it is possible for an offline attacker to cut each journal head or to drop the last reference node(s), but not to skip any journal heads or to reorder any operations. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Richard Weinberger <richard@nod.at>
1 parent 16a26b2 commit 6a98bc4

File tree

6 files changed

+153
-18
lines changed

6 files changed

+153
-18
lines changed

fs/ubifs/gc.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,8 @@ static int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
254254
snod->type == UBIFS_DATA_NODE ||
255255
snod->type == UBIFS_DENT_NODE ||
256256
snod->type == UBIFS_XENT_NODE ||
257-
snod->type == UBIFS_TRUN_NODE);
257+
snod->type == UBIFS_TRUN_NODE ||
258+
snod->type == UBIFS_AUTH_NODE);
258259

259260
if (snod->type != UBIFS_INO_NODE &&
260261
snod->type != UBIFS_DATA_NODE &&

fs/ubifs/journal.c

Lines changed: 107 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ static inline void zero_trun_node_unused(struct ubifs_trun_node *trun)
9090
memset(trun->padding, 0, 12);
9191
}
9292

93+
static void ubifs_add_auth_dirt(struct ubifs_info *c, int lnum)
94+
{
95+
if (ubifs_authenticated(c))
96+
ubifs_add_dirt(c, lnum, ubifs_auth_node_sz(c));
97+
}
98+
9399
/**
94100
* reserve_space - reserve space in the journal.
95101
* @c: UBIFS file-system description object
@@ -228,6 +234,35 @@ static int reserve_space(struct ubifs_info *c, int jhead, int len)
228234
return err;
229235
}
230236

237+
static int ubifs_hash_nodes(struct ubifs_info *c, void *node,
238+
int len, struct shash_desc *hash)
239+
{
240+
int auth_node_size = ubifs_auth_node_sz(c);
241+
int err;
242+
243+
while (1) {
244+
const struct ubifs_ch *ch = node;
245+
int nodelen = le32_to_cpu(ch->len);
246+
247+
ubifs_assert(c, len >= auth_node_size);
248+
249+
if (len == auth_node_size)
250+
break;
251+
252+
ubifs_assert(c, len > nodelen);
253+
ubifs_assert(c, ch->magic == cpu_to_le32(UBIFS_NODE_MAGIC));
254+
255+
err = ubifs_shash_update(c, hash, (void *)node, nodelen);
256+
if (err)
257+
return err;
258+
259+
node += ALIGN(nodelen, 8);
260+
len -= ALIGN(nodelen, 8);
261+
}
262+
263+
return ubifs_prepare_auth_node(c, node, hash);
264+
}
265+
231266
/**
232267
* write_head - write data to a journal head.
233268
* @c: UBIFS file-system description object
@@ -255,6 +290,12 @@ static int write_head(struct ubifs_info *c, int jhead, void *buf, int len,
255290
dbg_jnl("jhead %s, LEB %d:%d, len %d",
256291
dbg_jhead(jhead), *lnum, *offs, len);
257292

293+
if (ubifs_authenticated(c)) {
294+
err = ubifs_hash_nodes(c, buf, len, c->jheads[jhead].log_hash);
295+
if (err)
296+
return err;
297+
}
298+
258299
err = ubifs_wbuf_write_nolock(wbuf, buf, len);
259300
if (err)
260301
return err;
@@ -543,7 +584,10 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
543584

544585
len = aligned_dlen + aligned_ilen + UBIFS_INO_NODE_SZ;
545586
/* Make sure to also account for extended attributes */
546-
len += host_ui->data_len;
587+
if (ubifs_authenticated(c))
588+
len += ALIGN(host_ui->data_len, 8) + ubifs_auth_node_sz(c);
589+
else
590+
len += host_ui->data_len;
547591

548592
dent = kzalloc(len, GFP_NOFS);
549593
if (!dent)
@@ -611,6 +655,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
611655
}
612656
release_head(c, BASEHD);
613657
kfree(dent);
658+
ubifs_add_auth_dirt(c, lnum);
614659

615660
if (deletion) {
616661
if (nm->hash)
@@ -690,8 +735,9 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
690735
const union ubifs_key *key, const void *buf, int len)
691736
{
692737
struct ubifs_data_node *data;
693-
int err, lnum, offs, compr_type, out_len, compr_len;
738+
int err, lnum, offs, compr_type, out_len, compr_len, auth_len;
694739
int dlen = COMPRESSED_DATA_NODE_BUF_SZ, allocated = 1;
740+
int write_len;
695741
struct ubifs_inode *ui = ubifs_inode(inode);
696742
bool encrypted = ubifs_crypt_is_encrypted(inode);
697743
u8 hash[UBIFS_HASH_ARR_SZ];
@@ -703,7 +749,9 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
703749
if (encrypted)
704750
dlen += UBIFS_CIPHER_BLOCK_SIZE;
705751

706-
data = kmalloc(dlen, GFP_NOFS | __GFP_NOWARN);
752+
auth_len = ubifs_auth_node_sz(c);
753+
754+
data = kmalloc(dlen + auth_len, GFP_NOFS | __GFP_NOWARN);
707755
if (!data) {
708756
/*
709757
* Fall-back to the write reserve buffer. Note, we might be
@@ -742,15 +790,20 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
742790
}
743791

744792
dlen = UBIFS_DATA_NODE_SZ + out_len;
793+
if (ubifs_authenticated(c))
794+
write_len = ALIGN(dlen, 8) + auth_len;
795+
else
796+
write_len = dlen;
797+
745798
data->compr_type = cpu_to_le16(compr_type);
746799

747800
/* Make reservation before allocating sequence numbers */
748-
err = make_reservation(c, DATAHD, dlen);
801+
err = make_reservation(c, DATAHD, write_len);
749802
if (err)
750803
goto out_free;
751804

752805
ubifs_prepare_node(c, data, dlen, 0);
753-
err = write_head(c, DATAHD, data, dlen, &lnum, &offs, 0);
806+
err = write_head(c, DATAHD, data, write_len, &lnum, &offs, 0);
754807
if (err)
755808
goto out_release;
756809

@@ -761,6 +814,8 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
761814
ubifs_wbuf_add_ino_nolock(&c->jheads[DATAHD].wbuf, key_inum(c, key));
762815
release_head(c, DATAHD);
763816

817+
ubifs_add_auth_dirt(c, lnum);
818+
764819
err = ubifs_tnc_add(c, key, lnum, offs, dlen, hash);
765820
if (err)
766821
goto out_ro;
@@ -799,7 +854,8 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
799854
int err, lnum, offs;
800855
struct ubifs_ino_node *ino;
801856
struct ubifs_inode *ui = ubifs_inode(inode);
802-
int sync = 0, len = UBIFS_INO_NODE_SZ, last_reference = !inode->i_nlink;
857+
int sync = 0, write_len, ilen = UBIFS_INO_NODE_SZ;
858+
int last_reference = !inode->i_nlink;
803859
u8 hash[UBIFS_HASH_ARR_SZ];
804860

805861
dbg_jnl("ino %lu, nlink %u", inode->i_ino, inode->i_nlink);
@@ -809,15 +865,21 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
809865
* need to synchronize the write-buffer either.
810866
*/
811867
if (!last_reference) {
812-
len += ui->data_len;
868+
ilen += ui->data_len;
813869
sync = IS_SYNC(inode);
814870
}
815-
ino = kmalloc(len, GFP_NOFS);
871+
872+
if (ubifs_authenticated(c))
873+
write_len = ALIGN(ilen, 8) + ubifs_auth_node_sz(c);
874+
else
875+
write_len = ilen;
876+
877+
ino = kmalloc(write_len, GFP_NOFS);
816878
if (!ino)
817879
return -ENOMEM;
818880

819881
/* Make reservation before allocating sequence numbers */
820-
err = make_reservation(c, BASEHD, len);
882+
err = make_reservation(c, BASEHD, write_len);
821883
if (err)
822884
goto out_free;
823885

@@ -826,25 +888,27 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode)
826888
if (err)
827889
goto out_release;
828890

829-
err = write_head(c, BASEHD, ino, len, &lnum, &offs, sync);
891+
err = write_head(c, BASEHD, ino, write_len, &lnum, &offs, sync);
830892
if (err)
831893
goto out_release;
832894
if (!sync)
833895
ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf,
834896
inode->i_ino);
835897
release_head(c, BASEHD);
836898

899+
ubifs_add_auth_dirt(c, lnum);
900+
837901
if (last_reference) {
838902
err = ubifs_tnc_remove_ino(c, inode->i_ino);
839903
if (err)
840904
goto out_ro;
841905
ubifs_delete_orphan(c, inode->i_ino);
842-
err = ubifs_add_dirt(c, lnum, len);
906+
err = ubifs_add_dirt(c, lnum, ilen);
843907
} else {
844908
union ubifs_key key;
845909

846910
ino_key_init(c, &key, inode->i_ino);
847-
err = ubifs_tnc_add(c, &key, lnum, offs, len, hash);
911+
err = ubifs_tnc_add(c, &key, lnum, offs, ilen, hash);
848912
}
849913
if (err)
850914
goto out_ro;
@@ -973,6 +1037,8 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
9731037
if (twoparents)
9741038
len += plen;
9751039

1040+
len += ubifs_auth_node_sz(c);
1041+
9761042
dent1 = kzalloc(len, GFP_NOFS);
9771043
if (!dent1)
9781044
return -ENOMEM;
@@ -1042,6 +1108,8 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
10421108
}
10431109
release_head(c, BASEHD);
10441110

1111+
ubifs_add_auth_dirt(c, lnum);
1112+
10451113
dent_key_init(c, &key, snd_dir->i_ino, snd_nm);
10461114
err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, hash_dent1, snd_nm);
10471115
if (err)
@@ -1143,6 +1211,9 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
11431211
len = aligned_dlen1 + aligned_dlen2 + ALIGN(ilen, 8) + ALIGN(plen, 8);
11441212
if (move)
11451213
len += plen;
1214+
1215+
len += ubifs_auth_node_sz(c);
1216+
11461217
dent = kzalloc(len, GFP_NOFS);
11471218
if (!dent)
11481219
return -ENOMEM;
@@ -1240,6 +1311,8 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
12401311
}
12411312
release_head(c, BASEHD);
12421313

1314+
ubifs_add_auth_dirt(c, lnum);
1315+
12431316
dent_key_init(c, &key, new_dir->i_ino, new_nm);
12441317
err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, hash_dent1, new_nm);
12451318
if (err)
@@ -1411,6 +1484,9 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
14111484

14121485
sz = UBIFS_TRUN_NODE_SZ + UBIFS_INO_NODE_SZ +
14131486
UBIFS_MAX_DATA_NODE_SZ * WORST_COMPR_FACTOR;
1487+
1488+
sz += ubifs_auth_node_sz(c);
1489+
14141490
ino = kmalloc(sz, GFP_NOFS);
14151491
if (!ino)
14161492
return -ENOMEM;
@@ -1456,8 +1532,12 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
14561532

14571533
/* Must make reservation before allocating sequence numbers */
14581534
len = UBIFS_TRUN_NODE_SZ + UBIFS_INO_NODE_SZ;
1459-
if (dlen)
1535+
1536+
if (ubifs_authenticated(c))
1537+
len += ALIGN(dlen, 8) + ubifs_auth_node_sz(c);
1538+
else
14601539
len += dlen;
1540+
14611541
err = make_reservation(c, BASEHD, len);
14621542
if (err)
14631543
goto out_free;
@@ -1482,6 +1562,8 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
14821562
ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, inum);
14831563
release_head(c, BASEHD);
14841564

1565+
ubifs_add_auth_dirt(c, lnum);
1566+
14851567
if (dlen) {
14861568
sz = offs + UBIFS_INO_NODE_SZ + UBIFS_TRUN_NODE_SZ;
14871569
err = ubifs_tnc_add(c, &key, lnum, sz, dlen, hash_dn);
@@ -1545,7 +1627,7 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
15451627
const struct inode *inode,
15461628
const struct fscrypt_name *nm)
15471629
{
1548-
int err, xlen, hlen, len, lnum, xent_offs, aligned_xlen;
1630+
int err, xlen, hlen, len, lnum, xent_offs, aligned_xlen, write_len;
15491631
struct ubifs_dent_node *xent;
15501632
struct ubifs_ino_node *ino;
15511633
union ubifs_key xent_key, key1, key2;
@@ -1565,12 +1647,14 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
15651647
hlen = host_ui->data_len + UBIFS_INO_NODE_SZ;
15661648
len = aligned_xlen + UBIFS_INO_NODE_SZ + ALIGN(hlen, 8);
15671649

1568-
xent = kzalloc(len, GFP_NOFS);
1650+
write_len = len + ubifs_auth_node_sz(c);
1651+
1652+
xent = kzalloc(write_len, GFP_NOFS);
15691653
if (!xent)
15701654
return -ENOMEM;
15711655

15721656
/* Make reservation before allocating sequence numbers */
1573-
err = make_reservation(c, BASEHD, len);
1657+
err = make_reservation(c, BASEHD, write_len);
15741658
if (err) {
15751659
kfree(xent);
15761660
return err;
@@ -1595,10 +1679,12 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
15951679
if (err)
15961680
goto out_release;
15971681

1598-
err = write_head(c, BASEHD, xent, len, &lnum, &xent_offs, sync);
1682+
err = write_head(c, BASEHD, xent, write_len, &lnum, &xent_offs, sync);
15991683
if (!sync && !err)
16001684
ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, host->i_ino);
16011685
release_head(c, BASEHD);
1686+
1687+
ubifs_add_auth_dirt(c, lnum);
16021688
kfree(xent);
16031689
if (err)
16041690
goto out_ro;
@@ -1680,6 +1766,8 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode,
16801766
aligned_len1 = ALIGN(len1, 8);
16811767
aligned_len = aligned_len1 + ALIGN(len2, 8);
16821768

1769+
aligned_len += ubifs_auth_node_sz(c);
1770+
16831771
ino = kzalloc(aligned_len, GFP_NOFS);
16841772
if (!ino)
16851773
return -ENOMEM;
@@ -1709,6 +1797,8 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode,
17091797
if (err)
17101798
goto out_ro;
17111799

1800+
ubifs_add_auth_dirt(c, lnum);
1801+
17121802
ino_key_init(c, &key, host->i_ino);
17131803
err = ubifs_tnc_add(c, &key, lnum, offs, len1, hash_host);
17141804
if (err)

fs/ubifs/log.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
236236
bud->lnum = lnum;
237237
bud->start = offs;
238238
bud->jhead = jhead;
239+
bud->log_hash = NULL;
239240

240241
ref->ch.node_type = UBIFS_REF_NODE;
241242
ref->lnum = cpu_to_le32(bud->lnum);
@@ -275,6 +276,14 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
275276
if (err)
276277
goto out_unlock;
277278

279+
err = ubifs_shash_update(c, c->log_hash, ref, UBIFS_REF_NODE_SZ);
280+
if (err)
281+
goto out_unlock;
282+
283+
err = ubifs_shash_copy_state(c, c->log_hash, c->jheads[jhead].log_hash);
284+
if (err)
285+
goto out_unlock;
286+
278287
c->lhead_offs += c->ref_node_alsz;
279288

280289
ubifs_add_bud(c, bud);
@@ -377,6 +386,14 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
377386
cs->cmt_no = cpu_to_le64(c->cmt_no);
378387
ubifs_prepare_node(c, cs, UBIFS_CS_NODE_SZ, 0);
379388

389+
err = ubifs_shash_init(c, c->log_hash);
390+
if (err)
391+
goto out;
392+
393+
err = ubifs_shash_update(c, c->log_hash, cs, UBIFS_CS_NODE_SZ);
394+
if (err < 0)
395+
goto out;
396+
380397
/*
381398
* Note, we do not lock 'c->log_mutex' because this is the commit start
382399
* phase and we are exclusively using the log. And we do not lock
@@ -402,6 +419,12 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
402419

403420
ubifs_prepare_node(c, ref, UBIFS_REF_NODE_SZ, 0);
404421
len += UBIFS_REF_NODE_SZ;
422+
423+
err = ubifs_shash_update(c, c->log_hash, ref,
424+
UBIFS_REF_NODE_SZ);
425+
if (err)
426+
goto out;
427+
ubifs_shash_copy_state(c, c->log_hash, c->jheads[i].log_hash);
405428
}
406429

407430
ubifs_pad(c, buf + len, ALIGN(len, c->min_io_size) - len);
@@ -516,6 +539,7 @@ int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum)
516539
if (err)
517540
return err;
518541
list_del(&bud->list);
542+
kfree(bud->log_hash);
519543
kfree(bud);
520544
}
521545
mutex_lock(&c->log_mutex);

0 commit comments

Comments
 (0)