mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] isofs: Fix handling of directories with small logical blocks
@ 2026-10-10 17:56 Hengyu Liang
  2026-10-11 20:29 ` Thomas Schmitt
  0 siblings, 1 reply; 4+ messages in thread
From: Hengyu Liang @ 2026-10-10 17:56 UTC (permalink / raw)
  To: Jan Kara
  Cc: Christian Brauner, Thomas Schmitt, Matthias Goergens,
	linux-fsdevel, linux-kernel

Commit b2eb2e288604 ("isofs: Drop support of directory entries
straddling blocks") made do_isofs_readdir() and isofs_find_entry()
reject a directory record that does not end in the block it begins in.

However, the block is the logical block of the volume, which can be 512
or 1024 bytes. ECMA-119 only requires a record to end in the 2048-byte
logical sector in which it begins, so a record can cross a logical
block. As of now, ls stops at the first such record and the files after
it cannot be opened.

The issue can be reproduced with an image that has 1024-byte logical
blocks and 40 files in its root directory:

    mount -t iso9660 -o loop,ro lbs1024.iso /mnt
    ls /mnt | wc -l

Before commit b2eb2e288604 ("isofs: Drop support of directory entries
straddling blocks"), the result is 40.

After that commit, the result is 19, and the kernel logs:

    iso9660: Corrupted directory entry in block 0 of inode 1152

This patch will put such a record together from its two blocks again,
but only when it ends in the logical sector in which it begins.

Fixes: b2eb2e288604 ("isofs: Drop support of directory entries straddling blocks")
Signed-off-by: Hengyu Liang <hengyul@cs.unc.edu>
---
 fs/isofs/dir.c   | 22 +++++++++++++++++++++-
 fs/isofs/namei.c | 22 +++++++++++++++++++++-
 2 files changed, 42 insertions(+), 2 deletions(-)

diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index 28741251d56e..c72cfb08707c 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -95,7 +95,9 @@ static int do_isofs_readdir(struct inode *inode, struct file *file,
 	int map;
 	int first_de = 1;
 	char *p = NULL;		/* Quiet GCC */
+	u8 record[256];
 	struct iso_directory_record *de;
+	struct iso_directory_record *tmpde = (void *)record;
 	struct isofs_sb_info *sbi = ISOFS_SB(inode->i_sb);
 
 	offset = ctx->pos & (bufsize - 1);
@@ -129,7 +131,25 @@ static int do_isofs_readdir(struct inode *inode, struct file *file,
 		offset_saved = offset;
 		offset += de_len;
 
-		if (!isofs_dir_record_valid(de, offset_saved, bufsize)) {
+		/* A record may span blocks within a logical sector. */
+		if (offset > bufsize &&
+		    de_len <= ISOFS_BLOCK_SIZE -
+			      (ctx->pos & (ISOFS_BLOCK_SIZE - 1))) {
+			unsigned int slop = bufsize - offset_saved;
+
+			memcpy(tmpde, de, slop);
+			offset &= bufsize - 1;
+			block++;
+			brelse(bh);
+			bh = isofs_bread(inode, block);
+			if (!bh)
+				return -EIO;
+			memcpy((char *)tmpde + slop, bh->b_data, offset);
+			de = tmpde;
+		}
+
+		if (!isofs_dir_record_valid(de, de == tmpde ? 0 : offset_saved,
+					    de == tmpde ? de_len : bufsize)) {
 			printk(KERN_NOTICE "iso9660: Corrupted directory entry"
 			       " in block %lu of inode %llu\n", block,
 			       inode->i_ino);
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index 4fba1bf7f016..289efa60f3bf 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -54,6 +54,8 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry,
 	unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
 	unsigned long block, f_pos, offset, block_saved, offset_saved;
 	struct buffer_head *bh = NULL;
+	u8 record[256];
+	struct iso_directory_record *tmpde = (void *)record;
 	struct isofs_sb_info *sbi = ISOFS_SB(dir->i_sb);
 
 	if (!ISOFS_I(dir)->i_first_extent)
@@ -93,7 +95,25 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry,
 		offset += de_len;
 		f_pos += de_len;
 
-		if (!isofs_dir_record_valid(de, offset_saved, bufsize)) {
+		/* A record may span blocks within a logical sector. */
+		if (offset > bufsize &&
+		    de_len <= ISOFS_BLOCK_SIZE -
+			      ((f_pos - de_len) & (ISOFS_BLOCK_SIZE - 1))) {
+			unsigned int slop = bufsize - offset_saved;
+
+			memcpy(tmpde, de, slop);
+			offset &= bufsize - 1;
+			block++;
+			brelse(bh);
+			bh = isofs_bread(dir, block);
+			if (!bh)
+				return 0;
+			memcpy((char *)tmpde + slop, bh->b_data, offset);
+			de = tmpde;
+		}
+
+		if (!isofs_dir_record_valid(de, de == tmpde ? 0 : offset_saved,
+					    de == tmpde ? de_len : bufsize)) {
 			printk(KERN_NOTICE "iso9660: Corrupted directory entry"
 			       " in block %lu of inode %llu\n", block,
 			       dir->i_ino);
-- 
2.53.0


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-10-12 10:06 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-10 17:56 [PATCH] isofs: Fix handling of directories with small logical blocks Hengyu Liang
2026-10-11 20:29 ` Thomas Schmitt
2026-10-12  2:10   ` Hengyu Liang
2026-10-12 10:07     ` Thomas Schmitt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®