Linux filesystem development
 help / color / mirror / Atom feed
* [PATCH v2 0/4] udf: fix double allocation from the unallocated space table
@ 2026-10-30 14:05 Matthias Goergens
  2026-10-30 14:05 ` [PATCH v2 1/4] udf: don't let the extent type hide an exhausted free-space table extent Matthias Goergens
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Matthias Goergens @ 2026-10-30 14:05 UTC (permalink / raw)
  To: Jan Kara
  Cc: linux-fsdevel, linux-kernel, syzbot+799a0e744ac47f928024,
	syzbot+43fc5ba6dcb33e3261ca, syzkaller-bugs

Hi Honza,

Patch 3 now fixes udf_discard_prealloc() the way you suggested, and
udf_next_aext() is left alone.  Its Fixes: tag now names the commit that
added the peek into eloc and elen there.  The two other users that v1
covered through udf_next_aext(), both walks of the unallocated space
table, are fixed directly in patch 4.  The code in patch 1 is unchanged,
and patch 2 only rewords one code comment.  The messages now make the
mount and stable-backport consequences explicit.

A filesystem made with "mkudffs --space=unalloctable" hands out blocks
that are still in use.

Patch 1: udf_table_new_block() keeps the extent type in the length
word, so an exhausted type-1 table extent (the type mkudffs writes)
survives as a zero-length extent pointing at an in-use block, and the
next allocation from it underflows into about a gigabyte of "free"
space.  Filling a fresh 1 MiB image with empty files is enough to
overwrite the reserve VDS and the backup anchor.  This is the double
allocation behind the two syzbot reports linked in the patch.

Patch 2 checks the table once at mount and refuses read-write access
if it is damaged, for example by the bug in patch 1.

Patches 1 and 2 should be taken together.  Patch 1 prevents the
allocator from creating new empty extents.  Patch 2 rejects an empty
entry left by an old kernel before it can be consumed again.  It also
rejects extents outside the partition.  It cannot detect every possible
overlap in a table that is already damaged.

Patch 3: when a file's extent list ends in an empty allocation extent,
udf_discard_prealloc() frees that allocation extent's block a second
time instead of the preallocated blocks.  On a table the block is then
handed out twice, and fsx, as run by generic/091 and generic/263,
reads back bad data, with or without patches 1 and 2.  On a bitmap the
preallocated blocks leak.

Patch 4: udf_table_prealloc_blocks() can hand out the block of an
empty allocation extent at the end of the table.  With patch 3 alone,
the reproducer below patch 3 passes, but generic/091 or 263 failed in
8 of 34 runs on the 2 October base.  udf_table_free_blocks() can
write a partition reference it never set; that one I have not
reproduced.

One more user is left as it is: udf_fiiter_add_entry() takes the last
extent of a directory from iter->eloc and iter->elen after inode_bmap()
has returned 0 in udf_fiiter_init().  That goes wrong only if the
directory's extent list ends in an empty allocation extent.  The kernel
does not create one for a directory: udf_bread() passes
UDF_MAP_NOPREALLOC when it allocates directory blocks.  Normal updates
to a live directory do not shrink its extent list.

On the 2 October base (4ad934e7a85e), with the whole series, one run of
fstests -g quick per allocation type (2 GiB images made with
--space=unalloctable or --space=unallocbitmap; KASAN, UBSAN and lockdep
enabled) passed generic/091 and generic/263 on a table.  The remaining
failures (generic/131, 360, 563, 634 and 777, and a hang in generic/346)
also appeared without the series and on a bitmap, where the series
changed no result in those runs.  The reproducers are below the --- of
patches 1 and 3, and the runs behind patch 4 below its own.

Thanks,
Matthias


---
v1:
https://lore.kernel.org/r/20261002042627.1677228-1-matthias.goergens@gmail.com/

For stable: patches 2, 3 and 4 build on the int return of udf_next_aext()
(b405c1e58b73, v6.12, also backported to 6.6.y) and apply as they are
to 6.6.y and later.  Patches 1 and 2 should be backported together.

Refreshed onto jack/linux-fs for_next as of 30 October.  The four code
diffs are unchanged; the messages include the clarifications above.

I repeated the inline fsx reproducer on this base and the whole series,
with KASAN, UBSAN and lockdep enabled.  On a table, both fresh base
VMs read back bad data at operation 9852; both fixed VMs completed all
10000 operations.  On a bitmap, one fresh VM with each kernel completed
all operations.  In one fresh-image generic/091 and generic/263 group
per kernel, both tests read back bad data on base and both passed with
the series.  No kernel report appeared in these runs.

On the 30 September base, the unchanged patch 2 code also rejected a
crafted looping allocation-extent chain, forced read-only fallback when
the table location held a file entry, and let SIGKILL interrupt the walk
when a test-only knob disabled cycle detection.  Those malformed-image
checks were not repeated on the 30 October base.


Matthias Goergens (4):
  udf: don't let the extent type hide an exhausted free-space table
    extent
  udf: check the unallocated space table when it is loaded
  udf: fix preallocation discarding before an empty allocation extent
  udf: don't use eloc after the end of the unallocated space table

 fs/udf/balloc.c   | 11 ++++---
 fs/udf/super.c    | 80 ++++++++++++++++++++++++++++++++++++++++++++++-
 fs/udf/truncate.c |  7 +++--
 3 files changed, 90 insertions(+), 8 deletions(-)


base-commit: a344542d9f26d44a5ebf597220ccac84c536467e
-- 
2.56.0


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

end of thread, other threads:[~2026-10-30 14:05 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-30 14:05 [PATCH v2 0/4] udf: fix double allocation from the unallocated space table Matthias Goergens
2026-10-30 14:05 ` [PATCH v2 1/4] udf: don't let the extent type hide an exhausted free-space table extent Matthias Goergens
2026-10-30 14:05 ` [PATCH v2 2/4] udf: check the unallocated space table when it is loaded Matthias Goergens
2026-10-30 14:05 ` [PATCH v2 3/4] udf: fix preallocation discarding before an empty allocation extent Matthias Goergens
2026-10-30 14:05 ` [PATCH v2 4/4] udf: don't use eloc after the end of the unallocated space table Matthias Goergens

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