Repository navigation
udf: Fix zero-length extent handling in udf_table_new_block() - #2954
Open
vfsci-bot[bot] wants to merge 1 commit into
Open
vfsci-bot[bot] wants to merge 1 commit into
vfsci-bot[bot] wants to merge 1 commit into
Conversation
udf_table_new_block() keeps the remaining extent length together with the extent type in goal_elen and then uses the whole value to decide whether the extent is empty: goal_elen = (etype << 30) | elen; ... goal_elen -= sb->s_blocksize; if (goal_elen) udf_write_aext(...); else udf_delete_aext(...); On a table-managed partition, free extents may have non-zero type bits. If such an extent has exactly one block left, subtracting the block leaves only the type bits (e.g. 0x40000000 for type 1). The test is still true, so instead of deleting the extent the function writes a zero-length extent at the next block back into the unallocated space table. Consider a free extent with type 1 and 9 blocks: lb=55, len=9 blocks (55..63) A new file is allocated from it at lb=55, so the extent becomes "lb=56, len=8 blocks". A huge write then extends the file with a hole. After the in-ICB allocation descriptor area fills, AED blocks 56..63 are allocated from this extent. When lb=63 is allocated, goal_elen is 0x40000200; after subtracting one block it becomes 0x40000000, so the extent is rewritten as lb=64, len=0, type=1 instead of being deleted. The next allocation with goal=63 prefers this zero-length extent (distance 1) over the real next extent "lb=65, len=31 blocks" (distance 2) and allocates lb=64 from it. Subtracting a block from the zero-length value borrows from the type field: 0x40000000 - 0x200 = 0x3FFFFE00 and writes back a bogus ~1GB extent: lb=65, len=0x3FFFFE00 which now overlaps the real free extent "lb=65, len=31 blocks". The next allocation with goal=64 picks the bogus extent first (both start at 65, the bogus one is encountered first and the search keeps the first minimum), so lb=65 is handed out and the bogus extent advances to lb=66. lb=65 is now the file's current AED. After 60 short_ad descriptors are appended to it, epos->offset is 504 and aed->lengthAllocDescs is 480. The next append enters udf_setup_indirect_aext(). The allocation goal is 65, and now the real extent "lb=65, len=31 blocks" wins: the goal lies inside it (distance 0), while the bogus extent has advanced to lb=66 (distance 1). udf_new_block() therefore returns 65 again, i.e. the block that is already the current AED. udf_setup_indirect_aext() then does: sb_getblk() returns the buffer of the current AED memset(bh->b_data, 0, sb->s_blocksize) -> clears aed->lengthAllocDescs Because epos->offset is still 504, the block is not considered full (504 + 8 <= 512) and the else branch calls __udf_add_aext(), which hits WARN_ON(aed->lengthAllocDescs != epos->offset - sizeof(struct allocExtDesc)) with lengthAllocDescs == 0 and offset == 504, i.e. 0 != 480. The AED contents are destroyed and the filesystem is corrupted. This is reachable by mounting a table-based UDF image with adinicb,shortad and writing at a very large offset: the write creates a huge hole, fills the in-ICB allocation descriptor area and then allocates many AED blocks from the unallocated space table. Reproducer is https://syzkaller.appspot.com/x/repro.c?x=16562e75180000. Fix it by testing only the extent length field. Fixes: 1da177e ("Linux-2.6.12-rc2") Reported-by: syzbot+799a0e744ac47f928024@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=799a0e744ac47f928024 Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Series: https://patchwork.kernel.org/project/linux-fsdevel/list/?series=1191331
Submitter: Zhihao Cheng
Version: 1
Patches: 1/1
Message-ID:
<20261022132603.2464065-1-chengzhihao1@huawei.com>Base: vfs.base.ci
Lore: https://lore.kernel.org/linux-fsdevel/20261022132603.2464065-1-chengzhihao1@huawei.com
Automated by ml2pr