[PATCH v2 0/2] hfs, hfsplus: validate the partition map and wrapper before following them

From: Matthias Goergens

Date: Thu Oct 01 2026 - 12:21:49 EST


hfs_mdb_get() and hfsplus_read_wrapper() reread the volume header in a
loop, following a partition map entry and, in hfsplus, an HFS wrapper's
embedded-volume descriptor. An entry or descriptor with a zero offset
sends the loop back to the header it has just read, and a crafted image
hangs the mount.

v2 checks the offsets where they are parsed, in hfs_part_find() and
hfsplus_read_mdb(), as Slava suggested: a partition must start inside
the device and after a new-style partition map (TN1189), and a wrapper's
embedded volume must lie within its allocation blocks, which start after
its MDB (TN1150).

Every hop now moves past what it was read from, so the loop ends and the
work it does is linear in the size of the device. For a new-style map,
a non-zero start alone would not be enough. Take a map entry in every
block, all of type Apple_Free with a large pmMapBlkCnt, and one
Apple_HFS entry near the end with pmPyPartStart 2: each two-block hop
then rescans the map up to that entry. With a check on the start alone,
an hfsplus mount of an 8 MiB image built like this was still busy after
ten minutes; with these patches it fails in about a second. Chains of
small hops remain possible when each map has a single entry, and a
64 MiB image of two-block hops takes about three seconds to fail under
QEMU, the same as without these patches. If that should be bounded as
well, v1's limit of one hop of each kind could go on top. The
generator for these images, with timings for an unpatched kernel and
for these patches, is at

https://github.com/matthiasgoergens/linux/tree/reproducer/2026-09-30-hfs-part-sanity-v2

Under QEMU, v1's reproducers now fail at once. Plain, wrapped and
partitioned volumes made with newfs_hfs still mount, with maps written
by parted or, for the old-style format, by hand. So do hybrid CD images
from genisoimage -hfs and xorriso -hfsplus. Wrappers written by
newfs_hfs -w, for volumes up to 31 GB, pass the new check.

Changes in v2:
- Check the entries in hfs_part_find() and the wrapper in
hfsplus_read_mdb() instead of limiting the number of hops (Slava).
- hfs: stop at the first matching old-style ("TS") map entry, as
hfsplus already does, so that the start returned is one that was
checked.

v1: https://lore.kernel.org/all/20260926084010.569552-1-matthias.goergens@xxxxxxxxx/

Matthias Goergens (2):
hfs: validate partition map entries in hfs_part_find()
hfsplus: validate the wrapper and partition map before following them

fs/hfs/part_tbl.c | 27 ++++++++++++++++++++++++++-
fs/hfsplus/part_tbl.c | 24 +++++++++++++++++++++++-
fs/hfsplus/wrapper.c | 16 +++++++++++++++-
include/linux/hfs_common.h | 1 +
4 files changed, 65 insertions(+), 3 deletions(-)


base-commit: 6812ce4e4379ffc99c52401ec28f0d7ffbc36206
--
2.55.0