34
34
35
35
#include "ubifs.h"
36
36
#include <linux/list_sort.h>
37
+ #include <crypto/hash.h>
38
+ #include <crypto/algapi.h>
37
39
38
40
/**
39
41
* struct replay_entry - replay list entry.
@@ -531,6 +533,105 @@ static int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud)
531
533
return data == 0xFFFFFFFF ;
532
534
}
533
535
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
+ */
552
+ static 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
+ }
628
+ out :
629
+ kfree (hash );
630
+ kfree (hmac );
631
+
632
+ return err ? err : n_nodes - n_not_auth ;
633
+ }
634
+
534
635
/**
535
636
* replay_bud - replay a bud logical eraseblock.
536
637
* @c: UBIFS file-system description object
@@ -544,6 +645,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
544
645
{
545
646
int is_last = is_last_bud (c , b -> bud );
546
647
int err = 0 , used = 0 , lnum = b -> bud -> lnum , offs = b -> bud -> start ;
648
+ int n_nodes , n = 0 ;
547
649
struct ubifs_scan_leb * sleb ;
548
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
665
if (IS_ERR (sleb ))
564
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
678
* The bud does not have to start from offset zero - the beginning of
568
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
788
if (err )
678
789
goto out ;
790
+
791
+ n ++ ;
792
+ if (n == n_nodes )
793
+ break ;
679
794
}
680
795
681
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
870
struct ubifs_bud * bud ;
756
871
struct bud_entry * b ;
872
+ int err ;
757
873
758
874
dbg_mnt ("add replay bud LEB %d:%d, head %d" , lnum , offs , jhead );
759
875
@@ -763,20 +879,33 @@ static int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead,
763
879
764
880
b = kmalloc (sizeof (struct bud_entry ), GFP_KERNEL );
765
881
if (!b ) {
766
- kfree ( bud ) ;
767
- return - ENOMEM ;
882
+ err = - ENOMEM ;
883
+ goto out ;
768
884
}
769
885
770
886
bud -> lnum = lnum ;
771
887
bud -> start = offs ;
772
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
897
ubifs_add_bud (c , bud );
774
898
775
899
b -> bud = bud ;
776
900
b -> sqnum = sqnum ;
777
901
list_add_tail (& b -> list , & c -> replay_buds );
778
902
779
903
return 0 ;
904
+ out :
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
1012
c -> cs_sqnum = le64_to_cpu (node -> ch .sqnum );
884
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
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
1066
if (err )
930
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
1074
err = add_replay_bud (c , le32_to_cpu (ref -> lnum ),
933
1075
le32_to_cpu (ref -> offs ),
934
1076
le32_to_cpu (ref -> jhead ),
0 commit comments