lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:   Tue, 8 Sep 2020 08:51:50 +0000
From:   常凤楠 <changfengnan@...vision.com>
To:     "tytso@....edu" <tytso@....edu>,
        "linux-ext4@...r.kernel.org" <linux-ext4@...r.kernel.org>,
        "jack@...e.com" <jack@...e.com>
Subject: [PATCH v2] jbd2: fix descriptor block checksum failed after format
 with lazy_journal_init=1

After the last commit, I found that some situations were not considered.
In last post, I only considered the case of descriptor block checksum failed,but there is others situations.
for example:

if you format with lazy_journal_init=1 first time, after mount a short time, you reboot machine, the layout of jbd2 may be like this:

journal Superblock|     [ transactions..... ]      |descriptor_block | data_blocks|  commmit_block | descriptor_block |  data_blocks| commmit_block|[more transactions...
-------------------------|     [some transactions]   |-------------------       transaction x          -----------------|-----------------          transaction x+1         ---------------|

and after reboot, you format with lazy_journal_init=1 second time, after mount a short time, you reboot machine again, the layout of jbd2 may be like this:

1.
journal Superblock|     [ transactions..... ]       |descriptor_block | data_blocks|  commmit_block | descriptor_block |  data_blocks| commmit_block|[more transactions...
-------------------------|     [some transactions]   |---------------          transaction x       ---------------------|
2.
journal Superblock|     [ transactions..... ]       |descriptor_block |  data_blocks | data_blocks  |    data_blocks   | commmit_block| commmit_block|[more transactions...
-------------------------|     [some transactions]   |-----------------------------------               transaction x                  --------------------------------|
3.
journal Superblock|     [ transactions..... ]      |descriptor_block |  data_blocks | data_blocks  |    commmit_block | data_blocks | commmit_block|[more transactions...
-------------------------|    [some transactions]   |--------------------------------     transaction x           ----------------------------|

In case one and two,will be recovery failed. So there is another patch:

 fs/jbd2/recovery.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 55 insertions(+), 5 deletions(-)

diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
index a4967b27ffb6..56198c2c1a04 100644
--- a/fs/jbd2/recovery.c
+++ b/fs/jbd2/recovery.c
@@ -33,6 +33,8 @@ struct recovery_info
 intnr_replays;
 intnr_revokes;
 intnr_revoke_hits;
+int transaction_flag;
+__be64  last_trans_commit_time;
 };

 enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
@@ -412,7 +414,27 @@ static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag,
 else
 return tag->t_checksum == cpu_to_be16(csum32);
 }
+/*
+ * We check the commit time and compare it with the commit time of the previous transaction,
+ * if it's smaller than previous, We think it's not belong to same journal.
+ */
+static int is_same_journal(journal_t *journal,struct buffer_head *bh, unsigned long blocknr, __u64 last_commit_sec)
+{
+int commit_block_nr = blocknr + count_tags(journal, bh) + 1;
+struct buffer_head *nbh;

+int err = jread(&nbh, journal, commit_block_nr);
+if (err)
+return 1;
+
+struct commit_header *cbh = (struct commit_header *)nbh->b_data;
+__u64commit_sec = be64_to_cpu(cbh->h_commit_sec);
+
+if(commit_sec < last_commit_sec)
+return 0;
+else
+return 1;
+}
 static int do_one_pass(journal_t *journal,
 struct recovery_info *info, enum passtype pass)
 {
@@ -514,18 +536,31 @@ static int do_one_pass(journal_t *journal,
 switch(blocktype) {
 case JBD2_DESCRIPTOR_BLOCK:
 /* Verify checksum first */
+if(pass == PASS_SCAN) {
+info->transaction_flag = 0x1;
+}
 if (jbd2_journal_has_csum_v2or3(journal))
 descr_csum_size =
 sizeof(struct jbd2_journal_block_tail);
 if (descr_csum_size > 0 &&
     !jbd2_descriptor_block_csum_verify(journal,
        bh->b_data)) {
-printk(KERN_ERR "JBD2: Invalid checksum "
+if(is_same_journal(journal,bh,next_log_block-1,info->last_trans_commit_time)) {
+printk(KERN_ERR "JBD2: Invalid checksum "
        "recovering block %lu in log\n",
        next_log_block);
-err = -EFSBADCRC;
-brelse(bh);
-goto failed;
+err = -EFSBADCRC;
+brelse(bh);
+goto failed;
+} else {
+/*if it's not belong to same journal, just end this recovery, return with success*/
+printk(KERN_ERR "JBD2: Invalid checksum "
+       "found in block %lu in log, but not same journal %d\n",
+       next_log_block,next_commit_ID);
+err = 0;
+brelse(bh);
+goto done;
+}
 }

 /* If it is a valid descriptor block, replay it
@@ -688,6 +723,17 @@ static int do_one_pass(journal_t *journal,
  * are present verify them in PASS_SCAN; else not
  * much to do other than move on to the next sequence
  * number. */
+if(pass == PASS_SCAN) {
+struct commit_header *cbh =
+(struct commit_header *)bh->b_data;
+if(info->transaction_flag != 0x1) {
+jbd_debug(1, "invalid commit block found in %lu, stop here.\n",next_log_block);
+brelse(bh);
+goto done;
+}
+info->transaction_flag = 0x0;
+info->last_trans_commit_time = be64_to_cpu(cbh->h_commit_sec);
+}
 if (pass == PASS_SCAN &&
     jbd2_has_feature_checksum(journal)) {
 int chksum_err, chksum_seen;
@@ -761,7 +807,11 @@ static int do_one_pass(journal_t *journal,
 brelse(bh);
 continue;
 }
-
+if (pass != PASS_SCAN && info->transaction_flag != 0x1) {
+jbd_debug(1, "invalid revoke block found in %lu, stop here.\n",next_log_block);
+brelse(bh);
+goto done;
+}
 err = scan_revoke_records(journal, bh,
   next_commit_ID, info);
 brelse(bh);

________________________________

CONFIDENTIALITY NOTICE: This electronic message is intended to be viewed only by the individual or entity to whom it is addressed. It may contain information that is privileged, confidential and exempt from disclosure under applicable law. Any dissemination, distribution or copying of this communication is strictly prohibited without our prior permission. If the reader of this message is not the intended recipient, or the employee or agent responsible for delivering the message to the intended recipient, or if you have received this communication in error, please notify us immediately by return e-mail and delete the original message and any copies of it from your computer system. For further information about Hikvision company. please see our website at www.hikvision.com<http://www.hikvision.com>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ