From: Hengyu Liang <hengyul@cs.unc.edu>
To: Jan Kara <jack@suse.cz>
Cc: Christian Brauner <brauner@kernel.org>,
Thomas Schmitt <scdbackup@gmx.net>,
Matthias Goergens <matthias.goergens@gmail.com>,
linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH] isofs: Fix handling of directories with small logical blocks
Date: Sat, 10 Oct 2026 13:56:49 -0400 [thread overview]
Message-ID: <20261010175649.700233-1-hengyul@cs.unc.edu> (raw)
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
next reply other threads:[~2026-10-10 17:57 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-10 17:56 Hengyu Liang [this message]
2026-10-11 20:29 ` Thomas Schmitt
2026-10-12 2:10 ` Hengyu Liang
2026-10-12 10:07 ` Thomas Schmitt
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=20261010175649.700233-1-hengyul@cs.unc.edu \
--to=hengyul@cs.unc.edu \
--cc=brauner@kernel.org \
--cc=jack@suse.cz \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=matthias.goergens@gmail.com \
--cc=scdbackup@gmx.net \
/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 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®