summaryrefslogtreecommitdiff
path: root/fs/hfsplus
AgeCommit message (Collapse)Author
11 daysMerge tag 'hfs-v7.3-tag1' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs Pull HFS updates from Viacheslav Dubeyko: "This contains several fixes in HFS/HFS+ of syzbot reported issues and HFS/HFS+ fixes of xfstests failures. - b-tree bitmap corruption check (Aditya Prakash Srivastava) During b-tree open (hfs_btree_open()), the code verifies that the allocation map bit for the tree header (node 0) is set. If not, it indicates a corrupted map record/bitmap and mounts the volume as read-only (SB_RDONLY) to prevent further damage. - Validate catalog CNIDs before instantiating inodes (David Maximiliano Hermitte) The hfs_cat_find_brec() first resolves a catalog thread record by CNID and then looks up the corresponding catalog record by parent/name. On a corrupted filesystem image, the second lookup may find a record whose CNID does not match the CNID that was requested. Finally, corrupted catalog records are rejected. - Validate B-tree record offset table (Jiaming Zhang) A crafted HFS+ image can contain a corrupted B-tree node. The node descriptor may contain a record count that does not fit in the node, and record offsets may be unordered, unaligned, outside the node, or point into the offset table itself. Validate num_recs against the node size before walking the record offset table. Reject record ranges that are unordered, unaligned, outside the node, or overlapping the offset table. Reject invalid record indexes before reading their offset entries, and avoid decrementing an already-zero leaf_count. - Refactoring of hfsplus_delete_cat() logic (Kyle Zeng). The hfsplus_delete_cat() is called with str == NULL when the last open reference to an unlinked HFS+ hardlink backing inode is closed. In that case, the function finds the catalog thread by CNID and rebuilds the catalog key from thread.nodeName. A corrupted image can therefore provide an oversized thread name length and make hfs_bnode_read() write past the catalog search-key allocation. Read the CNID record through hfsplus_brec_read_cat(), which bounds the record read to sizeof(hfsplus_cat_entry) and verifies that a thread record's size exactly matches nodeName.length. - Cleanup in KUnit test (Mohammad Shahid) The kfree() safely handles NULL pointers, so the explicit NULL check in free_mock_str_env() before calling kfree() is unnecessary. The rest contain fixes of generic/564 xfstests' test-case failure for the case of HFS+ file system, syzbot reported issue in hfs_mdb_commit() and hfs_mdb_close() methods of HFS file system, and reworking the MDB locking scheme in HFS file system" * tag 'hfs-v7.3-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs: hfsplus: validate extent record length before writing it back hfsplus: validate B-tree record offset table hfs: rework MDB locking scheme fs: hfsplus: remove redundant NULL check before kfree() hfs: port HFS+ b-tree bitmap corruption check hfs: don't re-dirty MDB buffers after a write failure hfsplus: fix error code when writing beyond volume capacity hfs: fix error code when writing beyond volume capacity hfsplus: validate thread record before delete key rebuild hfs: validate catalog CNIDs before instantiating inodes
11 daysMerge tag 'vfs-7.3-rc1.misc' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs Pull misc vfs updates from Christian Brauner: "Bigger cleanups: - The lockref dead-count handling is tidied up. The open-coded check for a count below zero as the dead marker relies on information the caller should not have. - make put_mnt_ns() leave mounts connected. Destroying a mount namespace disconnected its mounts from their mount points. So a file descriptor still open on the parent of a mount point could be used to peek under it. Locked mounts were already kept connected to prevent exactly that. But a mount is only locked when its tree is copied across a user namespace boundary. So a mount namespace set up by a privileged component had no locked mounts and its mounts were disconnected. Passing UMOUNT_CONNECTED keeps every mount connected and prevents that bug. - vfs_prepare_mode() passes S_IFDIR for directories. I meant to fix that ago but didn't get to it. So now someone finally did it. This kills the exception where the mode could be 0 when a directory was created whereas every other creation operation passed it explicitly already. - move long delayed work for ufs, jffs2, hfsplus, hfs and affs from the per-cpu system_long_wq to the new unbound system_dfl_long_wq. None of that work relies on per-cpu state and the work item is enqueued with queue_delayed_work() whose timer is global anyway. So it may as well benefit from scheduler task placement. Smaller fixes and cleanups: - unlock_buffer() and journal_end_buffer_io_sync() use clear_and_wake_up_bit() - the pipe page pools are unified into a single per-pipe pool and the extra wake_up(rd_wait) is limited to EPOLLET consumers - eventpoll now computes its timer slack lazily in ep_poll() - shrink_dcache_for_umount() keeps making progress on busy roots - excess xarray nodes are freed in clear_inode() - romfs detects hard link cycles - the user path of nested backing files is fixed - pidfd holds exec_update_lock around the namespace ioctl - non-memcg-aware nr_cached_objects is skipped during memcg slab shrink - iomap_write_iter() always returns status - mangle_path() is renamed to seq_mangle_path() - inode timestamp accessors are annotated - new regression test for pipe->poll_usage. - a few documentation, kernel-doc and selftest fixes" * tag 'vfs-7.3-rc1.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (67 commits) selftests/namespaces: Fix racy pipe handshake in timens and pidns_separate selftests/epoll: add a regression test for pipe->poll_usage pipe: only enable the extra wake_up(rd_wait) for EPOLLET consumers pidfd: hold exec_update_lock around namespace ioctl fs: fix user path of nested backing files fs: remove stale inode_insert5() kernel-doc parameter fs: fix switch/case indentation in sysfs() syscall fs: document semantics of kstat::{uid,gid} fields dcache: keep shrink_dcache_for_umount() making progress on busy roots seq_file: rename mangle_path to seq_mangle_path nstree: add/fix struct ns_id_req kernel-doc member fields dcache: use lockref routines for dead count checks lockref: tidy up dead count handling initramfs: fix typo in reserve_initrd_mem comment fs/pipe: unify the page pools into a single per-pipe pool fs: annotate inode timestamp accessors eventpoll: compute timer slack lazily in ep_poll() selftests/filesystems: add mntns cleanup test put_mnt_ns(): leave mounts connected affs: Move long delayed work on system_dfl_long_wq ...
2026-08-11hfsplus: validate extent record length before writing it backJiaming Zhang
__hfsplus_ext_write_extent() writes the cached extent record back into a B-tree node using fd->entrylength as the length, and fd->entrylength is derived in __hfs_brec_find() from two on-disk values: fd->entrylength = len - keylen; A crafted image can keep both len and keylen valid but make fd->entrylength negative (keylen > len). __hfsplus_ext_write_extent() doesn't check fd->entrylength before consuming it, and hfs_bnode_write() takes the length as u32, so the negative value turns into a huge one. The copy then reads data past the end of hip->cached_extents, which is only sizeof(hfsplus_extent_rec) bytes long, and leaks kernel memory into the image. Reject an fd->entrylength that does not match sizeof(hfsplus_extent_rec) in __hfsplus_ext_write_extent(), mirroring the check already performed in __hfsplus_ext_read_extent(). Link: https://lore.kernel.org/lkml/cbd7003314c530d4f910eacf019ff80adad6687e.camel@dubeyko.com/ Signed-off-by: Jiaming Zhang <r772577952@gmail.com> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260810092422.1691377-1-r772577952@gmail.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-08-11hfsplus: validate B-tree record offset tableJiaming Zhang
A crafted HFS+ image can contain a corrupted B-tree node. The node descriptor may contain a record count that does not fit in the node, and record offsets may be unordered, unaligned, outside the node, or point into the offset table itself. Several B-tree helpers consume these on-disk fields before validating them: hfs_bnode_dump() can walk past the offset table when num_recs is corrupted, hfs_brec_lenoff() can produce an underflowed length or a record range that overlaps the offset table. This can make the unlink/writeback path repeatedly call hfs_bnode_read_u16() with invalid offsets while holding the HFS+ B-tree lock, producing a flood of "requested invalid offset" messages. Other writeback workers then block on tree->tree_lock and the system reports tasks hung in hfsplus_write_inode(). Validate num_recs against the node size before walking the record offset table. Reject record ranges that are unordered, unaligned, outside the node, or overlapping the offset table. Reject invalid record indexes before reading their offset entries, and avoid decrementing an already-zero leaf_count. Closes: https://lore.kernel.org/lkml/CANypQFb_2TqKGrztAXj5m0_v+QChxXDnQVeifzV8J25Vuju10Q@mail.gmail.com/ Assisted-by: Codex:gpt-5.5-xhigh Signed-off-by: Jiaming Zhang <r772577952@gmail.com> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Tested-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260806073358.1184938-1-r772577952@gmail.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-07-31Remove excl arg to ->create inode_operationNeilBrown
The only time that 'false' is passed as the 'excl' arg to the ->create inode_operation is in lookup_open() when ->atomic_open is not provided by the parent directory. *all* directory inode_operations which do not have ->atomic_open completely ignore the 'excl' arg. Therefore we don't need the 'excl' arg. Those few ->create operations which pay attention to the arg are only ever called with a value of 'true'. We remove that arg and change all ->create operations to behave as those thhe arg were 'true'. Signed-off-by: NeilBrown <neil@brown.name> Link: https://patch.msgid.link/178290671516.27465.15984496764174914338@noble.neil.brown.name Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-31hfsplus: Move long delayed work on system_dfl_long_wqMarco Crivellari
Currently the code enqueue work items using {queue|mod}_delayed_work(), using system_long_wq. This workqueue should be used when long works are expected and it is a per-cpu workqueue. The function(s) end up calling __queue_delayed_work(), which set a global timer that could fire anywhere, enqueuing the work where the timer fired. Unbound works could benefit from scheduler task placement, to optimize performance and power consumption. Long work shouldn't stick to a single CPU. Recently, a new unbound workqueue specific for long running work has been added:     c116737e972e ("workqueue: Add system_dfl_long_wq for long unbound works") Since the workqueue work doesn't rely on per-cpu variables, there is no obvious reason that justify the use of a per-cpu workqueue. So change system_long_wq with system_dfl_long_wq so that the work may benefit from scheduler task placement. Cc: Viacheslav Dubeyko <slava@dubeyko.com> Cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> Cc: Yangtao Li <frank.li@vivo.com> Cc: linux-fsdevel@vger.kernel.org Signed-off-by: Marco Crivellari <marco.crivellari@suse.com> Link: https://patch.msgid.link/20260706105443.173697-4-marco.crivellari@suse.com Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27fs: hfsplus: remove redundant NULL check before kfree()Mohammad Shahid
kfree() safely handles NULL pointers, so the explicit NULL check before calling kfree() is unnecessary. This issue was reported by ifnullfree.cocci. Signed-off-by: Mohammad Shahid <mdshahid03@gmail.com> Link: https://lore.kernel.org/r/20260726064228.248199-1-mdshahid03@gmail.com Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-07-14hfsplus: fix error code when writing beyond volume capacityViacheslav Dubeyko
The xfstests' test-case generic/564 fails for the case of HFS+ file system. Test-case expects that file system driver reports -EFBIG error code in the case if there is the effort to write beyond 8TiB. However, HFS+ file system driver returns -ENOSPC instead. The root cause is that hfsplus_fill_super() sets s_maxbytes as MAX_LFS_FILESIZE. VFS therefore considers the write position valid and calls into the filesystem. Because HFS+ does not support holes, cont_write_begin() zero-fills the entire intermediate range from the current end-of-file to the target offset. On a small test volume this exhausts free space long before any block-number overflow is detected, producing -ENOSPC instead of -EFBIG. This patch fixes the issue by adding a bounds check at the top of hfsplus_write_begin(). If the requested write position is at or beyond the actual capacity of the volume in bytes, return -EFBIG immediately before cont_write_begin() is entered and before any zero-fill I/O is attempted. sudo ./check generic/564 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.2.0-rc1-dirty #50 SMP PREEMPT_DYNAMIC Fri Jul 3 16:22:27 PDT 2026 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/564 13s ... 43s Ran: generic/564 Passed all 1 tests cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260706221738.140271-2-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-07-14hfsplus: validate thread record before delete key rebuildKyle Zeng
hfsplus_delete_cat() is called with str == NULL when the last open reference to an unlinked HFS+ hardlink backing inode is closed. In that case, the function finds the catalog thread by CNID and rebuilds the catalog key from thread.nodeName. That reconstruction path reads thread.nodeName.length directly from the catalog B-tree into fd.search_key and then copies length * 2 bytes into fd.search_key->cat.name.unicode. It does not first check that the found record is a thread record or that its size matches the thread name. A corrupted image can therefore provide an oversized thread name length and make hfs_bnode_read() write past the catalog search-key allocation. Read the CNID record through hfsplus_brec_read_cat(), which bounds the record read to sizeof(hfsplus_cat_entry) and verifies that a thread record's size exactly matches nodeName.length. Together, these checks ensure an accepted thread name fits HFSPLUS_MAX_STRLEN. Reject non-thread records before building the delete key from the validated thread name. Share the thread-record-type helper between hfsplus_find_cat() and hfsplus_delete_cat(). Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Assisted-by: Codex:gpt-5.6 Signed-off-by: Kyle Zeng <kylebot@openai.com> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260709010203.49664-1-kylebot@openai.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-07-01hfsplus: drop redundant S_IFDIR from mkdirJori Koolstra
vfs_mkdir() now sets the S_IFDIR type bit in the mode it passes to ->mkdir(), so OR-ing S_IFDIR into the mode again in hfsplus_mkdir() is redundant. Drop it. Assisted-by: LLM Signed-off-by: Jori Koolstra <jkoolstra@xs4all.nl> Link: https://patch.msgid.link/20260630105400.68459-14-jkoolstra@xs4all.nl Reviewed-by: NeilBrown <neil@brown.name> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-06-16Merge tag 'hfs-v7.2-tag1' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs Pull hfs/hfsplus updates from Viacheslav Dubeyko: "Several fixes in HFS/HFS+ of syzbot reported issues and HFS//HFS+ fixes of xfstests failures. - fix a null-ptr-deref issue reported by syzbot (Edward Adam Davis) If the attributes file is not loaded during system mount hfsplus_create_attributes_file can dereference a NULL pointer. Also, add a b-tree node size check in hfs_btree_open() with the goal to prevent an uninit-value bug reported by syzbot for the case of corrupted HFS+ image. - fix __hfs_bnode_create() by using kzalloc_flex() instead of kzalloc() (Rosen Penev) - fix early return in hfs_bnode_read() (Tristan Madani) hfs_bnode_read() can return early without writing to the output buffer when is_bnode_offset_valid() fails or when check_and_correct_requested_ length() corrects the length to zero. Callers such as hfs_bnode_read_ u16() and hfs_bnode_read_u8() pass stack-allocated buffers and use the result unconditionally, leading to KMSAN uninit-value reports. The rest fix (1) generic/637, generic/729 issue for the case of HFS+ file system, (2) generic/003, generic/637 for the case of HFS file system" * tag 'hfs-v7.2-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs: hfs: rework hfsplus_readdir() logic hfs: disable the updating of file access times (atime) hfs: fix incorrect inode ID assignment in hfs_new_inode() hfsplus: rework hfsplus_readdir() logic hfs/hfsplus: zero-initialize buffer in hfs_bnode_read hfs/hfsplus: fix u32 overflow in check_and_correct_requested_length hfsplus: Add a sanity check for btree node size hfsplus: fix issue of direct writes beyond end-of-file hfs/hfxplus: use kzalloc_flex() hfsplus: Remove the duplicate attr inode dirty marking action
2026-05-11hfsplus: rework hfsplus_readdir() logicViacheslav Dubeyko
The xfstests' test-case generic/637 fails with error: FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.15.0-rc4+ #8 SMP PREEMPT_DYNAMIC Thu May 1 16:43:22 PDT 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch QA output created by 637 entries 7 and 8 have duplicate d_off 8 Found unlinked files in open dir (see xfstests-dev/results//generic/637.full for details) Debugging of the hfsplus_readdir() logic showed this: hfsplus: hfsplus_readdir(): 163 ctx->pos 0 hfsplus: hfsplus_readdir(): 189 ctx->pos 1 hfsplus: hfsplus_readdir(): 264 ctx->pos 2, ino 18 hfsplus: hfsplus_readdir(): 264 ctx->pos 3, ino 19 hfsplus: hfsplus_readdir(): 264 ctx->pos 4, ino 28 hfsplus: hfsplus_readdir(): 264 ctx->pos 5, ino 118 hfsplus: hfsplus_readdir(): 264 ctx->pos 6, ino 29 hfsplus: hfsplus_readdir(): 264 ctx->pos 7, ino 30 hfsplus: hfsplus_readdir(): 264 ctx->pos 8, ino 31 hfsplus: hfsplus_readdir(): 304 ctx->pos 8 hfsplus: hfsplus_unlink():420 dir->i_ino 17, inode->i_ino 28 hfsplus: hfsplus_readdir(): 141 ctx->pos 7 hfsplus: hfsplus_readdir(): 264 ctx->pos 7, ino 31 hfsplus: hfsplus_readdir(): 264 ctx->pos 8, ino 32 hfsplus: hfsplus_readdir(): 264 ctx->pos 9, ino 33 It means that hfsplus_readdir() stopped the processing of folder's items on ctx->pos 8, then, item with ino 28 has been deleted and hfsplus_readdir() re-started the logic from ctx->pos 7. As a result, previous and new sets of folder's items have overlapping values for the case of d_off 8. Currently, HFS+ has very complicated and fragile logic of rd->file->f_pos correction in hfsplus_delete_cat(). This patch removes this logic and it stores the current pos into hfsplus_readdir_data. Finally, if rd->pos == ctx->pos then hfsplus_readdir() tries to find the position in b-tree's node by means of hfsplus_cat_key. This position is used to re-start the folder's content traversal. sudo ./check generic/637 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.1.0-rc1+ #44 SMP PREEMPT_DYNAMIC Mon May 4 15:58:45 PDT 2026 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/637 22s ... 22s Ran: generic/637 Passed all 1 tests Closes: https://github.com/hfs-linux-kernel/hfs-linux-kernel/issues/198 cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260505220051.2854696-2-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-05-11hfsplus: Report case sensitivity in fileattr_getChuck Lever
Add case sensitivity reporting to the existing hfsplus_fileattr_get() function via the FS_XFLAG_CASEFOLD flag. HFS+ always preserves case at rest. Case sensitivity depends on how the volume was formatted: HFSX volumes may be either case-sensitive or case-insensitive, indicated by the HFSPLUS_SB_CASEFOLD superblock flag. FS_XFLAG_CASEFOLD is read-only: FS_XFLAG_RDONLY_MASK ensures FS_IOC_FSSETXATTR strips it. The legacy FS_IOC_SETFLAGS path in hfsplus_fileattr_set() also allows FS_CASEFOLD_FL through its allowlist on case-insensitive volumes so that a chattr read-modify-write cycle does not fail with EOPNOTSUPP. Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Reviewed-by: Roland Mainz <roland.mainz@nrubsig.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Link: https://patch.msgid.link/20260507-case-sensitivity-v14-7-e62cc8200435@oracle.com Signed-off-by: Christian Brauner <brauner@kernel.org>
2026-05-07hfs/hfsplus: zero-initialize buffer in hfs_bnode_readTristan Madani
hfs_bnode_read() can return early without writing to the output buffer when is_bnode_offset_valid() fails or when check_and_correct_requested_ length() corrects the length to zero. Callers such as hfs_bnode_read_ u16() and hfs_bnode_read_u8() pass stack-allocated buffers and use the result unconditionally, leading to KMSAN uninit-value reports. Rather than initializing at each individual call site, zero the buffer at the start of hfs_bnode_read() before any validation checks. This ensures all callers in both hfs and hfsplus get a deterministic zero value regardless of which early-return path is taken. Reported-by: syzbot+217eb327242d08197efb@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=217eb327242d08197efb Tested-by: syzbot+217eb327242d08197efb@syzkaller.appspotmail.com Fixes: a431930c9bac ("hfs: fix slab-out-of-bounds in hfs_bnode_read()") Cc: stable@vger.kernel.org Signed-off-by: Tristan Madani <tristan@talencesecurity.com> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260505111300.3592757-3-tristmd@gmail.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-05-07hfs/hfsplus: fix u32 overflow in check_and_correct_requested_lengthTristan Madani
check_and_correct_requested_length() compares (off + len) against node_size using u32 arithmetic. When the caller passes a large len value (e.g. from an underflowed subtraction in hfs_brec_remove()), off + len can wrap past 2^32 and produce a small result, causing the bounds check to pass when it should fail. For example, with off=14 and len=0xFFFFFFF2 (underflowed from data_off - keyoffset - size in hfs_brec_remove), off + len wraps to 6, which is less than a typical node_size of 512, so the check passes and the subsequent memmove reads ~4GB past the node buffer. Fix this by widening the addition to u64 before comparing against node_size. This prevents the u32 wrap while keeping the logic straightforward. Reported-by: syzbot+6df204b70bf3261691c5@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=6df204b70bf3261691c5 Tested-by: syzbot+6df204b70bf3261691c5@syzkaller.appspotmail.com Reported-by: syzbot+e76bf3d19b85350571ac@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=e76bf3d19b85350571ac Tested-by: syzbot+e76bf3d19b85350571ac@syzkaller.appspotmail.com Fixes: a431930c9bac ("hfs: fix slab-out-of-bounds in hfs_bnode_read()") Cc: stable@vger.kernel.org Signed-off-by: Tristan Madani <tristan@talencesecurity.com> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260505111300.3592757-2-tristmd@gmail.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-04-27hfsplus: Add a sanity check for btree node sizeEdward Adam Davis
Syzbot reported an uninit-value bug in [1] with a corrupted HFS+ image, during the file system mounting process, specifically while loading the catalog, a corrupted node_size value of 1 caused the rec_off argument passed to hfs_bnode_read_u16() (within hfs_bnode_find()) to be excessively large. Consequently, the function failed to return a valid value to initialize the off variable, triggering the bug [1]. Every node starts from BTree node descriptor: struct hfs_bnode_desc. So, the size of node cannot be lesser than that. However, technical specification declares that: "The node size (which is expressed in bytes) must be power of two, from 512 through 32,768, inclusive." Add a check for btree node size base on technical specification. [1] BUG: KMSAN: uninit-value in hfsplus_bnode_find+0x141c/0x1600 fs/hfsplus/bnode.c:584 hfsplus_bnode_find+0x141c/0x1600 fs/hfsplus/bnode.c:584 hfsplus_btree_open+0x169a/0x1e40 fs/hfsplus/btree.c:382 hfsplus_fill_super+0x111f/0x2770 fs/hfsplus/super.c:553 get_tree_bdev_flags+0x6e6/0x920 fs/super.c:1694 get_tree_bdev+0x38/0x50 fs/super.c:1717 hfsplus_get_tree+0x35/0x40 fs/hfsplus/super.c:709 vfs_get_tree+0xb3/0x5d0 fs/super.c:1754 fc_mount fs/namespace.c:1193 [inline] Fixes: 8ad2c6a36ac4 ("hfsplus: validate b-tree node 0 bitmap at mount time") Reported-by: syzbot+217eb327242d08197efb@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=217eb327242d08197efb Signed-off-by: Edward Adam Davis <eadavis@qq.com> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/tencent_5ED373437A697F83A4A446B771577626CD05@qq.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-04-27hfsplus: fix issue of direct writes beyond end-of-fileViacheslav Dubeyko
The xfstests' test-case generic/729 fails with error: sudo ./check generic/729 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #36 SMP PREEMPT_DYNAMIC Fri Apr 17 12:40:51 PDT 2026 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/729 23s ... [failed, exit status 1]- output mismatch mmap-rw-fault: /mnt/test/mmap-rw-fault.tmp: Input/output error The hfsplus_get_block() only allows creating the next sequential block. It returns -EIO for direct writes beyond EOF. This patch waits for any in-flight DIO on the inode to finish. Then, it extends the file by calling generic_cont_expand_simple() with the goal to guarantee that blockdev_direct_IO() finds all needed blocks already reachable sequentially. And, finally, it flushes and invalidates the DIO range again so the page cache is clean before the direct write begins. sudo ./check generic/729 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #40 SMP PREEMPT_DYNAMIC Thu Apr 16 15:41:03 PDT 2026 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/729 23s ... 32s Ran: generic/729 Passed all 1 tests Closes: https://github.com/hfs-linux-kernel/hfs-linux-kernel/issues/210 cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260417214940.2735557-2-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-04-27hfs/hfxplus: use kzalloc_flex()Rosen Penev
Instead of doing the math manually, use kzalloc_flex() which does it in a cleaner way. Also clarifies which is the flexible array member. Signed-off-by: Rosen Penev <rosenp@gmail.com> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260425014441.441252-1-rosenp@gmail.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-04-27hfsplus: Remove the duplicate attr inode dirty marking actionEdward Adam Davis
Syzbot reported a null-ptr-deref in [1]. If the attributes file is not loaded during system mount, a trigger occurs [1] when setxattr is executed in userspace. Remove the first mark attr inode dirty operation. [1] KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] Call Trace: hfsplus_setxattr+0x124/0x340 fs/hfsplus/xattr.c:555 hfsplus_trusted_setxattr+0x40/0x60 fs/hfsplus/xattr_trusted.c:30 __vfs_setxattr+0x43c/0x480 fs/xattr.c:218 __vfs_setxattr_noperm+0x12d/0x660 fs/xattr.c:252 vfs_setxattr+0x163/0x360 fs/xattr.c:339 do_setxattr fs/xattr.c:654 [inline] Reported-by: syzbot+bc70a12e438dadba4fb4@syzkaller.appspotmail.com Fixes: ee8422d00b7c ("hfsplus: fix potential Allocation File corruption after fsync") Closes: https://syzkaller.appspot.com/bug?extid=bc70a12e438dadba4fb4 Signed-off-by: Edward Adam Davis <eadavis@qq.com> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/tencent_A8D47429765566CC3C8B378496D036664A09@qq.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-04-13Merge tag 'hfs-v7.1-tag1' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs Pull hfsplus updates from Viacheslav Dubeyko: "This contains several fixes of syzbot reported issues and HFS+ fixes of xfstests failures. - Fix a syzbot reported issue of a KMSAN uninit-value in hfsplus_strcasecmp(). The root cause was that hfs_brec_read() doesn't validate that the on-disk record size matches the expected size for the record type being read. The fix introduced hfsplus_brec_read_cat() wrapper that validates the record size based on the type field and returns -EIO if size doesn't match (Deepanshu Kartikey) - Fix a syzbot reported issue of processing corrupted HFS+ images where the b-tree allocation bitmap indicates that the header node (Node 0) is free. Node 0 must always be allocated. Violating this invariant leads to allocator corruption, which cascades into kernel panics or undefined behavior. Prevent trusting a corrupted allocator state by adding a validation check during hfs_btree_open(). If corruption is detected, print a warning identifying the specific corrupted tree and force the filesystem to mount read-only (SB_RDONLY). This prevents kernel panics from corrupted images while enabling data recovery (Shardul Bankar) - Fix a potential deadlock in hfsplus_fill_super(). hfsplus_fill_super() calls hfs_find_init() to initialize a search structure, which acquires tree->tree_lock. If the subsequent call to hfsplus_cat_build_key() fails, the function jumps to the out_put_root error label without releasing the lock. Fix this by adding the missing hfs_find_exit(&fd) call before jumping to the out_put_root error label. This ensures that tree->tree_lock is properly released on the error path (Zilin Guan) - Update a files ctime after rename in hfsplus_rename() (Yangtao Li) The rest of the patches introduce the HFS+ fixes for the case of generic/348, generic/728, generic/533, generic/523, and generic/642 test-cases of xfstests suite" * tag 'hfs-v7.1-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs: hfsplus: fix generic/642 failure hfsplus: rework logic of map nodes creation in xattr b-tree hfsplus: fix logic of alloc/free b-tree node hfsplus: fix error processing issue in hfs_bmap_free() hfsplus: fix potential race conditions in b-tree functionality hfsplus: extract hidden directory search into a helper function hfsplus: fix held lock freed on hfsplus_fill_super() hfsplus: fix generic/523 test-case failure hfsplus: validate b-tree node 0 bitmap at mount time hfsplus: refactor b-tree map page access and add node-type validation hfsplus: fix to update ctime after rename hfsplus: fix generic/533 test-case failure hfsplus: set ctime after setxattr and removexattr hfsplus: fix uninit-value by validating catalog record size hfsplus: fix potential Allocation File corruption after fsync
2026-04-08hfsplus: fix generic/642 failureViacheslav Dubeyko
The xfstests' test-case generic/642 finishes with corrupted HFS+ volume: sudo ./check generic/642 [sudo] password for slavad: FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #26 SMP PREEMPT_DYNAMIC Mon Mar 23 17:24:32 PDT 2026 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/642 6s ... _check_generic_filesystem: filesystem on /dev/loop51 is inconsistent (see xfstests-dev/results//generic/642.full for details) Ran: generic/642 Failures: generic/642 Failed 1 of 1 tests sudo fsck.hfs -d /dev/loop51 ** /dev/loop51 Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. Executing fsck_hfs (version 540.1-Linux). ** Checking non-journaled HFS Plus Volume. The volume name is untitled ** Checking extents overflow file. ** Checking catalog file. ** Checking multi-linked files. ** Checking catalog hierarchy. ** Checking extended attributes file. invalid free nodes - calculated 1637 header 1260 Invalid B-tree header Invalid map node (8, 0) ** Checking volume bitmap. ** Checking volume information. Verify Status: VIStat = 0x0000, ABTStat = 0xc000 EBTStat = 0x0000 CBTStat = 0x0000 CatStat = 0x00000000 ** Repairing volume. ** Rechecking volume. ** Checking non-journaled HFS Plus Volume. The volume name is untitled ** Checking extents overflow file. ** Checking catalog file. ** Checking multi-linked files. ** Checking catalog hierarchy. ** Checking extended attributes file. ** Checking volume bitmap. ** Checking volume information. ** The volume untitled was repaired successfully. The fsck tool detected that Extended Attributes b-tree is corrupted. Namely, the free nodes number is incorrect and map node bitmap has inconsistent state. Analysis has shown that during b-tree closing there are still some lost b-tree's nodes in the hash out of b-tree structure. But this orphaned b-tree nodes are still accounted as used in map node bitmap: tree_cnid 8, nidx 0, node_count 1408, free_nodes 1403 tree_cnid 8, nidx 1, node_count 1408, free_nodes 1403 tree_cnid 8, nidx 3, node_count 1408, free_nodes 1403 tree_cnid 8, nidx 54, node_count 1408, free_nodes 1403 tree_cnid 8, nidx 67, node_count 1408, free_nodes 1403 tree_cnid 8, nidx 0, prev 0, next 0, parent 0, num_recs 3, type 0x1, height 0 tree_cnid 8, nidx 1, prev 0, next 0, parent 3, num_recs 1, type 0xff, height 1 tree_cnid 8, nidx 3, prev 0, next 0, parent 0, num_recs 1, type 0x0, height 2 tree_cnid 8, nidx 54, prev 29, next 46, parent 3, num_recs 0, type 0xff, height 1 tree_cnid 8, nidx 67, prev 8, next 14, parent 3, num_recs 0, type 0xff, height 1 This issue happens in hfs_bnode_split() logic during detection the possibility of moving half ot the records out of the node. The hfs_bnode_split() contains a loop that implements a roughly 50/50 split of the B-tree node's records by scanning the offset table to find where the data crosses the node's midpoint. If this logic detects the incapability of spliting the node, then it simply calls hfs_bnode_put() for newly created node. However, node is not set as HFS_BNODE_DELETED and real deletion of node doesn't happen. As a result, the empty node becomes orphaned but it is still accounted as used. Finally, fsck tool detects this inconsistency of HFS+ volume. This patch adds call of hfs_bnode_unlink() before hfs_bnode_put() for the case if new node cannot be used for spliting the existing node. sudo ./check generic/642 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #26 SMP PREEMPT_DYNAMIC Fri Apr 3 12:39:13 PDT 2026 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/642 40s ... 39s Ran: generic/642 Passed all 1 tests Closes: https://github.com/hfs-linux-kernel/hfs-linux-kernel/issues/242 cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260403230556.614171-6-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-04-08hfsplus: rework logic of map nodes creation in xattr b-treeViacheslav Dubeyko
In hfsplus_init_header_node() when node_count > 63488 (header bitmap capacity), the code calculates map_nodes, subtracts them from free_nodes, and marks their positions used in the bitmap. However, it doesn't write the actual map node structure (type, record offsets, bitmap) for those physical positions, only node 0 is written. This patch reworks hfsplus_create_attributes_file() logic by introducing a specialized method of hfsplus_init_map_node() and writing the allocated map b-tree's nodes by means of hfsplus_write_attributes_file_node() method. cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260403230556.614171-5-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-04-08hfsplus: fix logic of alloc/free b-tree nodeViacheslav Dubeyko
The hfs_bmap_alloc() and hfs_bmap_free() modify the b-tree's counters and nodes' bitmap of b-tree. However, hfs_btree_write() synchronizes the state of in-core b-tree's counters and node's bitmap with b-tree's descriptor in header node. Postponing this synchronization could result in inconsistent state of file system volume. This patch adds calling of hfs_btree_write() in hfs_bmap_alloc() and hfs_bmap_free() methods. cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260403230556.614171-4-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-04-08hfsplus: fix error processing issue in hfs_bmap_free()Viacheslav Dubeyko
Currently, we check only -EINVAL error code in hfs_bmap_free() after calling the hfs_bmap_clear_bit(). It means that other error codes will be silently ignored. This patch adds the checking of all other error codes. cc: Shardul Bankar <shardul.b@mpiricsoftware.com> cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260403230556.614171-3-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-04-08hfsplus: fix potential race conditions in b-tree functionalityViacheslav Dubeyko
The HFS_BNODE_DELETED flag is checked in hfs_bnode_put() under locked tree->hash_lock. This patch adds locking for the case of setting the HFS_BNODE_DELETED flag in hfs_bnode_unlink() with the goal to avoid potential race conditions. The hfs_btree_write() method should be called under tree->tree_lock. This patch reworks logic by adding locking the tree->tree_lock for the calls of hfs_btree_write() in hfsplus_cat_write_inode() and hfsplus_system_write_inode(). This patch adds also the lockdep_assert_held() in hfs_bmap_reserve(), hfs_bmap_alloc(), and hfs_bmap_free(). cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260403230556.614171-2-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-03-27hfsplus: extract hidden directory search into a helper functionZilin Guan
In hfsplus_fill_super(), the process of looking up the hidden directory involves initializing a catalog search, building a search key, reading the b-tree record, and releasing the search data. Currently, this logic is open-coded directly within the main superblock initialization routine. This makes hfsplus_fill_super() quite lengthy and its error handling paths less straightforward. Extract the hidden directory search sequence into a new helper function, hfsplus_get_hidden_dir_entry(). This improves overall code readability, cleanly encapsulates the hfs_find_data lifecycle, and simplifies the error exits in hfsplus_fill_super(). Signed-off-by: Zilin Guan <zilin@seu.edu.cn> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Tested-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-03-27hfsplus: fix held lock freed on hfsplus_fill_super()Zilin Guan
hfsplus_fill_super() calls hfs_find_init() to initialize a search structure, which acquires tree->tree_lock. If the subsequent call to hfsplus_cat_build_key() fails, the function jumps to the out_put_root error label without releasing the lock. The later cleanup path then frees the tree data structure with the lock still held, triggering a held lock freed warning. Fix this by adding the missing hfs_find_exit(&fd) call before jumping to the out_put_root error label. This ensures that tree->tree_lock is properly released on the error path. The bug was originally detected on v6.13-rc1 using an experimental static analysis tool we are developing, and we have verified that the issue persists in the latest mainline kernel. The tool is specifically designed to detect memory management issues. It is currently under active development and not yet publicly available. We confirmed the bug by runtime testing under QEMU with x86_64 defconfig, lockdep enabled, and CONFIG_HFSPLUS_FS=y. To trigger the error path, we used GDB to dynamically shrink the max_unistr_len parameter to 1 before hfsplus_asc2uni() is called. This forces hfsplus_asc2uni() to naturally return -ENAMETOOLONG, which propagates to hfsplus_cat_build_key() and exercises the faulty error path. The following warning was observed during mount: ========================= WARNING: held lock freed! 7.0.0-rc3-00016-gb4f0dd314b39 #4 Not tainted ------------------------- mount/174 is freeing memory ffff888103f92000-ffff888103f92fff, with a lock still held there! ffff888103f920b0 (&tree->tree_lock){+.+.}-{4:4}, at: hfsplus_find_init+0x154/0x1e0 2 locks held by mount/174: #0: ffff888103f960e0 (&type->s_umount_key#42/1){+.+.}-{4:4}, at: alloc_super.constprop.0+0x167/0xa40 #1: ffff888103f920b0 (&tree->tree_lock){+.+.}-{4:4}, at: hfsplus_find_init+0x154/0x1e0 stack backtrace: CPU: 2 UID: 0 PID: 174 Comm: mount Not tainted 7.0.0-rc3-00016-gb4f0dd314b39 #4 PREEMPT(lazy) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.15.0-1 04/01/2014 Call Trace: <TASK> dump_stack_lvl+0x82/0xd0 debug_check_no_locks_freed+0x13a/0x180 kfree+0x16b/0x510 ? hfsplus_fill_super+0xcb4/0x18a0 hfsplus_fill_super+0xcb4/0x18a0 ? __pfx_hfsplus_fill_super+0x10/0x10 ? srso_return_thunk+0x5/0x5f ? bdev_open+0x65f/0xc30 ? srso_return_thunk+0x5/0x5f ? pointer+0x4ce/0xbf0 ? trace_contention_end+0x11c/0x150 ? __pfx_pointer+0x10/0x10 ? srso_return_thunk+0x5/0x5f ? bdev_open+0x79b/0xc30 ? srso_return_thunk+0x5/0x5f ? srso_return_thunk+0x5/0x5f ? vsnprintf+0x6da/0x1270 ? srso_return_thunk+0x5/0x5f ? __mutex_unlock_slowpath+0x157/0x740 ? __pfx_vsnprintf+0x10/0x10 ? srso_return_thunk+0x5/0x5f ? srso_return_thunk+0x5/0x5f ? mark_held_locks+0x49/0x80 ? srso_return_thunk+0x5/0x5f ? srso_return_thunk+0x5/0x5f ? irqentry_exit+0x17b/0x5e0 ? trace_irq_disable.constprop.0+0x116/0x150 ? __pfx_hfsplus_fill_super+0x10/0x10 ? __pfx_hfsplus_fill_super+0x10/0x10 get_tree_bdev_flags+0x302/0x580 ? __pfx_get_tree_bdev_flags+0x10/0x10 ? vfs_parse_fs_qstr+0x129/0x1a0 ? __pfx_vfs_parse_fs_qstr+0x3/0x10 vfs_get_tree+0x89/0x320 fc_mount+0x10/0x1d0 path_mount+0x5c5/0x21c0 ? __pfx_path_mount+0x10/0x10 ? trace_irq_enable.constprop.0+0x116/0x150 ? trace_irq_enable.constprop.0+0x116/0x150 ? srso_return_thunk+0x5/0x5f ? srso_return_thunk+0x5/0x5f ? kmem_cache_free+0x307/0x540 ? user_path_at+0x51/0x60 ? __x64_sys_mount+0x212/0x280 ? srso_return_thunk+0x5/0x5f __x64_sys_mount+0x212/0x280 ? __pfx___x64_sys_mount+0x10/0x10 ? srso_return_thunk+0x5/0x5f ? trace_irq_enable.constprop.0+0x116/0x150 ? srso_return_thunk+0x5/0x5f do_syscall_64+0x111/0x680 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7ffacad55eae Code: 48 8b 0d 85 1f 0f 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 49 89 ca b8 a5 00 00 8 RSP: 002b:00007fff1ab55718 EFLAGS: 00000246 ORIG_RAX: 00000000000000a5 RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007ffacad55eae RDX: 000055740c64e5b0 RSI: 000055740c64e630 RDI: 000055740c651ab0 RBP: 000055740c64e380 R08: 0000000000000000 R09: 0000000000000001 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 000055740c64e5b0 R14: 000055740c651ab0 R15: 000055740c64e380 </TASK> After applying this patch, the warning no longer appears. Fixes: 89ac9b4d3d1a ("hfsplus: fix longname handling") CC: stable@vger.kernel.org Signed-off-by: Zilin Guan <zilin@seu.edu.cn> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Tested-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-03-25hfsplus: fix generic/523 test-case failureViacheslav Dubeyko
The xfstests' test-case generic/523 fails to execute correctly: FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.15.0-rc4+ #8 SMP PREEMPT_DYNAMIC Thu May 1 16:43:22 PDT 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/523 - output mismatch (see xfstests-dev/results//generic/523.out.bad) The test-case expects to have '/' in the xattr name. However, HFS+ unicode logic makes conversion of '/' into ':'. In HFS+, a filename can contain '/' because ':' is the separator. The slash is a valid filename character on macOS. But on Linux, / is the path separator and it cannot appear in a filename component. But xattr name can contain any of these symbols. It means that this unicode logic conversion doesn't need to be executed for the case of xattr name. This patch adds distinguishing the regular and xattr names. If we have a regular name, then this conversion of special symbols will be executed. Otherwise, the conversion is skipped for the case of xattr names. sudo ./check -g auto FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #24 SMP PREEMPT_DYNAMIC Fri Mar 20 12:36:49 PDT 2026 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch <skipped> generic/523 33s ... 25s <skipped> Closes: https://github.com/hfs-linux-kernel/hfs-linux-kernel/issues/178 cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260324003949.417048-2-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-03-18hfsplus: validate b-tree node 0 bitmap at mount timeShardul Bankar
Syzkaller reported an issue with corrupted HFS+ images where the b-tree allocation bitmap indicates that the header node (Node 0) is free. Node 0 must always be allocated as it contains the b-tree header record and the allocation bitmap itself. Violating this invariant leads to allocator corruption, which cascades into kernel panics or undefined behavior when the filesystem attempts to allocate blocks. Prevent trusting a corrupted allocator state by adding a validation check during hfs_btree_open(). Introduce the hfs_bmap_test_bit() helper (utilizing the newly added map-access API) to safely verify that the MSB of the first bitmap byte (representing Node 0) is marked as allocated. The helper returns a boolean, allowing the caller to safely catch both structural IO errors and illegally cleared bits in a single check. If corruption is detected, print a warning identifying the specific corrupted tree and force the filesystem to mount read-only (SB_RDONLY). This prevents kernel panics from corrupted images while enabling data recovery. As a minor cleanup to support the warning logs, replace the verbose CNID logic with cleaner macro definitions (using official structural names like "Extents Overflow File") and a dedicated string lookup helper. Reported-by: syzbot+1c8ff72d0cd8a50dfeaa@syzkaller.appspotmail.com Link: https://syzkaller.appspot.com/bug?extid=1c8ff72d0cd8a50dfeaa Link: https://lore.kernel.org/all/20260315172005.2066677-1-shardul.b@mpiricsoftware.com/ Signed-off-by: Shardul Bankar <shardul.b@mpiricsoftware.com> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Tested-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260318073823.3933718-3-shardul.b@mpiricsoftware.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-03-18hfsplus: refactor b-tree map page access and add node-type validationShardul Bankar
In HFS+ b-trees, the node allocation bitmap is stored across multiple records. The first chunk resides in the b-tree Header Node at record index 2, while all subsequent chunks are stored in dedicated Map Nodes at record index 0. This structural quirk forces callers like hfs_bmap_alloc() and hfs_bmap_free() to duplicate boilerplate code to validate offsets, correct lengths, and map the underlying pages via kmap_local_page(). There is also currently no strict node-type validation before reading these records, leaving the allocator vulnerable if a corrupted image points a map linkage to an Index or Leaf node. Introduce a unified bit-level API to encapsulate the map record access: 1. A new `struct hfs_bmap_ctx` to cleanly pass state and safely handle page math across all architectures. 2. `hfs_bmap_get_map_page()`: Automatically validates node types (HFS_NODE_HEADER vs HFS_NODE_MAP), infers the correct record index, handles page-boundary math, and returns the unmapped `struct page *` directly to the caller to avoid asymmetric mappings. 3. `hfs_bmap_clear_bit()`: A clean wrapper that internally handles page mapping/unmapping for single-bit operations. Refactor hfs_bmap_alloc() and hfs_bmap_free() to utilize this new API. This deduplicates the allocator logic, hardens the map traversal against fuzzed images, and provides the exact abstractions needed for upcoming mount-time validation checks. Signed-off-by: Shardul Bankar <shardul.b@mpiricsoftware.com> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Tested-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260318073823.3933718-2-shardul.b@mpiricsoftware.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-03-17hfsplus: fix to update ctime after renameViacheslav Dubeyko
[BUG] $ sudo ./check generic/003 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 graphic 6.8.0-58-generic #60~22.04.1-Ubuntu MKFS_OPTIONS -- /dev/loop29 MOUNT_OPTIONS -- /dev/loop29 /mnt/scratch generic/003 - output mismatch --- tests/generic/003.out 2025-04-27 08:49:39.876945323 -0600 +++ /home/graphic/fs/xfstests-dev/results//generic/003.out.bad QA output created by 003 +ERROR: change time has not been updated after changing file1 Silence is golden ... Ran: generic/003 Failures: generic/003 Failed 1 of 1 tests [CAUSE] change time has not been updated after changing file1 [FIX] Update file ctime after rename in hfsplus_rename(). Signed-off-by: Yangtao Li <frank.li@vivo.com> Tested-by: Viacheslav Dubeyko <slava@dubeyko.com> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/linux-fsdevel/20250530081719.2430291-1-frank.li@vivo.com/ Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-03-16hfsplus: fix generic/533 test-case failureViacheslav Dubeyko
The xfstests' test-case generic/533 fails to execute correctly: FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.15.0-rc4+ #8 SMP PREEMPT_DYNAMIC Thu May 1 16:43:22 PDT 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/533 _check_generic_filesystem: filesystem on /dev/loop50 is inconsistent (see xfstests-dev/results//generic/533.full for details) The key reason of the issue is returning -ENOENT error code from hfsplus_find_attr(), __hfsplus_delete_attr(), hfsplus_delete_attr_nolock(), hfsplus_delete_all_attrs(). The file exists but we don't have any xattr for this file. Finally, -ENODATA error code is expected by application logic. This patch reworks xattr logic of HFS+ by means exchanging the -ENOENT error code on -ENODATA error code if xattr has not been found for existing file or folder. sudo ./check generic/533 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #16 SMP PREEMPT_DYNAMIC Wed Mar 11 15:04:58 PDT 2026 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/533 33s ... 32s Ran: generic/533 Passed all 1 tests Closes: https://github.com/hfs-linux-kernel/hfs-linux-kernel/issues/184 cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260312221920.1422683-2-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-03-12hfsplus: set ctime after setxattr and removexattrViacheslav Dubeyko
The generic/728 test-case complains that: (1) Expected ctime needs to be changed after setxattr; (2) Expected ctime needs to be changed after removexattr. This patch adds calling inode_set_ctime_current() in __hfsplus_setxattr() and hfsplus_removexattr(). sudo ./check generic/728 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #6 SMP PREEMPT_DYNAMIC Mon Mar 9 14:29:30 PDT 2026 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/728 35s ... 44s Ran: generic/728 Passed all 1 tests cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260309214947.1114618-2-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-03-09hfsplus: fix uninit-value by validating catalog record sizeDeepanshu Kartikey
Syzbot reported a KMSAN uninit-value issue in hfsplus_strcasecmp(). The root cause is that hfs_brec_read() doesn't validate that the on-disk record size matches the expected size for the record type being read. When mounting a corrupted filesystem, hfs_brec_read() may read less data than expected. For example, when reading a catalog thread record, the debug output showed: HFSPLUS_BREC_READ: rec_len=520, fd->entrylength=26 HFSPLUS_BREC_READ: WARNING - entrylength (26) < rec_len (520) - PARTIAL READ! hfs_brec_read() only validates that entrylength is not greater than the buffer size, but doesn't check if it's less than expected. It successfully reads 26 bytes into a 520-byte structure and returns success, leaving 494 bytes uninitialized. This uninitialized data in tmp.thread.nodeName then gets copied by hfsplus_cat_build_key_uni() and used by hfsplus_strcasecmp(), triggering the KMSAN warning when the uninitialized bytes are used as array indices in case_fold(). Fix by introducing hfsplus_brec_read_cat() wrapper that: 1. Calls hfs_brec_read() to read the data 2. Validates the record size based on the type field: - Fixed size for folder and file records - Variable size for thread records (depends on string length) 3. Returns -EIO if size doesn't match expected For thread records, check against HFSPLUS_MIN_THREAD_SZ before reading nodeName.length to avoid reading uninitialized data at call sites that don't zero-initialize the entry structure. Also initialize the tmp variable in hfsplus_find_cat() as defensive programming to ensure no uninitialized data even if validation is bypassed. Reported-by: syzbot+d80abb5b890d39261e72@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=d80abb5b890d39261e72 Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Tested-by: syzbot+d80abb5b890d39261e72@syzkaller.appspotmail.com Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Tested-by: Viacheslav Dubeyko <slava@dubeyko.com> Suggested-by: Charalampos Mitrodimas <charmitro@posteo.net> Link: https://lore.kernel.org/all/20260120051114.1281285-1-kartikey406@gmail.com/ [v1] Link: https://lore.kernel.org/all/20260121063109.1830263-1-kartikey406@gmail.com/ [v2] Link: https://lore.kernel.org/all/20260212014233.2422046-1-kartikey406@gmail.com/ [v3] Link: https://lore.kernel.org/all/20260214002100.436125-1-kartikey406@gmail.com/T/ [v4] Link: https://lore.kernel.org/all/20260221061626.15853-1-kartikey406@gmail.com/T/ [v5] Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260307010302.41547-1-kartikey406@gmail.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-03-06treewide: change inode->i_ino from unsigned long to u64Jeff Layton
On 32-bit architectures, unsigned long is only 32 bits wide, which causes 64-bit inode numbers to be silently truncated. Several filesystems (NFS, XFS, BTRFS, etc.) can generate inode numbers that exceed 32 bits, and this truncation can lead to inode number collisions and other subtle bugs on 32-bit systems. Change the type of inode->i_ino from unsigned long to u64 to ensure that inode numbers are always represented as 64-bit values regardless of architecture. Update all format specifiers treewide from %lu/%lx to %llu/%llx to match the new type, along with corresponding local variable types. This is the bulk treewide conversion. Earlier patches in this series handled trace events separately to allow trace field reordering for better struct packing on 32-bit. Signed-off-by: Jeff Layton <jlayton@kernel.org> Link: https://patch.msgid.link/20260304-iino-u64-v3-12-2257ad83d372@kernel.org Acked-by: Damien Le Moal <dlemoal@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Jan Kara <jack@suse.cz> Reviewed-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Christian Brauner <brauner@kernel.org>
2026-03-04hfsplus: fix potential Allocation File corruption after fsyncViacheslav Dubeyko
The generic/348 test-case has revealed the issue of HFS+ volume corruption after simulated power failure: FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.15.0-rc4+ #8 SMP PREEMPT_DYNAMIC Thu May 1 16:43:22 PDT 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/348 _check_generic_filesystem: filesystem on /dev/loop51 is inconsistent (see xfstests-dev/results//generic/348.full for details) The fsck tool complains about Allocation File (block bitmap) corruption as a result of such event. The generic/348 creates a symlink, fsync its parent directory, power fail and mount again the filesystem. Currently, HFS+ logic has several flags HFSPLUS_I_CAT_DIRTY, HFSPLUS_I_EXT_DIRTY, HFSPLUS_I_ATTR_DIRTY, HFSPLUS_I_ALLOC_DIRTY. If inode operation modified the Catalog File, Extents Overflow File, Attributes File, or Allocation File, then inode is marked as dirty and one of the mentioned flags has been set. When hfsplus_file_fsync() has been called, then this set of flags is checked and dirty b-tree or/and block bitmap is flushed. However, block bitmap can be modified during file's content allocation. It means that if we call hfsplus_file_fsync() for directory, then we never flush the modified Allocation File in such case because such inode cannot receive HFSPLUS_I_ALLOC_DIRTY flag. Moreover, this inode-centric model is not good at all because Catalog File, Extents Overflow File, Attributes File, and Allocation File represent the whole state of file system metadata. This inode-centric policy is the main reason of the issue. This patch saves the whole approach of using HFSPLUS_I_CAT_DIRTY, HFSPLUS_I_EXT_DIRTY, HFSPLUS_I_ATTR_DIRTY, and HFSPLUS_I_ALLOC_DIRTY flags. But Catalog File, Extents Overflow File, Attributes File, and Allocation File have associated inodes. And namely these inodes become the mechanism of checking the dirty state of metadata. The hfsplus_file_fsync() method checks the dirtiness of file system metadata by testing HFSPLUS_I_CAT_DIRTY, HFSPLUS_I_EXT_DIRTY, HFSPLUS_I_ATTR_DIRTY, and HFSPLUS_I_ALLOC_DIRTY flags of Catalog File's, Extents Overflow File's, Attributes File's, or Allocation File's inodes. As a result, even if we call hfsplus_file_fsync() for parent folder, then dirty Allocation File will be flushed anyway. Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Link: https://lore.kernel.org/r/20260220220152.152721-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-02-21Convert 'alloc_obj' family to use the new default GFP_KERNEL argumentLinus Torvalds
This was done entirely with mindless brute force, using git grep -l '\<k[vmz]*alloc_objs*(.*, GFP_KERNEL)' | xargs sed -i 's/\(alloc_objs*(.*\), GFP_KERNEL)/\1)/' to convert the new alloc_obj() users that had a simple GFP_KERNEL argument to just drop that argument. Note that due to the extreme simplicity of the scripting, any slightly more complex cases spread over multiple lines would not be triggered: they definitely exist, but this covers the vast bulk of the cases, and the resulting diff is also then easier to check automatically. For the same reason the 'flex' versions will be done as a separate conversion. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2026-02-21treewide: Replace kmalloc with kmalloc_obj for non-scalar typesKees Cook
This is the result of running the Coccinelle script from scripts/coccinelle/api/kmalloc_objs.cocci. The script is designed to avoid scalar types (which need careful case-by-case checking), and instead replace kmalloc-family calls that allocate struct or union object instances: Single allocations: kmalloc(sizeof(TYPE), ...) are replaced with: kmalloc_obj(TYPE, ...) Array allocations: kmalloc_array(COUNT, sizeof(TYPE), ...) are replaced with: kmalloc_objs(TYPE, COUNT, ...) Flex array allocations: kmalloc(struct_size(PTR, FAM, COUNT), ...) are replaced with: kmalloc_flex(*PTR, FAM, COUNT, ...) (where TYPE may also be *VAR) The resulting allocations no longer return "void *", instead returning "TYPE *". Signed-off-by: Kees Cook <kees@kernel.org>
2026-02-06hfsplus: avoid double unload_nls() on mount failureShardul Bankar
The recent commit "hfsplus: ensure sb->s_fs_info is always cleaned up" [1] introduced a custom ->kill_sb() handler (hfsplus_kill_super) that cleans up the s_fs_info structure (including the NLS table) on superblock destruction. However, the error handling path in hfsplus_fill_super() still calls unload_nls() before returning an error. Since the VFS layer calls ->kill_sb() when fill_super fails, this results in unload_nls() being called twice for the same sbi->nls pointer: once in hfsplus_fill_super() and again in hfsplus_kill_super() (via delayed_free). Remove the explicit unload_nls() call from the error path in hfsplus_fill_super() to rely solely on the cleanup in ->kill_sb(). [1] https://lore.kernel.org/r/20251201222843.82310-3-mehdi.benhadjkhelifa@gmail.com/ Reported-by: Al Viro <viro@zeniv.linux.org.uk> Link: https://lore.kernel.org/r/20260203043806.GF3183987@ZenIV/ Signed-off-by: Shardul Bankar <shardul.b@mpiricsoftware.com> Link: https://lore.kernel.org/r/20260204170440.1337261-1-shardul.b@mpiricsoftware.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-01-29hfsplus: fix warning issue in inode.cViacheslav Dubeyko
This patch fixes the sparse warning issue in inode.c by adding static to hfsplus_symlink_inode_operations and hfsplus_special_inode_operations declarations. Reported-by: kernel test robot <lkp@intel.com> Closes: https://lore.kernel.org/oe-kbuild-all/202601291957.bunRsD8R-lkp@intel.com/ Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Link: https://lore.kernel.org/r/20260129195442.594884-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-01-28hfsplus: fix generic/062 xfstests failureViacheslav Dubeyko
The xfstests' test-case generic/062 fails to execute correctly: FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.15.0-rc4+ #8 SMP PREEMPT_DYNAMIC Thu May 1 16:43:22 PDT 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/062 - output mismatch (see xfstests-dev/results//generic/062.out.bad) The generic/062 test tries to set and get xattrs for various types of objects (regular file, folder, block device, character device, pipe, etc) with the goal to check that xattr operations works correctly for all possible types of file system objects. But current HFS+ implementation somehow hasn't support of xattr operatioons for the case of block device, character device, and pipe objects. Also, it has not completely correct set of operations for the case symlinks. This patch implements proper declaration of xattrs operations hfsplus_special_inode_operations and hfsplus_symlink_inode_operations. Also, it slightly corrects the logic of hfsplus_listxattr() method. sudo ./check generic/062 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.19.0-rc1+ #59 SMP PREEMPT_DYNAMIC Mon Jan 19 16:26:21 PST 2026 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/062 20s ... 20s Ran: generic/062 Passed all 1 tests [1] https://github.com/hfs-linux-kernel/hfs-linux-kernel/issues/93 Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Link: https://lore.kernel.org/r/20260120041937.3450928-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-01-19hfsplus: fix generic/037 xfstests failureViacheslav Dubeyko
The xfstests' test-case generic/037 fails to execute correctly: FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.15.0-rc4+ #8 SMP PREEMPT_DYNAMIC Thu May 1 16:43:22 PDT 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/037 - output mismatch (see xfstests-dev/results//generic/037.out.bad) The goal of generic/037 test-case is to "verify that replacing a xattr's value is an atomic operation". The test "consists of removing the old value and then inserting the new value in a btree. This made readers (getxattr and listxattrs) not getting neither the old nor the new value during a short time window". The HFS+ has the issue of executing the xattr replace operation because __hfsplus_setxattr() method [1] implemented it as not atomic operation [2]: if (hfsplus_attr_exists(inode, name)) { if (flags & XATTR_CREATE) { pr_err("xattr exists yet\n"); err = -EOPNOTSUPP; goto end_setxattr; } err = hfsplus_delete_attr(inode, name); if (err) goto end_setxattr; err = hfsplus_create_attr(inode, name, value, size); if (err) goto end_setxattr; } The main issue of the logic that it implements delete and create of xattr as independent atomic operations, but the replace operation at whole is not atomic operation. This patch implements a new hfsplus_replace_attr() method that makes the xattr replace operation by atomic one. Also, it reworks hfsplus_create_attr() and hfsplus_delete_attr() with the goal of reusing the common logic in hfsplus_replace_attr() method. sudo ./check generic/037 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.19.0-rc1+ #47 SMP PREEMPT_DYNAMIC Thu Jan 8 15:37:20 PST 2026 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/037 37s ... 37s Ran: generic/037 Passed all 1 tests [1] https://elixir.bootlin.com/linux/v6.19-rc4/source/fs/hfsplus/xattr.c#L261 [2] https://elixir.bootlin.com/linux/v6.19-rc4/source/fs/hfsplus/xattr.c#L338 Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Link: https://lore.kernel.org/r/20260109234213.2805400-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-01-06hfsplus: pretend special inodes as regular filesTetsuo Handa
Since commit af153bb63a33 ("vfs: catch invalid modes in may_open()") requires any inode be one of S_IFDIR/S_IFLNK/S_IFREG/S_IFCHR/S_IFBLK/ S_IFIFO/S_IFSOCK type, use S_IFREG for special inodes. Reported-by: syzbot <syzbot+895c23f6917da440ed0d@syzkaller.appspotmail.com> Closes: https://syzkaller.appspot.com/bug?extid=895c23f6917da440ed0d Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/d0a07b1b-8b73-4002-8e29-e2bd56871262@I-love.SAKURA.ne.jp Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-01-06hfsplus: return error when node already exists in hfs_bnode_createShardul Bankar
When hfs_bnode_create() finds that a node is already hashed (which should not happen in normal operation), it currently returns the existing node without incrementing its reference count. This causes a reference count inconsistency that leads to a kernel panic when the node is later freed in hfs_bnode_put(): kernel BUG at fs/hfsplus/bnode.c:676! BUG_ON(!atomic_read(&node->refcnt)) This scenario can occur when hfs_bmap_alloc() attempts to allocate a node that is already in use (e.g., when node 0's bitmap bit is incorrectly unset), or due to filesystem corruption. Returning an existing node from a create path is not normal operation. Fix this by returning ERR_PTR(-EEXIST) instead of the node when it's already hashed. This properly signals the error condition to callers, which already check for IS_ERR() return values. Reported-by: syzbot+1c8ff72d0cd8a50dfeaa@syzkaller.appspotmail.com Link: https://syzkaller.appspot.com/bug?extid=1c8ff72d0cd8a50dfeaa Link: https://lore.kernel.org/all/784415834694f39902088fa8946850fc1779a318.camel@ibm.com/ Fixes: 634725a92938 ("[PATCH] hfs: cleanup HFS+ prints") Signed-off-by: Shardul Bankar <shardul.b@mpiricsoftware.com> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20251229204938.1907089-1-shardul.b@mpiricsoftware.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-01-06hfsplus: fix generic/020 xfstests failureViacheslav Dubeyko
The xfstests' test-case generic/020 fails to execute correctly: FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.15.0-rc4+ #8 SMP PREEMPT_DYNAMIC Thu May 1 16:43:22 PDT 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/020 _check_generic_filesystem: filesystem on /dev/loop50 is inconsistent (see xfstests-dev/results//generic/020.full for details) *** add lots of attributes *** check *** MAX_ATTRS attribute(s) +/mnt/test/attribute_12286: Numerical result out of range *** -1 attribute(s) *** remove lots of attributes ... (Run 'diff -u /xfstests-dev/tests/generic/020.out /xfstests-dev/results//generic/020.out.bad' to see the entire diff) The generic/020 creates more than 100 xattrs and gives its the names user.attribute_<number> (for example, user.attribute_101). As the next step, listxattr() is called with the goal to check the correctness of xattrs creation. However, it was issue in hfsplus_listxattr() logic. This method re-uses the fd.key->attr.key_name.unicode and strbuf buffers in the loop without re-initialization. As a result, part of the previous name could still remain in the buffers. For example, user.attribute_101 could be processed before user.attribute_54. The issue resulted in formation the name user.attribute_541 instead of user.attribute_54. This patch adds initialization of fd.key->attr.key_name.unicode and strbuf buffers before calling hfs_brec_goto() method that prepare next name in the buffer. HFS+ logic supports only inline xattrs. Such extended attributes can store values not bigger than 3802 bytes [1]. This limitation requires correction of generic/020 logic. Finally, generic/020 can be executed without any issue: sudo ./check generic/020 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.19.0-rc1+ #44 SMP PREEMPT_DYNAMIC Mon Dec 22 15:39:00 PST 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/020 31s ... 38s Ran: generic/020 Passed all 1 tests [1] https://elixir.bootlin.com/linux/v6.19-rc2/source/include/linux/hfs_common.h#L626 Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Link: https://lore.kernel.org/r/20251224002810.1137139-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2025-12-15hfsplus: fix volume corruption issue for generic/498Viacheslav Dubeyko
The xfstests' test-case generic/498 leaves HFS+ volume in corrupted state: sudo ./check generic/498 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.18.0-rc1+ #18 SMP PREEMPT_DYNAMIC Thu Dec 4 12:24:45 PST 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/498 _check_generic_filesystem: filesystem on /dev/loop51 is inconsistent (see XFSTESTS-2/xfstests-dev/results//generic/498.full for details) Ran: generic/498 Failures: generic/498 Failed 1 of 1 tests sudo fsck.hfsplus -d /dev/loop51 ** /dev/loop51 Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. Executing fsck_hfs (version 540.1-Linux). ** Checking non-journaled HFS Plus Volume. The volume name is untitled ** Checking extents overflow file. ** Checking catalog file. Invalid leaf record count (It should be 16 instead of 2) ** Checking multi-linked files. CheckHardLinks: found 1 pre-Leopard file inodes. ** Checking catalog hierarchy. ** Checking extended attributes file. ** Checking volume bitmap. ** Checking volume information. Verify Status: VIStat = 0x0000, ABTStat = 0x0000 EBTStat = 0x0000 CBTStat = 0x8000 CatStat = 0x00000000 ** Repairing volume. ** Rechecking volume. ** Checking non-journaled HFS Plus Volume. The volume name is untitled ** Checking extents overflow file. ** Checking catalog file. ** Checking multi-linked files. CheckHardLinks: found 1 pre-Leopard file inodes. ** Checking catalog hierarchy. ** Checking extended attributes file. ** Checking volume bitmap. ** Checking volume information. ** The volume untitled was repaired successfully. The generic/498 test executes such steps on final phase: mkdir $SCRATCH_MNT/A mkdir $SCRATCH_MNT/B mkdir $SCRATCH_MNT/A/C touch $SCRATCH_MNT/B/foo $XFS_IO_PROG -c "fsync" $SCRATCH_MNT/B/foo ln $SCRATCH_MNT/B/foo $SCRATCH_MNT/A/C/foo $XFS_IO_PROG -c "fsync" $SCRATCH_MNT/A "Simulate a power failure and mount the filesystem to check that what we explicitly fsync'ed exists." _flakey_drop_and_remount The FSCK tool complains about "Invalid leaf record count". HFS+ b-tree header contains leaf_count field is updated by hfs_brec_insert() and hfs_brec_remove(). The hfs_brec_insert() is involved into hard link creation process. However, modified in-core leaf_count field is stored into HFS+ b-tree header by hfs_btree_write() method. But, unfortunately, hfs_btree_write() hasn't been called by hfsplus_cat_write_inode() and hfsplus_file_fsync() stores not fully consistent state of the Catalog File's b-tree. This patch adds calling hfs_btree_write() method in the hfsplus_cat_write_inode() with the goal of storing consistent state of Catalog File's b-tree. Finally, it makes FSCK tool happy. sudo ./check generic/498 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.18.0-rc1+ #22 SMP PREEMPT_DYNAMIC Sat Dec 6 17:01:31 PST 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/498 33s ... 31s Ran: generic/498 Passed all 1 tests Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Link: https://lore.kernel.org/r/20251207035821.3863657-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2025-12-15hfsplus: fix volume corruption issue for generic/480Viacheslav Dubeyko
The xfstests' test-case generic/480 leaves HFS+ volume in corrupted state: sudo ./check generic/480 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.17.0-rc1+ #4 SMP PREEMPT_DYNAMIC Wed Oct 1 15:02:44 PDT 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/480 _check_generic_filesystem: filesystem on /dev/loop51 is inconsistent (see XFSTESTS-2/xfstests-dev/results//generic/480.full for details) Ran: generic/480 Failures: generic/480 Failed 1 of 1 tests sudo fsck.hfsplus -d /dev/loop51 ** /dev/loop51 Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. Executing fsck_hfs (version 540.1-Linux). ** Checking non-journaled HFS Plus Volume. The volume name is untitled ** Checking extents overflow file. ** Checking catalog file. ** Checking multi-linked files. CheckHardLinks: found 1 pre-Leopard file inodes. Incorrect number of file hard links ** Checking catalog hierarchy. ** Checking extended attributes file. ** Checking volume bitmap. ** Checking volume information. invalid VHB nextCatalogID Volume header needs minor repair (2, 0) Verify Status: VIStat = 0x8000, ABTStat = 0x0000 EBTStat = 0x0000 CBTStat = 0x0000 CatStat = 0x00000002 ** Repairing volume. Incorrect flags for file hard link (id = 19) (It should be 0x22 instead of 0x2) Incorrect flags for file inode (id = 18) (It should be 0x22 instead of 0x2) first link ID=0 is < 16 for fileinode=18 Error getting first link ID for inode = 18 (result=2) Invalid first link in hard link chain (id = 18) (It should be 19 instead of 0) Indirect node 18 needs link count adjustment (It should be 1 instead of 2) ** Rechecking volume. ** Checking non-journaled HFS Plus Volume. The volume name is untitled ** Checking extents overflow file. ** Checking catalog file. ** Checking multi-linked files. ** Checking catalog hierarchy. ** Checking extended attributes file. ** Checking volume bitmap. ** Checking volume information. ** The volume untitled was repaired successfully. The generic/480 test executes such steps on final phase: "Now remove of the links of our file and create a new file with the same name and in the same parent directory, and finally fsync this new file." unlink $SCRATCH_MNT/testdir/bar touch $SCRATCH_MNT/testdir/bar $XFS_IO_PROG -c "fsync" $SCRATCH_MNT/testdir/bar "Simulate a power failure and mount the filesystem to check that replaying the fsync log/journal succeeds, that is the mount operation does not fail." _flakey_drop_and_remount The key issue in HFS+ logic is that hfsplus_link(), hfsplus_unlink(), hfsplus_rmdir(), hfsplus_symlink(), and hfsplus_mknod() methods don't call hfsplus_cat_write_inode() for the case of modified inode objects. As a result, even if hfsplus_file_fsync() is trying to flush the dirty Catalog File, but because of not calling hfsplus_cat_write_inode() not all modified inodes save the new state into Catalog File's records. Finally, simulation of power failure results in inconsistent state of Catalog File and FSCK tool reports about volume corruption. This patch adds calling of hfsplus_cat_write_inode() method for modified inodes in hfsplus_link(), hfsplus_unlink(), hfsplus_rmdir(), hfsplus_symlink(), and hfsplus_mknod() methods. Also, it adds debug output in several methods. sudo ./check generic/480 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.18.0-rc1+ #18 SMP PREEMPT_DYNAMIC Thu Dec 4 12:24:45 PST 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/480 16s ... 16s Ran: generic/480 Passed all 1 tests Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Link: https://lore.kernel.org/r/20251205000054.3670326-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2025-12-15hfsplus: ensure sb->s_fs_info is always cleaned upMehdi Ben Hadj Khelifa
When hfsplus was converted to the new mount api a bug was introduced by changing the allocation pattern of sb->s_fs_info. If setup_bdev_super() fails after a new superblock has been allocated by sget_fc(), but before hfsplus_fill_super() takes ownership of the filesystem-specific s_fs_info data it was leaked. Fix this by freeing sb->s_fs_info in hfsplus_kill_super(). Cc: stable@vger.kernel.org Fixes: 432f7c78cb00 ("hfsplus: convert hfsplus to use the new mount api") Reported-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com> Tested-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com> Signed-off-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Mehdi Ben Hadj Khelifa <mehdi.benhadjkhelifa@gmail.com> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20251201222843.82310-3-mehdi.benhadjkhelifa@gmail.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2025-12-03Merge tag 'hfs-v6.19-tag1' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs Pull hfs/hfsplus updates from Viacheslav Dubeyko: "Several fixes for syzbot reported issues, HFS/HFS+ fixes of xfstests failures, Kunit-based unit-tests introduction, and code cleanup: - Dan Carpenter fixed a potential use-after-free issue in hfs_correct_next_unused_CNID() method. Tetsuo Handa has made nice fix of syzbot reported issue related to incorrect inode->i_mode management if volume has been corrupted somehow. Yang Chenzhi has made really good fix of potential race condition in __hfs_bnode_create() method for HFS+ file system. - Several fixes to xfstests failures. Particularly, generic/070, generic/073, and generic/101 test-cases finish successfully for the case of HFS+ file system right now. - HFS and HFS+ drivers share multiple structures of on-disk layout declarations. Some structures are used without any change. However, we had two independent declarations of the same structures in HFS and HFS+ drivers. The on-disk layout declarations have been moved into include/linux/hfs_common.h with the goal to exclude the declarations duplication and to keep the HFS/HFS+ on-disk layout declarations in one place. Also, this patch prepares the basis for creating a hfslib that can aggregate common functionality without necessity to duplicate the same code in HFS and HFS+ drivers. - HFS/HFS+ really need unit-tests because of multiple xfstests failures. The first two patches introduce Kunit-based unit-tests for the case string operations in HFS/HFS+ file system drivers" * tag 'hfs-v6.19-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs: hfs/hfsplus: move on-disk layout declarations into hfs_common.h hfsplus: fix volume corruption issue for generic/101 hfsplus: introduce KUnit tests for HFS+ string operations hfs: introduce KUnit tests for HFS string operations hfsplus: fix volume corruption issue for generic/073 hfsplus: Verify inode mode when loading from disk hfsplus: fix volume corruption issue for generic/070 hfs/hfsplus: prevent getting negative values of offset/length hfsplus: fix missing hfs_bnode_get() in __hfs_bnode_create hfs: fix potential use after free in hfs_correct_next_unused_CNID()
2025-12-01Merge tag 'vfs-6.19-rc1.fs_header' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs Pull fs header updates from Christian Brauner: "This contains initial work to start splitting up fs.h. Begin the long-overdue work of splitting up the monolithic fs.h header. The header has grown to over 3000 lines and includes types and functions for many different subsystems, making it difficult to navigate and causing excessive compilation dependencies. This series introduces new focused headers for superblock-related code: - Rename fs_types.h to fs_dirent.h to better reflect its actual content (directory entry types) - Add fs/super_types.h containing superblock type definitions - Add fs/super.h containing superblock function declarations This is the first step in a longer effort to modularize the VFS headers. Cleanups: - Inode Field Layout Optimization (Mateusz Guzik) Move inode fields used during fast path lookup closer together to improve cache locality during path resolution. - current_umask() Optimization (Mateusz Guzik) Inline current_umask() and move it to fs_struct.h. This improves performance by avoiding function call overhead for this frequently-used function, and places it in a more appropriate header since it operates on fs_struct" * tag 'vfs-6.19-rc1.fs_header' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: fs: move inode fields used during fast path lookup closer together fs: inline current_umask() and move it to fs_struct.h fs: add fs/super.h header fs: add fs/super_types.h header fs: rename fs_types.h to fs_dirent.h