All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ana Bobillo <anabobillo3@gmail.com>
To: Tom Rini <trini@konsulko.com>
Cc: u-boot@lists.u-boot-project.org, Tony Dinh <mibodhi@gmail.com>,
	Simon Glass <sjg@chromium.org>
Subject: [PATCH 5/6] fs: ext4: stop the journal scan at the end of the log
Date: Sun, 08 Nov 2026 15:12:20 +0000	[thread overview]
Message-ID: <1100fb7c-dfd6-4f82-be8f-5ab6b1a61371@gmail.com> (raw)
In-Reply-To: <5072bec2-e2e3-405d-91eb-58fe78ea6669@gmail.com>

From: Ana Bobillo <anabobillo3@gmail.com>

Before every write, ext4fs_check_journal_state() scans the journal of a
filesystem that needs recovery for the transactions to replay. It
follows the log block by block and decides what each block is from its
h_blocktype alone:

- a block of an unknown type with the current sequence number does not
  advance the scan, so the scan never ends
- the h_magic of a block is not checked, so a block that is not a
  journal block is taken as one when its type and sequence words match
- the scan is not bounded by the length of the journal, s_maxlen, nor
  stopped at a block the journal inode does not map
- a revoke block is kept with its r_count unchecked, and
  check_blknr_for_revoke() then reads r_count bytes of records from a
  copy of one block

End the log at a block without the journal magic or of an unknown
type, as Linux's jbd2 does, and at a revoke block whose r_count is
larger than the block, which jbd2's scan_revoke_records() rejects. Also
end it at a block the journal inode does not map and at the end of the
journal: the scan does not follow a log that wraps around the end of
the journal, so it now ends there instead of reading past it.

Ending the log keeps the transactions committed before the block that
ends it, which are replayed. Failing the scan instead would make
ext4fs_init() fail, and its ext4fs_deinit() would mark the journal
clean without replaying any of them.

Remove print_revoke_blks(), which has no caller and walks a revoke
block by its r_count in the same way.

Signed-off-by: Ana Bobillo <anabobillo3@gmail.com>
---
 fs/ext4/ext4_journal.c | 65 +++++++++++++++++++++++-------------------
 1 file changed, 36 insertions(+), 29 deletions(-)

diff --git a/fs/ext4/ext4_journal.c b/fs/ext4/ext4_journal.c
index cb63addea0a..c2c022d6c4f 100644
--- a/fs/ext4/ext4_journal.c
+++ b/fs/ext4/ext4_journal.c
@@ -239,28 +239,6 @@ int ext4fs_put_metadata(char *metadata_buffer, uint32_t blknr)
 	return 0;
 }
 
-void print_revoke_blks(char *revk_blk)
-{
-	int offset;
-	int max;
-	long int blocknr;
-	struct journal_revoke_header_t *header;
-
-	if (revk_blk == NULL)
-		return;
-
-	header = (struct journal_revoke_header_t *) revk_blk;
-	offset = sizeof(struct journal_revoke_header_t);
-	max = be32_to_cpu(header->r_count);
-	printf("total bytes %d\n", max);
-
-	while (offset < max) {
-		blocknr = be32_to_cpu(*((__be32 *)(revk_blk + offset)));
-		printf("revoke blknr is %ld\n", blocknr);
-		offset += 4;
-	}
-}
-
 static struct revoke_blk_list *_get_node(void)
 {
 	struct revoke_blk_list *tmp_node;
@@ -430,7 +408,7 @@ void print_jrnl_status(int recovery_flag)
 
 int ext4fs_check_journal_state(int recovery_flag)
 {
-	int i;
+	unsigned int i, maxlen;
 	int DB_FOUND = NO;
 	long int blknr;
 	int transaction_state = TRANSACTION_COMPLETE;
@@ -440,6 +418,7 @@ int ext4fs_check_journal_state(int recovery_flag)
 	struct ext2_inode inode_journal;
 	struct journal_superblock_t *jsb = NULL;
 	struct journal_header_t *jdb = NULL;
+	struct journal_revoke_header_t *revoke;
 	char *p_jdb = NULL;
 	struct ext3_journal_block_tag *tag = NULL;
 	char *temp_buff = NULL;
@@ -482,14 +461,35 @@ int ext4fs_check_journal_state(int recovery_flag)
 		jsb->s_feature_compat |=
 				cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM);
 
+	/*
+	 * The scan does not follow a log that wraps around the end of the
+	 * journal, so it ends there. Keep the block indexes in the range
+	 * read_allocated_block() takes.
+	 */
+	maxlen = min_t(u32, be32_to_cpu(jsb->s_maxlen), INT_MAX);
 	i = be32_to_cpu(jsb->s_first);
 	while (1) {
+		if (i >= maxlen) {
+			print_jrnl_status(recovery_flag);
+			break;
+		}
+
 		blknr = read_allocated_block(&inode_journal, i, NULL);
+		if (blknr <= 0) {
+			print_jrnl_status(recovery_flag);
+			break;
+		}
 		memset(temp_buff1, '\0', fs->blksz);
 		ext4fs_devread((lbaint_t)blknr * fs->sect_perblk,
 			       0, fs->blksz, temp_buff1);
 		jdb = (struct journal_header_t *) temp_buff1;
 
+		/* A block that is not a journal block ends the log */
+		if (jdb->h_magic != cpu_to_be32(EXT3_JOURNAL_MAGIC_NUMBER)) {
+			print_jrnl_status(recovery_flag);
+			break;
+		}
+
 		if (be32_to_cpu(jdb->h_blocktype) ==
 		    EXT3_JOURNAL_DESCRIPTOR_BLOCK) {
 			if (be32_to_cpu(jdb->h_sequence) !=
@@ -547,16 +547,23 @@ int ext4fs_check_journal_state(int recovery_flag)
 				print_jrnl_status(recovery_flag);
 				break;
 			}
+			/*
+			 * check_blknr_for_revoke() walks the records up to
+			 * r_count bytes, which must lie inside the block
+			 */
+			revoke = (struct journal_revoke_header_t *)jdb;
+			if (be32_to_cpu(revoke->r_count) > fs->blksz) {
+				printf("Invalid revoke block\n");
+				print_jrnl_status(recovery_flag);
+				break;
+			}
 			if (recovery_flag == SCAN)
 				ext4fs_push_revoke_blk((char *)jdb);
 			i++;
 		} else {
-			debug("Else Case\n");
-			if (be32_to_cpu(jdb->h_sequence) !=
-			    be32_to_cpu(jsb->s_sequence)) {
-				print_jrnl_status(recovery_flag);
-				break;
-			}
+			/* An unknown block type ends the log, as for Linux */
+			print_jrnl_status(recovery_flag);
+			break;
 		}
 	}
 

  parent reply	other threads:[~2026-11-08 15:12 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-08 15:11 [PATCH 0/6] fs: ext4: check on-disk values in the write path Ana Bobillo
2026-11-08 15:11 ` [PATCH 1/6] fs: ext4: refuse to write with an unexpected first data block Ana Bobillo
2026-11-08 15:12 ` [PATCH 2/6] fs: ext4: use ext4fs_blk_to_group() in ext4fs_get_new_blk_no() Ana Bobillo
2026-11-08 15:12 ` [PATCH 3/6] fs: ext4: check directory entries before using them Ana Bobillo
2026-11-08 15:12 ` [PATCH 4/6] fs: ext4: bound the journal entry tables Ana Bobillo
2026-11-08 15:12 ` Ana Bobillo [this message]
2026-11-08 15:12 ` [PATCH 6/6] test: fs: ext4: add tests for the write path checks Ana Bobillo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1100fb7c-dfd6-4f82-be8f-5ab6b1a61371@gmail.com \
    --to=anabobillo3@gmail.com \
    --cc=mibodhi@gmail.com \
    --cc=sjg@chromium.org \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.u-boot-project.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.