* [PATCH] isofs: reject short directory records in isofs_read_level3_size()
@ 2026-09-19 22:25 Hui Peng
2026-09-23 17:52 ` Matthias Goergens
0 siblings, 1 reply; 13+ messages in thread
From: Hui Peng @ 2026-09-19 22:25 UTC (permalink / raw)
To: jack, brauner, viro; +Cc: linux-fsdevel, linux-kernel
In isofs_read_level3_size(), check that de_len is at least sizeof(struct
iso_directory_record) + de->name_len[0] before advancing or inspecting
Rock Ridge extensions so corrupted ISO9660 directory records cannot
trigger out-of-bounds reads or infinite loops.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Assisted-by: LLM
Signed-off-by: Hui Peng <benquike@gmail.com>
---
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 337836a0a170..6007439a085a 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -1173,7 +1173,9 @@ static int isofs_read_level3_size(struct inode *inode)
struct buffer_head *bh = NULL;
unsigned long block, offset, block_saved, offset_saved;
int i = 0;
+ unsigned int empty_blocks = 0;
int more_entries = 0;
+ int ret = -EIO;
struct iso_directory_record *tmpde = NULL;
struct iso_inode_info *ei = ISOFS_I(inode);
@@ -1205,9 +1207,15 @@ static int isofs_read_level3_size(struct inode *inode)
bh = NULL;
++block;
offset = 0;
+ if (++empty_blocks > 100)
+ goto out;
continue;
}
+ if (de_len < sizeof(struct iso_directory_record))
+ goto out;
+ empty_blocks = 0;
+
block_saved = block;
offset_saved = offset;
offset += de_len;
@@ -1246,10 +1254,11 @@ static int isofs_read_level3_size(struct inode *inode)
if (i > 100)
goto out_toomany;
} while (more_entries);
+ ret = 0;
out:
kfree(tmpde);
brelse(bh);
- return 0;
+ return ret;
out_nomem:
brelse(bh);
@@ -1264,6 +1273,7 @@ static int isofs_read_level3_size(struct inode *inode)
printk(KERN_INFO "%s: More than 100 file sections ?!?, aborting...\n"
"isofs_read_level3_size: inode=%llu\n",
__func__, inode->i_ino);
+ ret = 0;
goto out;
}
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH] isofs: reject short directory records in isofs_read_level3_size() 2026-09-19 22:25 [PATCH] isofs: reject short directory records in isofs_read_level3_size() Hui Peng @ 2026-09-23 17:52 ` Matthias Goergens 2026-09-24 15:03 ` Jan Kara 0 siblings, 1 reply; 13+ messages in thread From: Matthias Goergens @ 2026-09-23 17:52 UTC (permalink / raw) To: Hui Peng Cc: Jan Kara, Christian Brauner, Alexander Viro, linux-fsdevel, linux-kernel Hi Hui, I'm sorry, I missed your patch when I sent mine for the same function a few days later ("[PATCH v2] isofs: validate directory records in isofs_read_level3_size()"), and Jan has since applied mine to his tree. I did test yours, on mainline and on Jan's for_next, running fs/isofs in a userspace harness with ASan and UBSan: it fixes the three fuzzer images that made isofs_read_level3_size() read past a record, and I found no change on valid multi-extent images. The part of yours that mine doesn't have is the limit on how many empty blocks the walk skips. Without it, a run of zero blocks is walked until the end of the device. On top of for_next that would be a small follow-up, and if you'd like to send it I'm happy to test and review it. If you'd rather I send it, I'll credit you with Suggested-by, or with Co-developed-by followed by your Signed-off-by if you prefer. Thanks, Matthias ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] isofs: reject short directory records in isofs_read_level3_size() 2026-09-23 17:52 ` Matthias Goergens @ 2026-09-24 15:03 ` Jan Kara 2026-09-24 15:13 ` Matthias Goergens 0 siblings, 1 reply; 13+ messages in thread From: Jan Kara @ 2026-09-24 15:03 UTC (permalink / raw) To: Matthias Goergens Cc: Hui Peng, Jan Kara, Christian Brauner, Alexander Viro, linux-fsdevel, linux-kernel Hi! On Thu 24-09-26 01:52:15, Matthias Goergens wrote: > I'm sorry, I missed your patch when I sent mine for the same function a > few days later ("[PATCH v2] isofs: validate directory records in > isofs_read_level3_size()"), and Jan has since applied mine to his tree. > > I did test yours, on mainline and on Jan's for_next, running fs/isofs in > a userspace harness with ASan and UBSan: it fixes the three fuzzer > images that made isofs_read_level3_size() read past a record, and I > found no change on valid multi-extent images. For record I think your fix was better because it used proper entry validation helper which catches more problems. > The part of yours that mine doesn't have is the limit on how many empty > blocks the walk skips. Without it, a run of zero blocks is walked until > the end of the device. On top of for_next that would be a small > follow-up, and if you'd like to send it I'm happy to test and review it. > If you'd rather I send it, I'll credit you with Suggested-by, or with > Co-developed-by followed by your Signed-off-by if you prefer. Based on the standard empty directory blocks are not allowed (there must be at least one directory record in each directory block). So I'd perhaps just add checks to refuse them. Then the limit on the number of sections of inode description already present in isofs_read_level3_size() will naturally take care of the rest. Honza -- Jan Kara <jack@suse.com> SUSE Labs, CR ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] isofs: reject short directory records in isofs_read_level3_size() 2026-09-24 15:03 ` Jan Kara @ 2026-09-24 15:13 ` Matthias Goergens 2026-09-25 4:38 ` Matthias Goergens 0 siblings, 1 reply; 13+ messages in thread From: Matthias Goergens @ 2026-09-24 15:13 UTC (permalink / raw) To: jack; +Cc: benquike, brauner, viro, linux-fsdevel, linux-kernel Hi Honza, On Thu 24-09-26 17:03:50, Jan Kara wrote: > Based on the standard empty directory blocks are not allowed (there must be > at least one directory record in each directory block). So I'd perhaps just > add checks to refuse them. Then the limit on the number of sections of inode > description already present in isofs_read_level3_size() will naturally take > care of the rest. That's simpler, thanks. Hui, would you like to do that? If not, I'll send it in a few days. Either way, I'll first check a set of real images for empty directory blocks, so we know the check doesn't reject discs that mount today. Thanks, Matthias ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] isofs: reject short directory records in isofs_read_level3_size() 2026-09-24 15:13 ` Matthias Goergens @ 2026-09-25 4:38 ` Matthias Goergens 2026-09-25 9:28 ` Jan Kara 0 siblings, 1 reply; 13+ messages in thread From: Matthias Goergens @ 2026-09-25 4:38 UTC (permalink / raw) To: jack; +Cc: benquike, brauner, viro, linux-fsdevel, linux-kernel Hi Honza, On Thu, Sep 24, 2026 at 11:13:56PM +0800, Matthias Goergens wrote: > Either way, I'll first check a set of real images for empty directory > blocks, so we know the check doesn't reject discs that mount today. Empty directory blocks do occur: about 1% of the disc images I checked on archive.org have them, mostly from Easy CD Creator 4.0 to 4.2 and Nero, and always at the end of a directory. One of them hangs on for_next, see [1]. Two more examples, with the bytes used in each block of the directory: https://archive.org/details/Anime_Transformer DM_BXL2.iso /XTRAS 2022 1526 empty (Easy CD Creator 4.2) https://archive.org/details/comdex-edu Comdex_05.iso /IMAGES 2012 2048 empty (Nero) So a general check in readdir or lookup would stop those discs from mounting. In isofs_read_level3_size() it would reject none of them: no empty block on those discs follows a record with the multi-extent flag, so the walk always ends first. What refusing buys is limited to crafted images, where a flagged record followed by empty blocks makes the walk skip block after block until a read fails, because the 100-section limit counts records, not blocks. No other reader I looked at rejects them: Microsoft's published CDFS sample, GRUB, libarchive, libcdio, 7-Zip and libisofs all skip empty blocks inside a multi-extent chain and stop at the end of the directory, and GRUB fixed an unbounded walk that way in 4e0bab34ece7 ("fs/iso9660: Add check to prevent infinite loop"). Windows Server 2022 and 2025 also join the sections across an empty block and return the whole file. So I'd suggest following their lead: skip empty blocks in the walk as readdir and lookup do, and stop at the end of the directory. isofs_read_level3_size() doesn't know where the directory ends today, though. isofs_lookup() does and could pass it down through __isofs_iget(), but inodes reached from an NFS file handle can't, so those would still need a bound such as counting skipped blocks towards the 100-section limit. If that is more plumbing than you'd like, the counting alone would do. What would you prefer? Whatever the bound, only a zero length at the start of a block should count as an empty block. A multi-extent record can end one block with padding and its next section start the following one; that has to keep working. Thanks, Matthias [1] https://lore.kernel.org/all/20260925042835.1974673-1-matthias.goergens@gmail.com/ ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] isofs: reject short directory records in isofs_read_level3_size() 2026-09-25 4:38 ` Matthias Goergens @ 2026-09-25 9:28 ` Jan Kara 2026-09-25 11:22 ` Matthias Goergens 2026-09-26 8:35 ` [PATCH] isofs: bound empty directory blocks " Matthias Goergens 0 siblings, 2 replies; 13+ messages in thread From: Jan Kara @ 2026-09-25 9:28 UTC (permalink / raw) To: Matthias Goergens Cc: jack, benquike, brauner, viro, linux-fsdevel, linux-kernel On Fri 25-09-26 12:38:04, Matthias Goergens wrote: > Hi Honza, > > On Thu, Sep 24, 2026 at 11:13:56PM +0800, Matthias Goergens wrote: > > Either way, I'll first check a set of real images for empty directory > > blocks, so we know the check doesn't reject discs that mount today. > > Empty directory blocks do occur: about 1% of the disc images I checked > on archive.org have them, mostly from Easy CD Creator 4.0 to 4.2 and > Nero, and always at the end of a directory. One of them hangs on > for_next, see [1]. Two more examples, with the bytes used in each > block of the directory: > > https://archive.org/details/Anime_Transformer DM_BXL2.iso > /XTRAS 2022 1526 empty (Easy CD Creator 4.2) > https://archive.org/details/comdex-edu Comdex_05.iso > /IMAGES 2012 2048 empty (Nero) > > So a general check in readdir or lookup would stop those discs from > mounting. OK, thanks for checking! BTW how did you do the check. Have you've downloaded all the images? Anyway, despite this being contrary to ECMA-119 standard I agree we shouldn't start refusing such images if they worked in the past. > In isofs_read_level3_size() it would reject none of them: no empty block > on those discs follows a record with the multi-extent flag, so the walk > always ends first. What refusing buys is limited to crafted images, > where a flagged record followed by empty blocks makes the walk skip > block after block until a read fails, because the 100-section limit > counts records, not blocks. > > No other reader I looked at rejects them: Microsoft's published CDFS > sample, GRUB, libarchive, libcdio, 7-Zip and libisofs all skip empty > blocks inside a multi-extent chain and stop at the end of the directory, > and GRUB fixed an unbounded walk that way in 4e0bab34ece7 ("fs/iso9660: > Add check to prevent infinite loop"). Windows Server 2022 and 2025 also > join the sections across an empty block and return the whole file. > > So I'd suggest following their lead: skip empty blocks in the walk as > readdir and lookup do, and stop at the end of the directory. > isofs_read_level3_size() doesn't know where the directory ends today, > though. isofs_lookup() does and could pass it down through > __isofs_iget(), but inodes reached from an NFS file handle can't, so > those would still need a bound such as counting skipped blocks towards > the 100-section limit. If that is more plumbing than you'd like, the > counting alone would do. What would you prefer? Yes. I was actually looking at propagating the directory size to __isofs_iget() yesterday before sending my replay and concluded we cannot easily do that in all the cases. I don't think it makes sense to plumb the directory size for the cases where we can do it - unless the image is corrupted we don't need it and unreliable check doesn't help for corrupted images. So yes, just keep the code skipping empty blocks and I'd just limit the number of sections + empty blocks to 100. No sane disk image should exceed that. > Whatever the bound, only a zero length at the start of a block should > count as an empty block. A multi-extent record can end one block with > padding and its next section start the following one; that has to keep > working. Agreed. Honza -- Jan Kara <jack@suse.com> SUSE Labs, CR ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] isofs: reject short directory records in isofs_read_level3_size() 2026-09-25 9:28 ` Jan Kara @ 2026-09-25 11:22 ` Matthias Goergens 2026-09-26 8:35 ` [PATCH] isofs: bound empty directory blocks " Matthias Goergens 1 sibling, 0 replies; 13+ messages in thread From: Matthias Goergens @ 2026-09-25 11:22 UTC (permalink / raw) To: jack; +Cc: benquike, brauner, viro, linux-fsdevel, linux-kernel Hi Honza, On Fri 25-09-26 11:28:18, Jan Kara wrote: > OK, thanks for checking! BTW how did you do the check. Have you've downloaded > all the images? Gotta use that 10 Gbps fibre-to-the-home broadband for something! But no, I used a script: archive.org serves range requests, so it fetched only the volume descriptors, path tables and directory extents of each image, about half a megabyte per disc, and parsed those. I'm happy to share the script and the list of images. > So yes, just keep the code skipping empty blocks and I'd just limit > the number of sections + empty blocks to 100. Will do, unless Hui would like to take it. Thanks, Matthias ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH] isofs: bound empty directory blocks in isofs_read_level3_size() 2026-09-25 9:28 ` Jan Kara 2026-09-25 11:22 ` Matthias Goergens @ 2026-09-26 8:35 ` Matthias Goergens 2026-09-29 10:57 ` Jan Kara 1 sibling, 1 reply; 13+ messages in thread From: Matthias Goergens @ 2026-09-26 8:35 UTC (permalink / raw) To: Jan Kara Cc: Hui Peng, Christian Brauner, Alexander Viro, linux-fsdevel, linux-kernel isofs_read_level3_size() walks the sections of a level-3 (multi-extent) directory record and, on a zero length byte, moves on to the next block with no limit. A crafted image can put a long run of empty blocks between two sections of a multi-extent file, and the walk reads every one of them before it gives up, all the way to the end of the device if it has to. Real discs do have trailing empty directory blocks, written by tools such as Easy CD Creator and Nero, but always at the end of the directory, never between two sections of a multi-extent record, so they do not exercise this path [1]. Jan Kara suggested treating an empty block like a section: count it towards the existing 100-section limit rather than adding a separate one [2]. Do that: both the section count and the empty-block count are checked against their combined total, so neither one alone can reach 100 while the other keeps growing. Only a zero length byte at the start of a block counts as an empty block; the same byte later in a block still just ends that block's records, as it does today, and is not counted. Hui Peng's earlier patch for this function added its own, separate limit on the number of empty blocks [3]; this uses the combined limit Jan suggested instead. Suggested-by: Jan Kara <jack@suse.cz> Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com> [1] https://lore.kernel.org/all/20260925043804.2091174-1-matthias.goergens@gmail.com/ [2] https://lore.kernel.org/all/cmlro2xzle2aa7ebflvxhbcv74mea7p6qvxhin6egpdvyzyuxh@s45tpgxdal3n/ [3] https://lore.kernel.org/all/20260919222553.3792320-1-benquike@gmail.com/ --- Tested with fs/isofs built as a userspace program under ASan and UBSan, and in a KASAN VM on Jan's for_next: - The real discs from [1] (DM_BXL2, Comdex_05, ITSOFTCD_39, each with trailing empty directory blocks) and the level-3 images from the earlier patches list and read the same with and without this patch. - A crafted multi-extent file with 150 empty blocks between two sections now stops with "More than 100 file sections/empty blocks ?!?" instead of reading all of them. - A crafted file with 60 sections and 50 empty blocks interleaved (110 in all) is rejected; without this patch it is accepted. The image generators are at https://github.com/matthiasgoergens/linux/tree/reproducer/2026-09-26-isofs-empty-blocks fs/isofs/inode.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 184350d2e6ad..e884618c0c53 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -1175,6 +1175,7 @@ static int isofs_read_level3_size(struct inode *inode) struct buffer_head *bh = NULL; unsigned long block, offset, block_saved, offset_saved; int i = 0; + int empty_blocks = 0; int more_entries = 0; struct iso_inode_info *ei = ISOFS_I(inode); @@ -1202,9 +1203,14 @@ static int isofs_read_level3_size(struct inode *inode) /* * If we are at the end of a block (or at its zero-padded - * tail), move on to the next block. + * tail), move on to the next block. A zero length byte at + * the start of a block means the whole block is empty; + * count that towards the same limit as sections below, or a + * chain of empty blocks could be walked without bound. */ if (offset >= bufsize || de->length[0] == 0) { + if (offset == 0 && ++empty_blocks + i > 100) + goto out_toomany; brelse(bh); bh = NULL; ++block; @@ -1233,7 +1239,7 @@ static int isofs_read_level3_size(struct inode *inode) more_entries = de->flags[-high_sierra] & 0x80; i++; - if (i > 100) + if (i + empty_blocks > 100) goto out_toomany; } while (more_entries); out: @@ -1245,7 +1251,7 @@ static int isofs_read_level3_size(struct inode *inode) return -EIO; out_toomany: - printk(KERN_INFO "%s: More than 100 file sections ?!?, aborting...\n" + printk(KERN_INFO "%s: More than 100 file sections/empty blocks ?!?, aborting...\n" "isofs_read_level3_size: inode=%llu\n", __func__, inode->i_ino); goto out; base-commit: f622f21cddacf8a0ef3b0344382924dc52c72a72 -- 2.55.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH] isofs: bound empty directory blocks in isofs_read_level3_size() 2026-09-26 8:35 ` [PATCH] isofs: bound empty directory blocks " Matthias Goergens @ 2026-09-29 10:57 ` Jan Kara 2026-09-30 3:39 ` Matthias Goergens 0 siblings, 1 reply; 13+ messages in thread From: Jan Kara @ 2026-09-29 10:57 UTC (permalink / raw) To: Matthias Goergens Cc: Jan Kara, Hui Peng, Christian Brauner, Alexander Viro, linux-fsdevel, linux-kernel On Sat 26-09-26 16:35:17, Matthias Goergens wrote: > isofs_read_level3_size() walks the sections of a level-3 (multi-extent) > directory record and, on a zero length byte, moves on to the next > block with no limit. A crafted image can put a long run of empty > blocks between two sections of a multi-extent file, and the walk reads > every one of them before it gives up, all the way to the end of the > device if it has to. > > Real discs do have trailing empty directory blocks, written by tools > such as Easy CD Creator and Nero, but always at the end of the > directory, never between two sections of a multi-extent record, so > they do not exercise this path [1]. > > Jan Kara suggested treating an empty block like a section: count it > towards the existing 100-section limit rather than adding a separate > one [2]. Do that: both the section count and the empty-block count > are checked against their combined total, so neither one alone can > reach 100 while the other keeps growing. Only a zero length byte at > the start of a block counts as an empty block; the same byte later in > a block still just ends that block's records, as it does today, and > is not counted. > > Hui Peng's earlier patch for this function added its own, separate > limit on the number of empty blocks [3]; this uses the combined limit > Jan suggested instead. > > Suggested-by: Jan Kara <jack@suse.cz> > Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com> > > [1] https://lore.kernel.org/all/20260925043804.2091174-1-matthias.goergens@gmail.com/ > [2] https://lore.kernel.org/all/cmlro2xzle2aa7ebflvxhbcv74mea7p6qvxhin6egpdvyzyuxh@s45tpgxdal3n/ > [3] https://lore.kernel.org/all/20260919222553.3792320-1-benquike@gmail.com/ > --- > Tested with fs/isofs built as a userspace program under ASan and UBSan, > and in a KASAN VM on Jan's for_next: > > - The real discs from [1] (DM_BXL2, Comdex_05, ITSOFTCD_39, each with > trailing empty directory blocks) and the level-3 images from the > earlier patches list and read the same with and without this patch. > - A crafted multi-extent file with 150 empty blocks between two sections > now stops with "More than 100 file sections/empty blocks ?!?" instead > of reading all of them. > - A crafted file with 60 sections and 50 empty blocks interleaved (110 > in all) is rejected; without this patch it is accepted. > > The image generators are at > https://github.com/matthiasgoergens/linux/tree/reproducer/2026-09-26-isofs-empty-blocks Thanks for the patch and the generator. Just one question below: > diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c > index 184350d2e6ad..e884618c0c53 100644 > --- a/fs/isofs/inode.c > +++ b/fs/isofs/inode.c > @@ -1175,6 +1175,7 @@ static int isofs_read_level3_size(struct inode *inode) > struct buffer_head *bh = NULL; > unsigned long block, offset, block_saved, offset_saved; > int i = 0; > + int empty_blocks = 0; > int more_entries = 0; > struct iso_inode_info *ei = ISOFS_I(inode); > > @@ -1202,9 +1203,14 @@ static int isofs_read_level3_size(struct inode *inode) > > /* > * If we are at the end of a block (or at its zero-padded > - * tail), move on to the next block. > + * tail), move on to the next block. A zero length byte at > + * the start of a block means the whole block is empty; > + * count that towards the same limit as sections below, or a > + * chain of empty blocks could be walked without bound. > */ > if (offset >= bufsize || de->length[0] == 0) { > + if (offset == 0 && ++empty_blocks + i > 100) > + goto out_toomany; Any reason why don't you do just "++i > 100" here and completely remove the empty_blocks variable? Honza -- Jan Kara <jack@suse.com> SUSE Labs, CR ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] isofs: bound empty directory blocks in isofs_read_level3_size() 2026-09-29 10:57 ` Jan Kara @ 2026-09-30 3:39 ` Matthias Goergens 2026-09-30 10:33 ` Jan Kara 0 siblings, 1 reply; 13+ messages in thread From: Matthias Goergens @ 2026-09-30 3:39 UTC (permalink / raw) To: Jan Kara Cc: Hui Peng, Christian Brauner, Alexander Viro, linux-fsdevel, linux-kernel Hi Honza, > Any reason why don't you do just "++i > 100" here and completely > remove the empty_blocks variable? Yes: i has one other use. The "if (i == 1)" further down records where the second section starts (i_next_section_block/offset). Counting empty blocks in i would move i past 1 before the second record is read when an empty block sits between the first two records, so the next-section link stays 0 and isofs_get_blocks() reads past the first extent into whatever follows it on disk. I tried your variant on a two-section image with one empty block between the records: v1 reads the file correctly, the variant returns different bytes. I'm happy to send a v2 that adds a comment saying why the count stays out of i, if you'd like one. Thanks, Matthias ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] isofs: bound empty directory blocks in isofs_read_level3_size() 2026-09-30 3:39 ` Matthias Goergens @ 2026-09-30 10:33 ` Jan Kara 2026-10-01 10:30 ` Matthias Goergens 0 siblings, 1 reply; 13+ messages in thread From: Jan Kara @ 2026-09-30 10:33 UTC (permalink / raw) To: Matthias Goergens Cc: Jan Kara, Hui Peng, Christian Brauner, Alexander Viro, linux-fsdevel, linux-kernel [-- Attachment #1: Type: text/plain, Size: 987 bytes --] On Wed 30-09-26 11:39:40, Matthias Goergens wrote: > Hi Honza, > > > Any reason why don't you do just "++i > 100" here and completely > > remove the empty_blocks variable? > > Yes: i has one other use. The "if (i == 1)" further down records > where the second section starts (i_next_section_block/offset). > Counting empty blocks in i would move i past 1 before the second > record is read when an empty block sits between the first two > records, so the next-section link stays 0 and isofs_get_blocks() > reads past the first extent into whatever follows it on disk. I > tried your variant on a two-section image with one empty block > between the records: v1 reads the file correctly, the variant returns > different bytes. > > I'm happy to send a v2 that adds a comment saying why the count stays > out of i, if you'd like one. Right, that needs a bit more care but still, something like the attached patch should work? Honza -- Jan Kara <jack@suse.com> SUSE Labs, CR [-- Attachment #2: 0001-isofs-Simplify-isofs_read_level3_size.patch --] [-- Type: text/x-patch, Size: 2132 bytes --] From 8474b0d97f2c136f9870b85852e5b76bd4e4103e Mon Sep 17 00:00:00 2001 From: Jan Kara <jack@suse.cz> Date: Wed, 30 Sep 2026 12:28:56 +0200 Subject: [PATCH] isofs: Simplify isofs_read_level3_size() After recent changes it is possible to further simplify isofs_read_level3_size() by reorganizing the loop a bit and removing empty_blocks, block_saved, offset_saved variables. Signed-off-by: Jan Kara <jack@suse.cz> --- fs/isofs/inode.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index e884618c0c53..c8f0f8803a7b 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -1173,9 +1173,8 @@ static int isofs_read_level3_size(struct inode *inode) unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); int high_sierra = ISOFS_SB(inode->i_sb)->s_high_sierra; struct buffer_head *bh = NULL; - unsigned long block, offset, block_saved, offset_saved; + unsigned long block, offset; int i = 0; - int empty_blocks = 0; int more_entries = 0; struct iso_inode_info *ei = ISOFS_I(inode); @@ -1209,7 +1208,7 @@ static int isofs_read_level3_size(struct inode *inode) * chain of empty blocks could be walked without bound. */ if (offset >= bufsize || de->length[0] == 0) { - if (offset == 0 && ++empty_blocks + i > 100) + if (offset == 0 && ++i > 100) goto out_toomany; brelse(bh); bh = NULL; @@ -1225,21 +1224,17 @@ static int isofs_read_level3_size(struct inode *inode) return -EIO; } + /* Save the first continuation directory entry in the inode */ + if (more_entries && !ei->i_next_section_block) { + ei->i_next_section_block = block; + ei->i_next_section_offset = offset; + } de_len = de->length[0]; - block_saved = block; - offset_saved = offset; offset += de_len; - inode->i_size += isonum_733(de->size); - if (i == 1) { - ei->i_next_section_block = block_saved; - ei->i_next_section_offset = offset_saved; - } - more_entries = de->flags[-high_sierra] & 0x80; - i++; - if (i + empty_blocks > 100) + if (++i > 100) goto out_toomany; } while (more_entries); out: -- 2.51.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH] isofs: bound empty directory blocks in isofs_read_level3_size() 2026-09-30 10:33 ` Jan Kara @ 2026-10-01 10:30 ` Matthias Goergens 2026-10-02 10:55 ` Jan Kara 0 siblings, 1 reply; 13+ messages in thread From: Matthias Goergens @ 2026-10-01 10:30 UTC (permalink / raw) To: Jan Kara Cc: Hui Peng, Christian Brauner, Alexander Viro, linux-fsdevel, linux-kernel Hi Honza, > Right, that needs a bit more care but still, something like the attached > patch should work? Yes, it does. Testing the next-section link as "not yet set" instead of "i == 1" is what was missing from the first variant. I ran your patch on top of v1, built in userspace with ASan and UBSan, against 67 test images: empty blocks between and after the section records, three-section files, and the 100 bound from both sides. i_size, the recorded next section, the limit message and the file contents match v1 on every image, including the split-gap one your first variant read wrongly. No sanitizer reports. Reviewed-by: Matthias Goergens <matthias.goergens@gmail.com> Tested-by: Matthias Goergens <matthias.goergens@gmail.com> Thanks, Matthias ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] isofs: bound empty directory blocks in isofs_read_level3_size() 2026-10-01 10:30 ` Matthias Goergens @ 2026-10-02 10:55 ` Jan Kara 0 siblings, 0 replies; 13+ messages in thread From: Jan Kara @ 2026-10-02 10:55 UTC (permalink / raw) To: Matthias Goergens Cc: Jan Kara, Hui Peng, Christian Brauner, Alexander Viro, linux-fsdevel, linux-kernel On Thu 01-10-26 18:30:00, Matthias Goergens wrote: > Hi Honza, > > > Right, that needs a bit more care but still, something like the attached > > patch should work? > > Yes, it does. Testing the next-section link as "not yet set" instead > of "i == 1" is what was missing from the first variant. I ran your > patch on top of v1, built in userspace with ASan and UBSan, against 67 > test images: empty blocks between and after the section records, > three-section files, and the 100 bound from both sides. i_size, the > recorded next section, the limit message and the file contents match > v1 on every image, including the split-gap one your first variant read > wrongly. No sanitizer reports. > > Reviewed-by: Matthias Goergens <matthias.goergens@gmail.com> > Tested-by: Matthias Goergens <matthias.goergens@gmail.com> Thanks for review & testing! Honza -- Jan Kara <jack@suse.com> SUSE Labs, CR ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-10-02 10:55 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-09-19 22:25 [PATCH] isofs: reject short directory records in isofs_read_level3_size() Hui Peng 2026-09-23 17:52 ` Matthias Goergens 2026-09-24 15:03 ` Jan Kara 2026-09-24 15:13 ` Matthias Goergens 2026-09-25 4:38 ` Matthias Goergens 2026-09-25 9:28 ` Jan Kara 2026-09-25 11:22 ` Matthias Goergens 2026-09-26 8:35 ` [PATCH] isofs: bound empty directory blocks " Matthias Goergens 2026-09-29 10:57 ` Jan Kara 2026-09-30 3:39 ` Matthias Goergens 2026-09-30 10:33 ` Jan Kara 2026-10-01 10:30 ` Matthias Goergens 2026-10-02 10:55 ` Jan Kara
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox