aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2018-09-07 08:36:38 -0400
committerRichard Weinberger <richard@nod.at>2018-10-23 07:48:40 -0400
commitda8ef65f9573952c717d86f8f501773daf29bd10 (patch)
treeebe8f65efa5e149eca12d592b6aa1591bfddeb17
parent6f06d96fdf624be3e1d65c6100704a1fd79a30b7 (diff)
ubifs: Authenticate replayed journal
Make sure that during replay all buds can be authenticated. To do this we calculate the hash chain until we find an authentication node and check the HMAC in that node against the current status of the hash chain. After a power cut it can happen that some nodes have been written, but not yet the authentication node for them. These nodes have to be discarded during replay. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Richard Weinberger <richard@nod.at>
-rw-r--r--fs/ubifs/replay.c146
1 files changed, 144 insertions, 2 deletions
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index db489d93439c..75f961c4c044 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -34,6 +34,8 @@
34 34
35#include "ubifs.h" 35#include "ubifs.h"
36#include <linux/list_sort.h> 36#include <linux/list_sort.h>
37#include <crypto/hash.h>
38#include <crypto/algapi.h>
37 39
38/** 40/**
39 * struct replay_entry - replay list entry. 41 * struct replay_entry - replay list entry.
@@ -532,6 +534,105 @@ static int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud)
532} 534}
533 535
534/** 536/**
537 * authenticate_sleb - authenticate one scan LEB
538 * @c: UBIFS file-system description object
539 * @sleb: the scan LEB to authenticate
540 * @log_hash:
541 * @is_last: if true, this is is the last LEB
542 *
543 * This function iterates over the buds of a single LEB authenticating all buds
544 * with the authentication nodes on this LEB. Authentication nodes are written
545 * after some buds and contain a HMAC covering the authentication node itself
546 * and the buds between the last authentication node and the current
547 * authentication node. It can happen that the last buds cannot be authenticated
548 * because a powercut happened when some nodes were written but not the
549 * corresponding authentication node. This function returns the number of nodes
550 * that could be authenticated or a negative error code.
551 */
552static int authenticate_sleb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
553 struct shash_desc *log_hash, int is_last)
554{
555 int n_not_auth = 0;
556 struct ubifs_scan_node *snod;
557 int n_nodes = 0;
558 int err;
559 u8 *hash, *hmac;
560
561 if (!ubifs_authenticated(c))
562 return sleb->nodes_cnt;
563
564 hash = kmalloc(crypto_shash_descsize(c->hash_tfm), GFP_NOFS);
565 hmac = kmalloc(c->hmac_desc_len, GFP_NOFS);
566 if (!hash || !hmac) {
567 err = -ENOMEM;
568 goto out;
569 }
570
571 list_for_each_entry(snod, &sleb->nodes, list) {
572
573 n_nodes++;
574
575 if (snod->type == UBIFS_AUTH_NODE) {
576 struct ubifs_auth_node *auth = snod->node;
577 SHASH_DESC_ON_STACK(hash_desc, c->hash_tfm);
578 SHASH_DESC_ON_STACK(hmac_desc, c->hmac_tfm);
579
580 hash_desc->tfm = c->hash_tfm;
581 hash_desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
582
583 ubifs_shash_copy_state(c, log_hash, hash_desc);
584 err = crypto_shash_final(hash_desc, hash);
585 if (err)
586 goto out;
587
588 hmac_desc->tfm = c->hmac_tfm;
589 hmac_desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
590 err = crypto_shash_digest(hmac_desc, hash, c->hash_len,
591 hmac);
592 if (err)
593 goto out;
594
595 err = ubifs_check_hmac(c, auth->hmac, hmac);
596 if (err) {
597 err = -EPERM;
598 goto out;
599 }
600 n_not_auth = 0;
601 } else {
602 err = crypto_shash_update(log_hash, snod->node,
603 snod->len);
604 if (err)
605 goto out;
606 n_not_auth++;
607 }
608 }
609
610 /*
611 * A powercut can happen when some nodes were written, but not yet
612 * the corresponding authentication node. This may only happen on
613 * the last bud though.
614 */
615 if (n_not_auth) {
616 if (is_last) {
617 dbg_mnt("%d unauthenticated nodes found on LEB %d, Ignoring them",
618 n_not_auth, sleb->lnum);
619 err = 0;
620 } else {
621 dbg_mnt("%d unauthenticated nodes found on non-last LEB %d",
622 n_not_auth, sleb->lnum);
623 err = -EPERM;
624 }
625 } else {
626 err = 0;
627 }
628out:
629 kfree(hash);
630 kfree(hmac);
631
632 return err ? err : n_nodes - n_not_auth;
633}
634
635/**
535 * replay_bud - replay a bud logical eraseblock. 636 * replay_bud - replay a bud logical eraseblock.
536 * @c: UBIFS file-system description object 637 * @c: UBIFS file-system description object
537 * @b: bud entry which describes the bud 638 * @b: bud entry which describes the bud
@@ -544,6 +645,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
544{ 645{
545 int is_last = is_last_bud(c, b->bud); 646 int is_last = is_last_bud(c, b->bud);
546 int err = 0, used = 0, lnum = b->bud->lnum, offs = b->bud->start; 647 int err = 0, used = 0, lnum = b->bud->lnum, offs = b->bud->start;
648 int n_nodes, n = 0;
547 struct ubifs_scan_leb *sleb; 649 struct ubifs_scan_leb *sleb;
548 struct ubifs_scan_node *snod; 650 struct ubifs_scan_node *snod;
549 651
@@ -563,6 +665,15 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
563 if (IS_ERR(sleb)) 665 if (IS_ERR(sleb))
564 return PTR_ERR(sleb); 666 return PTR_ERR(sleb);
565 667
668 n_nodes = authenticate_sleb(c, sleb, b->bud->log_hash, is_last);
669 if (n_nodes < 0) {
670 err = n_nodes;
671 goto out;
672 }
673
674 ubifs_shash_copy_state(c, b->bud->log_hash,
675 c->jheads[b->bud->jhead].log_hash);
676
566 /* 677 /*
567 * The bud does not have to start from offset zero - the beginning of 678 * The bud does not have to start from offset zero - the beginning of
568 * the 'lnum' LEB may contain previously committed data. One of the 679 * the 'lnum' LEB may contain previously committed data. One of the
@@ -676,6 +787,10 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
676 } 787 }
677 if (err) 788 if (err)
678 goto out; 789 goto out;
790
791 n++;
792 if (n == n_nodes)
793 break;
679 } 794 }
680 795
681 ubifs_assert(c, ubifs_search_bud(c, lnum)); 796 ubifs_assert(c, ubifs_search_bud(c, lnum));
@@ -754,6 +869,7 @@ static int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
754{ 869{
755 struct ubifs_bud *bud; 870 struct ubifs_bud *bud;
756 struct bud_entry *b; 871 struct bud_entry *b;
872 int err;
757 873
758 dbg_mnt("add replay bud LEB %d:%d, head %d", lnum, offs, jhead); 874 dbg_mnt("add replay bud LEB %d:%d, head %d", lnum, offs, jhead);
759 875
@@ -763,13 +879,21 @@ static int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
763 879
764 b = kmalloc(sizeof(struct bud_entry), GFP_KERNEL); 880 b = kmalloc(sizeof(struct bud_entry), GFP_KERNEL);
765 if (!b) { 881 if (!b) {
766 kfree(bud); 882 err = -ENOMEM;
767 return -ENOMEM; 883 goto out;
768 } 884 }
769 885
770 bud->lnum = lnum; 886 bud->lnum = lnum;
771 bud->start = offs; 887 bud->start = offs;
772 bud->jhead = jhead; 888 bud->jhead = jhead;
889 bud->log_hash = ubifs_hash_get_desc(c);
890 if (IS_ERR(bud->log_hash)) {
891 err = PTR_ERR(bud->log_hash);
892 goto out;
893 }
894
895 ubifs_shash_copy_state(c, c->log_hash, bud->log_hash);
896
773 ubifs_add_bud(c, bud); 897 ubifs_add_bud(c, bud);
774 898
775 b->bud = bud; 899 b->bud = bud;
@@ -777,6 +901,11 @@ static int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
777 list_add_tail(&b->list, &c->replay_buds); 901 list_add_tail(&b->list, &c->replay_buds);
778 902
779 return 0; 903 return 0;
904out:
905 kfree(bud);
906 kfree(b);
907
908 return err;
780} 909}
781 910
782/** 911/**
@@ -882,6 +1011,14 @@ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
882 1011
883 c->cs_sqnum = le64_to_cpu(node->ch.sqnum); 1012 c->cs_sqnum = le64_to_cpu(node->ch.sqnum);
884 dbg_mnt("commit start sqnum %llu", c->cs_sqnum); 1013 dbg_mnt("commit start sqnum %llu", c->cs_sqnum);
1014
1015 err = ubifs_shash_init(c, c->log_hash);
1016 if (err)
1017 goto out;
1018
1019 err = ubifs_shash_update(c, c->log_hash, node, UBIFS_CS_NODE_SZ);
1020 if (err < 0)
1021 goto out;
885 } 1022 }
886 1023
887 if (snod->sqnum < c->cs_sqnum) { 1024 if (snod->sqnum < c->cs_sqnum) {
@@ -929,6 +1066,11 @@ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf)
929 if (err) 1066 if (err)
930 goto out_dump; 1067 goto out_dump;
931 1068
1069 err = ubifs_shash_update(c, c->log_hash, ref,
1070 UBIFS_REF_NODE_SZ);
1071 if (err)
1072 goto out;
1073
932 err = add_replay_bud(c, le32_to_cpu(ref->lnum), 1074 err = add_replay_bud(c, le32_to_cpu(ref->lnum),
933 le32_to_cpu(ref->offs), 1075 le32_to_cpu(ref->offs),
934 le32_to_cpu(ref->jhead), 1076 le32_to_cpu(ref->jhead),