aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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),