[PATCH 2/2] isofs: drop support for level 3 records straddling blocks

From: Matthias Goergens

Date: Tue Sep 22 2026 - 10:13:43 EST


isofs_read_level3_size() is the third copy of the directory record walk
and the last one that still reassembles a record spanning two blocks.
Now that it validates every record with isofs_dir_record_valid(), such a
record is rejected before the copy can run. ECMA-119 does not allow
directory records to straddle sector boundaries, the same assumption
commit b2eb2e288604 ("isofs: Drop support of directory entries
straddling blocks") relied on when it removed the equivalent code from
readdir and lookup.

Remove it here too, along with the temporary record buffer it needed,
and fold the end-of-block case into the existing zero-length check the
way commit bda8d8d49ca1 ("isofs: Fix handling of directories with tight
blocks") did for the other two walkers. That check has to cover both
cases. The code being removed here ran on "offset >= bufsize", so it
was also doing the block advance for a record that ends exactly at the
end of a block, and dropping it without replacing that is what went
wrong last time.

Signed-off-by: Matthias Goergens <matthias.goergens@xxxxxxxxx>
---
fs/isofs/inode.c | 38 ++++++--------------------------------
1 file changed, 6 insertions(+), 32 deletions(-)

diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index c9bc1f479161..70097456b721 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -1174,7 +1174,6 @@ static int isofs_read_level3_size(struct inode *inode)
unsigned long block, offset, block_saved, offset_saved;
int i = 0;
int more_entries = 0;
- struct iso_directory_record *tmpde = NULL;
struct iso_inode_info *ei = ISOFS_I(inode);

inode->i_size = 0;
@@ -1198,9 +1197,12 @@ static int isofs_read_level3_size(struct inode *inode)
goto out_noread;
}
de = (struct iso_directory_record *) (bh->b_data + offset);
- de_len = *(unsigned char *) de;

- if (de_len == 0) {
+ /*
+ * If we are at the end of a block (or at its zero-padded
+ * tail), move on to the next block.
+ */
+ if (offset >= bufsize || de->length[0] == 0) {
brelse(bh);
bh = NULL;
++block;
@@ -1212,36 +1214,14 @@ static int isofs_read_level3_size(struct inode *inode)
printk(KERN_NOTICE "iso9660: Corrupted directory entry in block %lu of inode %llu\n",
block, inode->i_ino);
brelse(bh);
- kfree(tmpde);
return -EIO;
}

+ de_len = de->length[0];
block_saved = block;
offset_saved = offset;
offset += de_len;

- /* Make sure we have a full directory entry */
- if (offset >= bufsize) {
- int slop = bufsize - offset + de_len;
- if (!tmpde) {
- tmpde = kmalloc(256, GFP_KERNEL);
- if (!tmpde)
- goto out_nomem;
- }
- memcpy(tmpde, de, slop);
- offset &= bufsize - 1;
- block++;
- brelse(bh);
- bh = NULL;
- if (offset) {
- bh = sb_bread(inode->i_sb, block);
- if (!bh)
- goto out_noread;
- memcpy((void *)tmpde+slop, bh->b_data, offset);
- }
- de = tmpde;
- }
-
inode->i_size += isonum_733(de->size);
if (i == 1) {
ei->i_next_section_block = block_saved;
@@ -1255,17 +1235,11 @@ static int isofs_read_level3_size(struct inode *inode)
goto out_toomany;
} while (more_entries);
out:
- kfree(tmpde);
brelse(bh);
return 0;

-out_nomem:
- brelse(bh);
- return -ENOMEM;
-
out_noread:
printk(KERN_INFO "ISOFS: unable to read i-node block %lu\n", block);
- kfree(tmpde);
return -EIO;

out_toomany:
--
2.55.0