summaryrefslogtreecommitdiff
path: root/fs/hfs
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
12 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-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-31hfs: 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 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-5-marco.crivellari@suse.com Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-27hfs: rework MDB locking schemeViacheslav Dubeyko
hfs_mdb_commit() used to hold the primary MDB buffer_head (mdb_bh) locked for the whole commit, including writing the alternate MDB and the volume bitmap. A corrupted image can set drVBMSt so the bitmap block aliases mdb_bh. The bitmap writeback path then calls lock_buffer() on that same buffer_head while it is already locked by hfs_mdb_commit(). Finally, we have a deadlock during flushing the MDB to the file system volume. However, even for valid images, the locking scheme of holding the mdb_bh locked across this much unrelated I/O is fragile anyway. This patch adds a dedicated sbi->mdb_lock and take it around every hfs_mdb_commit() caller (hfs_sync_fs(), flush_mdb(), and the initial hfs_mdb_get() in hfs_fill_super()). Additionally, this patch makes sbi->mdb/sbi->alt_mdb independent in-memory copies (allocated with kmemdup()) instead of pointers into mdb_bh's/alt_mdb_bh's page cache data. Every MDB field read or write in hfs_mdb_commit(), hfs_mdb_close() and hfs_mdb_get() now operates on these copies. Also, hfs_mdb_publish() and hfs_alt_mdb_publish() are the only places left that touch the buffer_heads. The hfs_mdb_put() frees the two copies. Reported-by: Yue Sun <samsun1006219@gmail.com> Link: https://lore.kernel.org/all/CAEkJfYMB47v1yOWHB8q2dc8kf=uj-rLO=+yMyudwPguJ8Kd3jA@mail.gmail.com/ Signed-off-by: Yue Sun <samsun1006219@gmail.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/20260720184414.195213-2-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-07-20hfs: port HFS+ b-tree bitmap corruption checkAditya Prakash Srivastava
In HFS+ filesystems, 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. HFS filesystems share the same b-tree structure but currently lack this corruption detection check. Port this check to HFS, aligning its implementation with HFS+ to maintain consistent b-tree logic across both filesystems: 1. Define struct hfs_bmap_ctx, and define HFS_TREE_HEAD and the relevant map record indices in include/linux/hfs_common.h. 2. Port the necessary offset and length validation helpers to fs/hfs/btree.h as static inline functions with robust null pointer checks. 3. Implement static hfs_bmap_get_map_page() in fs/hfs/btree.c. 4. Implement static hfs_bmap_test_bit() in fs/hfs/btree.c to inspect the B-tree bitmap using the get_map_page helper. 5. Implement static hfs_bmap_clear_bit() in fs/hfs/btree.c. 6. Rewrite hfs_bmap_alloc() in fs/hfs/btree.c to use the unified hfs_bmap_get_map_page() helper, eliminating redundant page and offset calculation code. 7. Refactor hfs_bmap_free() in fs/hfs/btree.c to use the new hfs_bmap_clear_bit() helper. 8. In hfs_btree_open(), retrieve the header node via hfs_bnode_find(), test its allocation bit with hfs_bmap_test_bit(), and release it using hfs_bnode_put(). Suggested-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/all/6a36101b.be22b350.2a3e9.0001.GAE@google.com/T/#r446d0fed2a2900bd805534bbcb799d86619ae2ea Signed-off-by: Aditya Prakash Srivastava <aditya.ansh182@gmail.com> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260716074150.1660-1-aditya.ansh182@gmail.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-07-14hfs: don't re-dirty MDB buffers after a write failureViacheslav Dubeyko
hfs_mdb_commit() and hfs_mdb_close() keep the MDB and alternate-MDB buffer heads (mdb_bh, alt_mdb_bh) pinned for the lifetime of the mount and write into them in place. If a write against the backing device fails, the block layer clears BH_Uptodate on the buffer (end_buffer_write_sync(), fs/buffer.c) to mark its contents as no longer trustworthy. !buffer_uptodate(bh) WARNING: fs/buffer.c:1093 at mark_buffer_dirty+0x299/0x410 fs/buffer.c:1093, CPU#0: syz.1.1033/6784 Modules linked in: CPU: 0 UID: 0 PID: 6784 Comm: syz.1.1033 Not tainted syzkaller #0 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 RIP: 0010:mark_buffer_dirty+0x299/0x410 fs/buffer.c:1093 Code: 4c 89 f7 e8 f9 0d d9 ff 49 8b 3e be 40 00 00 00 5b 41 5c 41 5e 41 5f 5d e9 d4 5e fb ff e8 af e7 69 ff eb 8c e8 a8 e7 69 ff 90 <0f> 0b 90 e9 a5 fd ff ff e8 9a e7 69 ff 90 0f 0b 90 e9 cf fd ff ff RSP: 0018:ffffc90005d379a8 EFLAGS: 00010293 RAX: ffffffff825c9ae8 RBX: ffff8880123aa700 RCX: ffff888034a30000 RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000002 RBP: 1ffff1100a45f401 R08: ffff8880123aa707 R09: 1ffff110024754e0 R10: dffffc0000000000 R11: ffffed10024754e1 R12: dffffc0000000000 R13: ffff8880522fa668 R14: ffff888045ba945b R15: ffff888045ba9400 FS: 000055556b366500(0000) GS:ffff88808c54e000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000001b31a63fff CR3: 0000000034b1d000 CR4: 0000000000352ef0 Call Trace: <TASK> hfs_mdb_commit+0x503/0x1160 fs/hfs/mdb.c:309 hfs_sync_fs+0x1d/0x30 fs/hfs/super.c:38 sync_filesystem+0x1cf/0x230 fs/sync.c:66 fs_bdev_sync+0x2c/0x50 fs/super.c:1433 blkdev_flushbuf block/ioctl.c:520 [inline] blkdev_common_ioctl+0x12e1/0x3250 block/ioctl.c:658 blkdev_ioctl+0x528/0x740 block/ioctl.c:791 vfs_ioctl fs/ioctl.c:51 [inline] __do_sys_ioctl fs/ioctl.c:597 [inline] __se_sys_ioctl+0xfc/0x170 fs/ioctl.c:583 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x174/0x580 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7f1d9239de59 Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48 RSP: 002b:00007fffd0ece148 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 00007f1d92625fa0 RCX: 00007f1d9239de59 RDX: 0000000000000000 RSI: 0000000000001261 RDI: 0000000000000004 RBP: 00007f1d92433e6f R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 R13: 00007f1d92625fac R14: 00007f1d92625fa0 R15: 00007f1d92625fa0 </TASK> This was found by fuzzing an HFS image on a loop device backed by a memfd; under memory pressure the shmem write-back path returned -ENOSPC (mm/shmem.c, shmem_acct_blocks()), which surfaced as a plain write error on the block device. The call path: ioctl(BLKFLSBUF) -> blkdev_common_ioctl() -> sync_filesystem() -> hfs_sync_fs() -> hfs_mdb_commit(). Check buffer_uptodate() on mdb_bh/alt_mdb_bh before dirtying them. If either has gone stale, mark the volume read-only and skip the write instead of asserting on it. Also, hfs_mdb_commit() returns -EIO error code in such situation. As a result, hfs_sync_fs() can report the failure instead of always returning 0. The sync()/fsync()/BLKFLSBUF now observe -EIO instead of silently succeeding while the volume goes read-only underneath them. Reported-by: syzbot+c149ad75e9633be0c1ad@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=c149ad75e9633be0c1ad 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/20260709225001.473320-2-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-07-14hfs: fix error code when writing beyond volume capacityViacheslav Dubeyko
Likewise HFS+, HFS has the same issue of returning the -ENOSPC error code instead of -EFBIG in the case if there is the effort to write beyond 8TiB. The root cause is that hfs_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 hfs_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. 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/20260706221804.140295-2-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-07-14hfs: validate catalog CNIDs before instantiating inodesDavid Maximiliano Hermitte
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. Validate the record found by the second lookup before returning it. Read the already-found record with hfs_bnode_read(), require the exact fixed size for file and directory records, reject other record types, and verify that the stored CNID matches the requested CNID. Also validate reserved CNIDs in hfs_read_inode() before populating the inode, propagate hfs_read_inode() failures from the resource-fork lookup path, and reject bad resource-fork and root inodes. Keep hfs_write_inode() unchanged, so corrupted catalog records are rejected before reaching its existing reserved-CNID BUG() path. Reported-by: syzbot+97e301b4b82ae803d21b@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=97e301b4b82ae803d21b Cc: George Anthony Vernon <contact@gvernon.com> Cc: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Signed-off-by: David Maximiliano Hermitte <davemadmaxxx@gmail.com> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260708215636.73815-1-davemadmaxxx@gmail.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-07-01hfs: 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 hfs_mkdir() is redundant. Drop it. Assisted-by: LLM Signed-off-by: Jori Koolstra <jkoolstra@xs4all.nl> Link: https://patch.msgid.link/20260630105400.68459-13-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-27hfs: rework hfsplus_readdir() logicViacheslav Dubeyko
The xfstests' test-case generic/637 fails with error: FSTYP -- hfs PLATFORM -- Linux/x86_64 kvm-xfstests 6.15.0-rc4-xfstests-g00b827f0cffa #1 SMP PREEMPT_DYNAMIC Fri May 25 MKFS_OPTIONS -- /dev/vdc MOUNT_OPTIONS -- /dev/vdc /vdc 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) Likewise HFS+, currently, HFS has very complicated and fragile logic of rd->file->f_pos correction in hfs_delete_cat(). This patch removes this logic and it stores the current pos into hfs_readdir_data. Finally, if rd->pos == ctx->pos then hfs_readdir() tries to find the position in b-tree's node by means of hfs_cat_key. This position is used to re-start the folder's content traversal. sudo ./check generic/637 FSTYP -- hfs PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.1.0-rc1+ #55 SMP PREEMPT_DYNAMIC Tue May 19 15:18:02 PDT 2026 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/637 32s ... 31s Ran: generic/637 Passed all 1 tests Closes: https://github.com/hfs-linux-kernel/hfs-linux-kernel/issues/65 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/20260519222811.1311071-2-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-05-19hfs: disable the updating of file access times (atime)Viacheslav Dubeyko
The xfstests' test-case generic/003 fails with errors: sudo ./check generic/003 FSTYP -- hfs PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #18 SMP PREEMPT_DYNAMIC Fri Mar 13 17:54:19 PDT 2026 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch output mismatch QA output created by 003 ERROR: access time has changed for file1 after remount ERROR: access time has changed after modifying file1 ERROR: change time has not been updated after changing file1 ERROR: access time has changed for file in read-only filesystem Silence is golden This patch fixes the issue with change time by adding inode_set_ctime_current() and mark_inode_dirty() in hfs_rename(). Also, it reworks hfs_inode_setattr() by changing simple_inode_init_ts() on inode_set_mtime_to_ts() and inode_set_ctime_current() calls. HFS hasn't any field in on-disk layout that can keep the file/folder access times (atime). It was added setting of SB_NOATIME in SB_NOATIME. Finally, we have only atime related errors in generic/003 output: sudo ./check generic/003 FSTYP -- hfs PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.1.0-rc1+ #52 SMP PREEMPT_DYNAMIC Wed May 13 15:04:37 PDT 2026 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch QA output created by 003 ERROR: access time has not been updated after accessing file1 first time ERROR: access time has not been updated after accessing file2 ERROR: access time has not been updated after accessing file3 second time ERROR: access time has not been updated after accessing file3 third time Silence is golden The generic/003 test-case needs to be disabled for HFS case because it cannot support the file/folder access times (atime). Closes: https://github.com/hfs-linux-kernel/hfs-linux-kernel/issues/3 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/20260514195630.354206-2-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-05-19hfs: fix incorrect inode ID assignment in hfs_new_inode()Viacheslav Dubeyko
The xfstests' test-case generic/003 reveals the HFS volume corruption: sudo ./check generic/003 FSTYP -- hfs PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #18 SMP PREEMPT_DYNAMIC Fri Mar 13 17:54:19 PDT 2026 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/003 51s ... _check_generic_filesystem: filesystem on /dev/loop51 is inconsistent sudo fsck.hfs -d /dev/loop51 ** /dev/loop51 Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. Executing fsck_hfs (version 540.1-Linux). ** Checking HFS volume. The volume name is untitled ** Checking extents overflow file. ** Checking catalog file. ** Checking catalog hierarchy. ** Checking volume bitmap. ** Checking volume information. invalid MDB drNxtCNID Master Directory Block needs minor repair (1, 0) Verify Status: VIStat = 0x8000, ABTStat = 0x0000 EBTStat = 0x0000 CBTStat = 0x0000 CatStat = 0x00000000 ** Repairing volume. ** Rechecking volume. ** Checking HFS volume. The volume name is untitled ** Checking extents overflow file. ** Checking catalog file. ** Checking catalog hierarchy. ** Checking volume bitmap. ** Checking volume information. ** The volume untitled was repaired successfully. The reason of corruption is incorrect value of drNxtCNID (next CNID) in the MDB or superblock. The generic/003 test-case creates several new inodes: kernel: run fstests generic/003 hfs: hfs_mdb_get():179 next_id 16 hfs: hfs_mdb_get():179 next_id 16 hfs: hfs_new_inode():208 next_id 17 hfs: hfs_new_inode():208 next_id 18 hfs: hfs_mdb_commit():307 next_id 18 hfs: hfs_mdb_get():179 next_id 18 hfs: hfs_new_inode():208 next_id 19 hfs: hfs_new_inode():208 next_id 20 hfs_mdb_commit():307 next_id 20 hfs: hfs_mdb_get():179 next_id 20 hfs: hfs_new_inode():208 next_id 21 hfs: hfs_mdb_commit():307 next_id 21 hfs: hfs_mdb_get():179 next_id 21 The final assigned CNID was 21 but fsck correct it on 22. It is possible to see that the reason of the issue is incrementing the next_id value at first and assigning already incremented value to the inode->i_ino: struct inode *hfs_new_inode(...) { <skipped> next_id = atomic64_inc_return(&HFS_SB(sb)->next_id); <skipped> inode->i_ino = (u32)next_id; <skipped> } This patch fixes the issue by assigning the decremented value to inode->i_ino. Fixes: a06ec283e125 ("hfs: add logic of correcting a next unused CNID") 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/20260514195518.354108-2-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2026-05-11hfs: Implement fileattr_get for case sensitivityChuck Lever
Report HFS case sensitivity behavior via the FS_XFLAG_CASEFOLD flag. HFS is always case-insensitive (using Mac OS Roman case folding) and always preserves case at rest. 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-6-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-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-13Merge tag 'vfs-7.1-rc1.misc' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs Pull misc vfs updates from Christian Brauner: "Features: - coredump: add tracepoint for coredump events - fs: hide file and bfile caches behind runtime const machinery Fixes: - fix architecture-specific compat_ftruncate64 implementations - dcache: Limit the minimal number of bucket to two - fs/omfs: reject s_sys_blocksize smaller than OMFS_DIR_START - fs/mbcache: cancel shrink work before destroying the cache - dcache: permit dynamic_dname()s up to NAME_MAX Cleanups: - remove or unexport unused fs_context infrastructure - trivial ->setattr cleanups - selftests/filesystems: Assume that TIOCGPTPEER is defined - writeback: fix kernel-doc function name mismatch for wb_put_many() - autofs: replace manual symlink buffer allocation in autofs_dir_symlink - init/initramfs.c: trivial fix: FSM -> Finite-state machine - fs: remove stale and duplicate forward declarations - readdir: Introduce dirent_size() - fs: Replace user_access_{begin/end} by scoped user access - kernel: acct: fix duplicate word in comment - fs: write a better comment in step_into() concerning .mnt assignment - fs: attr: fix comment formatting and spelling issues" * tag 'vfs-7.1-rc1.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (28 commits) dcache: permit dynamic_dname()s up to NAME_MAX fs: attr: fix comment formatting and spelling issues fs: hide file and bfile caches behind runtime const machinery fs: write a better comment in step_into() concerning .mnt assignment proc: rename proc_notify_change to proc_setattr proc: rename proc_setattr to proc_nochmod_setattr affs: rename affs_notify_change to affs_setattr adfs: rename adfs_notify_change to adfs_setattr hfs: update comments on hfs_inode_setattr kernel: acct: fix duplicate word in comment fs: Replace user_access_{begin/end} by scoped user access readdir: Introduce dirent_size() coredump: add tracepoint for coredump events fs: remove do_sys_truncate fs: pass on FTRUNCATE_* flags to do_truncate fs: fix archiecture-specific compat_ftruncate64 fs: remove stale and duplicate forward declarations init/initramfs.c: trivial fix: FSM -> Finite-state machine autofs: replace manual symlink buffer allocation in autofs_dir_symlink fs/mbcache: cancel shrink work before destroying the cache ...
2026-03-26hfs: update comments on hfs_inode_setattrChristoph Hellwig
The top of function comment about hfs_inode_setattr is severely out of date and reference a previous name for this function. Remove it, and update the comments in the file to record the still relevant bits directly. Signed-off-by: Christoph Hellwig <hch@lst.de> Link: https://patch.msgid.link/20260325063711.3298685-2-hch@lst.de Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Christian Brauner <brauner@kernel.org>
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-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-01-06hfs: Replace BUG_ON with error handling for CNID count checksJori Koolstra
In a06ec283e125 next_id, folder_count, and file_count in the super block info were expanded to 64 bits, and BUG_ONs were added to detect overflow. This triggered an error reported by syzbot: if the MDB is corrupted, the BUG_ON is triggered. This patch replaces this mechanism with proper error handling and resolves the syzbot reported bug. Singed-off-by: Jori Koolstra <jkoolstra@xs4all.nl> Reported-by: syzbot+17cc9bb6d8d69b4139f0@syzkaller.appspotmail.com Closes: https://syzbot.org/bug?extid=17cc9bb6d8d69b4139f0 Signed-off-by: Jori Koolstra <jkoolstra@xs4all.nl> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20251220191006.2465256-1-jkoolstra@xs4all.nl Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2025-12-15hfs: ensure sb->s_fs_info is always cleaned upMehdi Ben Hadj Khelifa
When hfs 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 hfs_fill_super() takes ownership of the filesystem-specific s_fs_info data it was leaked. Fix this by freeing sb->s_fs_info in hfs_kill_super(). Cc: stable@vger.kernel.org Fixes: ffcd06b6d13b ("hfs: convert hfs to use the new mount api") Reported-by: syzbot+ad45f827c88778ff7df6@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=ad45f827c88778ff7df6 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-2-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-11-25hfs/hfsplus: move on-disk layout declarations into hfs_common.hViacheslav Dubeyko
Currently, HFS declares on-disk layout's metadata structures in fs/hfs/hfs.h and HFS+ declares it in fs/hfsplus/hfsplus_raw.h. However, HFS and HFS+ on-disk layouts have some similarity and overlapping in declarations. As a result, fs/hfs/hfs.h and fs/hfsplus/hfsplus_raw.h contain multiple duplicated declarations. Moreover, both HFS and HFS+ drivers contain completely similar implemented functionality in multiple places. This patch is moving the on-disk layout declarations from fs/hfs/hfs.h and fs/hfsplus/hfsplus_raw.h into include/linux/hfs_common.h with the goal to exclude the duplication in declarations. 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. 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 Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2025-11-19hfs: introduce KUnit tests for HFS string operationsViacheslav Dubeyko
This patch implements the initial Kunit based set of unit tests for HFS string operations. It checks functionality of hfs_strcmp(), hfs_hash_dentry(), and hfs_compare_dentry() methods. ./tools/testing/kunit/kunit.py run --kunitconfig ./fs/hfs/.kunitconfig [16:04:50] Configuring KUnit Kernel ... Regenerating .config ... Populating config with: $ make ARCH=um O=.kunit olddefconfig [16:04:51] Building KUnit Kernel ... Populating config with: $ make ARCH=um O=.kunit olddefconfig Building with: $ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=22 [16:04:59] Starting KUnit Kernel (1/1)... [16:04:59] ============================================================ Running tests with: $ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt [16:04:59] ================= hfs_string (3 subtests) ================== [16:04:59] [PASSED] hfs_strcmp_test [16:04:59] [PASSED] hfs_hash_dentry_test [16:04:59] [PASSED] hfs_compare_dentry_test [16:04:59] =================== [PASSED] hfs_string ==================== [16:04:59] ============================================================ [16:04:59] Testing complete. Ran 3 tests: passed: 3 [16:04:59] Elapsed time: 9.087s total, 1.310s configuring, 7.611s building, 0.125s running v2 Fix linker error. v3 Chen Linxuan suggested to use EXPORT_SYMBOL_IF_KUNIT. Signed-off-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com> cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org cc: Chen Linxuan <me@black-desk.cn> Reviewed-by: Chen Linxuan <me@black-desk.cn> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20250912225022.1083313-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2025-11-13hfs/hfsplus: prevent getting negative values of offset/lengthViacheslav Dubeyko
The syzbot reported KASAN out-of-bounds issue in hfs_bnode_move(): [ 45.588165][ T9821] hfs: dst 14, src 65536, len -65536 [ 45.588895][ T9821] ================================================================== [ 45.590114][ T9821] BUG: KASAN: out-of-bounds in hfs_bnode_move+0xfd/0x140 [ 45.591127][ T9821] Read of size 18446744073709486080 at addr ffff888035935400 by task repro/9821 [ 45.592207][ T9821] [ 45.592420][ T9821] CPU: 0 UID: 0 PID: 9821 Comm: repro Not tainted 6.16.0-rc7-dirty #42 PREEMPT(full) [ 45.592428][ T9821] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 45.592431][ T9821] Call Trace: [ 45.592434][ T9821] <TASK> [ 45.592437][ T9821] dump_stack_lvl+0x1c1/0x2a0 [ 45.592446][ T9821] ? __virt_addr_valid+0x1c8/0x5c0 [ 45.592454][ T9821] ? __pfx_dump_stack_lvl+0x10/0x10 [ 45.592461][ T9821] ? rcu_is_watching+0x15/0xb0 [ 45.592469][ T9821] ? lock_release+0x4b/0x3e0 [ 45.592476][ T9821] ? __virt_addr_valid+0x1c8/0x5c0 [ 45.592483][ T9821] ? __virt_addr_valid+0x4a5/0x5c0 [ 45.592491][ T9821] print_report+0x17e/0x7c0 [ 45.592497][ T9821] ? __virt_addr_valid+0x1c8/0x5c0 [ 45.592504][ T9821] ? __virt_addr_valid+0x4a5/0x5c0 [ 45.592511][ T9821] ? __phys_addr+0xd3/0x180 [ 45.592519][ T9821] ? hfs_bnode_move+0xfd/0x140 [ 45.592526][ T9821] kasan_report+0x147/0x180 [ 45.592531][ T9821] ? _printk+0xcf/0x120 [ 45.592537][ T9821] ? hfs_bnode_move+0xfd/0x140 [ 45.592544][ T9821] ? hfs_bnode_move+0xfd/0x140 [ 45.592552][ T9821] kasan_check_range+0x2b0/0x2c0 [ 45.592557][ T9821] ? hfs_bnode_move+0xfd/0x140 [ 45.592565][ T9821] __asan_memmove+0x29/0x70 [ 45.592572][ T9821] hfs_bnode_move+0xfd/0x140 [ 45.592580][ T9821] hfs_brec_remove+0x473/0x560 [ 45.592589][ T9821] hfs_cat_move+0x6fb/0x960 [ 45.592598][ T9821] ? __pfx_hfs_cat_move+0x10/0x10 [ 45.592607][ T9821] ? seqcount_lockdep_reader_access+0x122/0x1c0 [ 45.592614][ T9821] ? lockdep_hardirqs_on+0x9c/0x150 [ 45.592631][ T9821] ? __lock_acquire+0xaec/0xd80 [ 45.592641][ T9821] hfs_rename+0x1dc/0x2d0 [ 45.592649][ T9821] ? __pfx_hfs_rename+0x10/0x10 [ 45.592657][ T9821] vfs_rename+0xac6/0xed0 [ 45.592664][ T9821] ? __pfx_vfs_rename+0x10/0x10 [ 45.592670][ T9821] ? d_alloc+0x144/0x190 [ 45.592677][ T9821] ? bpf_lsm_path_rename+0x9/0x20 [ 45.592683][ T9821] ? security_path_rename+0x17d/0x490 [ 45.592691][ T9821] do_renameat2+0x890/0xc50 [ 45.592699][ T9821] ? __pfx_do_renameat2+0x10/0x10 [ 45.592707][ T9821] ? getname_flags+0x1e5/0x540 [ 45.592714][ T9821] __x64_sys_rename+0x82/0x90 [ 45.592720][ T9821] ? entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 45.592725][ T9821] do_syscall_64+0xf3/0x3a0 [ 45.592741][ T9821] ? exc_page_fault+0x9f/0xf0 [ 45.592748][ T9821] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 45.592754][ T9821] RIP: 0033:0x7f7f73fe3fc9 [ 45.592760][ T9821] Code: 00 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 48 [ 45.592765][ T9821] RSP: 002b:00007ffc7e116cf8 EFLAGS: 00000283 ORIG_RAX: 0000000000000052 [ 45.592772][ T9821] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f7f73fe3fc9 [ 45.592776][ T9821] RDX: 0000200000000871 RSI: 0000200000000780 RDI: 00002000000003c0 [ 45.592781][ T9821] RBP: 00007ffc7e116d00 R08: 0000000000000000 R09: 00007ffc7e116d30 [ 45.592784][ T9821] R10: fffffffffffffff0 R11: 0000000000000283 R12: 00005557e81f8250 [ 45.592788][ T9821] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 [ 45.592795][ T9821] </TASK> [ 45.592797][ T9821] [ 45.619721][ T9821] The buggy address belongs to the physical page: [ 45.620300][ T9821] page: refcount:1 mapcount:1 mapping:0000000000000000 index:0x559a88174 pfn:0x35935 [ 45.621150][ T9821] memcg:ffff88810a1d5b00 [ 45.621531][ T9821] anon flags: 0xfff60000020838(uptodate|dirty|lru|owner_2|swapbacked|node=0|zone=1|lastcpupid=0x7ff) [ 45.622496][ T9821] raw: 00fff60000020838 ffffea0000d64d88 ffff888021753e10 ffff888029da0771 [ 45.623260][ T9821] raw: 0000000559a88174 0000000000000000 0000000100000000 ffff88810a1d5b00 [ 45.624030][ T9821] page dumped because: kasan: bad access detected [ 45.624602][ T9821] page_owner tracks the page as allocated [ 45.625115][ T9821] page last allocated via order 0, migratetype Movable, gfp_mask 0x140dca(GFP_HIGHUSER_MOVABLE|__GFP_ZERO0 [ 45.626685][ T9821] post_alloc_hook+0x240/0x2a0 [ 45.627127][ T9821] get_page_from_freelist+0x2101/0x21e0 [ 45.627628][ T9821] __alloc_frozen_pages_noprof+0x274/0x380 [ 45.628154][ T9821] alloc_pages_mpol+0x241/0x4b0 [ 45.628593][ T9821] vma_alloc_folio_noprof+0xe4/0x210 [ 45.629066][ T9821] folio_prealloc+0x30/0x180 [ 45.629487][ T9821] __handle_mm_fault+0x34bd/0x5640 [ 45.629957][ T9821] handle_mm_fault+0x40e/0x8e0 [ 45.630392][ T9821] do_user_addr_fault+0xa81/0x1390 [ 45.630862][ T9821] exc_page_fault+0x76/0xf0 [ 45.631273][ T9821] asm_exc_page_fault+0x26/0x30 [ 45.631712][ T9821] page last free pid 5269 tgid 5269 stack trace: [ 45.632281][ T9821] free_unref_folios+0xc73/0x14c0 [ 45.632740][ T9821] folios_put_refs+0x55b/0x640 [ 45.633177][ T9821] free_pages_and_swap_cache+0x26d/0x510 [ 45.633685][ T9821] tlb_flush_mmu+0x3a0/0x680 [ 45.634105][ T9821] tlb_finish_mmu+0xd4/0x200 [ 45.634525][ T9821] exit_mmap+0x44c/0xb70 [ 45.634914][ T9821] __mmput+0x118/0x420 [ 45.635286][ T9821] exit_mm+0x1da/0x2c0 [ 45.635659][ T9821] do_exit+0x652/0x2330 [ 45.636039][ T9821] do_group_exit+0x21c/0x2d0 [ 45.636457][ T9821] __x64_sys_exit_group+0x3f/0x40 [ 45.636915][ T9821] x64_sys_call+0x21ba/0x21c0 [ 45.637342][ T9821] do_syscall_64+0xf3/0x3a0 [ 45.637756][ T9821] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 45.638290][ T9821] page has been migrated, last migrate reason: numa_misplaced [ 45.638956][ T9821] [ 45.639173][ T9821] Memory state around the buggy address: [ 45.639677][ T9821] ffff888035935300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 45.640397][ T9821] ffff888035935380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 45.641117][ T9821] >ffff888035935400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 45.641837][ T9821] ^ [ 45.642207][ T9821] ffff888035935480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 45.642929][ T9821] ffff888035935500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 45.643650][ T9821] ================================================================== This commit [1] fixes the issue if an offset inside of b-tree node or length of the request is bigger than b-tree node. However, this fix is still not ready for negative values of the offset or length. Moreover, negative values of the offset or length doesn't make sense for b-tree's operations. Because we could try to access the memory address outside of the beginning of memory page's addresses range. Also, using of negative values make logic very complicated, unpredictable, and we could access the wrong item(s) in the b-tree node. This patch changes b-tree interface by means of converting signed integer arguments of offset and length on u32 type. Such conversion has goal to prevent of using negative values unintentionally or by mistake in b-tree operations. [1] 'commit a431930c9bac ("hfs: fix slab-out-of-bounds in hfs_bnode_read()")' 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/20251002200020.2578311-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2025-11-06hfs: fix potential use after free in hfs_correct_next_unused_CNID()Dan Carpenter
This code calls hfs_bnode_put(node) which drops the refcount and then dreferences "node" on the next line. It's only safe to use "node" when we're holding a reference so flip these two lines around. Fixes: a06ec283e125 ("hfs: add logic of correcting a next unused CNID") Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/aN-Xw8KnbSnuIcLk@stanley.mountain Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2025-10-20Coccinelle-based conversion to use ->i_state accessorsMateusz Guzik
All places were patched by coccinelle with the default expecting that ->i_lock is held, afterwards entries got fixed up by hand to use unlocked variants as needed. The script: @@ expression inode, flags; @@ - inode->i_state & flags + inode_state_read(inode) & flags @@ expression inode, flags; @@ - inode->i_state &= ~flags + inode_state_clear(inode, flags) @@ expression inode, flag1, flag2; @@ - inode->i_state &= ~flag1 & ~flag2 + inode_state_clear(inode, flag1 | flag2) @@ expression inode, flags; @@ - inode->i_state |= flags + inode_state_set(inode, flags) @@ expression inode, flags; @@ - inode->i_state = flags + inode_state_assign(inode, flags) @@ expression inode, flags; @@ - flags = inode->i_state + flags = inode_state_read(inode) @@ expression inode, flags; @@ - READ_ONCE(inode->i_state) & flags + inode_state_read(inode) & flags Signed-off-by: Mateusz Guzik <mjguzik@gmail.com> Signed-off-by: Christian Brauner <brauner@kernel.org>
2025-09-24hfs/hfsplus: rework debug output subsystemViacheslav Dubeyko
Currently, HFS/HFS+ has very obsolete and inconvenient debug output subsystem. Also, the code is duplicated in HFS and HFS+ driver. This patch introduces linux/hfs_common.h for gathering common declarations, inline functions, and common short methods. Currently, this file contains only hfs_dbg() function that employs pr_debug() with the goal to print a debug-level messages conditionally. So, now, it is possible to enable the debug output by means of: echo 'file extent.c +p' > /proc/dynamic_debug/control echo 'func hfsplus_evict_inode +p' > /proc/dynamic_debug/control And debug output looks like this: hfs: pid 5831:fs/hfs/catalog.c:228 hfs_cat_delete(): delete_cat: 00,48 hfs: pid 5831:fs/hfs/extent.c:484 hfs_file_truncate(): truncate: 48, 409600 -> 0 hfs: pid 5831:fs/hfs/extent.c:212 hfs_dump_extent(): hfs: pid 5831:fs/hfs/extent.c:214 hfs_dump_extent(): 78:4 hfs: pid 5831:fs/hfs/extent.c:214 hfs_dump_extent(): 0:0 hfs: pid 5831:fs/hfs/extent.c:214 hfs_dump_extent(): 0:0 v4 Debug messages have been reworked and information about new HFS/HFS+ shared declarations file has been added to MAINTAINERS file. v5 Yangtao Li suggested to clean up debug output and fix several typos. 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 cc: Johannes Thumshirn <Johannes.Thumshirn@wdc.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2025-08-31hfs: clear offset and space out of valid records in b-tree nodeViacheslav Dubeyko
Currently, hfs_brec_remove() executes moving records towards the location of deleted record and it updates offsets of moved records. However, the hfs_brec_remove() logic ignores the "mess" of b-tree node's free space and it doesn't touch the offsets out of records number. Potentially, it could confuse fsck or driver logic or to be a reason of potential corruption cases. This patch reworks the logic of hfs_brec_remove() by means of clearing freed space of b-tree node after the records moving. And it clear the last offset that keeping old location of free space because now the offset before this one is keeping the actual offset to the free space after the record deletion. 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/20250815194918.38165-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2025-08-31hfs: add logic of correcting a next unused CNIDViacheslav Dubeyko
The generic/736 xfstest fails for HFS case: BEGIN TEST default (1 test): hfs Mon May 5 03:18:32 UTC 2025 DEVICE: /dev/vdb HFS_MKFS_OPTIONS: MOUNT_OPTIONS: MOUNT_OPTIONS FSTYP -- hfs PLATFORM -- Linux/x86_64 kvm-xfstests 6.15.0-rc4-xfstests-g00b827f0cffa #1 SMP PREEMPT_DYNAMIC Fri May 25 MKFS_OPTIONS -- /dev/vdc MOUNT_OPTIONS -- /dev/vdc /vdc generic/736 [03:18:33][ 3.510255] run fstests generic/736 at 2025-05-05 03:18:33 _check_generic_filesystem: filesystem on /dev/vdb is inconsistent (see /results/hfs/results-default/generic/736.full for details) Ran: generic/736 Failures: generic/736 Failed 1 of 1 tests The HFS volume becomes corrupted after the test run: sudo fsck.hfs -d /dev/loop50 ** /dev/loop50 Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. Executing fsck_hfs (version 540.1-Linux). ** Checking HFS volume. The volume name is untitled ** Checking extents overflow file. ** Checking catalog file. ** Checking catalog hierarchy. ** Checking volume bitmap. ** Checking volume information. invalid MDB drNxtCNID Master Directory Block needs minor repair (1, 0) Verify Status: VIStat = 0x8000, ABTStat = 0x0000 EBTStat = 0x0000 CBTStat = 0x0000 CatStat = 0x00000000 ** Repairing volume. ** Rechecking volume. ** Checking HFS volume. The volume name is untitled ** Checking extents overflow file. ** Checking catalog file. ** Checking catalog hierarchy. ** Checking volume bitmap. ** Checking volume information. ** The volume untitled was repaired successfully. The main reason of the issue is the absence of logic that corrects mdb->drNxtCNID/HFS_SB(sb)->next_id (next unused CNID) after deleting a record in Catalog File. This patch introduces a hfs_correct_next_unused_CNID() method that implements the necessary logic. In the case of Catalog File's record delete operation, the function logic checks that (deleted_CNID + 1) == next_unused_CNID and it finds/sets the new value of next_unused_CNID. sudo ./check generic/736 FSTYP -- hfs PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.15.0+ #6 SMP PREEMPT_DYNAMIC Tue Jun 10 15:02:48 PDT 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/736 33s Ran: generic/736 Passed all 1 tests sudo fsck.hfs -d /dev/loop50 ** /dev/loop50 Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. Executing fsck_hfs (version 540.1-Linux). ** Checking HFS volume. The volume name is untitled ** Checking extents overflow file. ** Checking catalog file. ** Checking catalog hierarchy. ** Checking volume bitmap. ** Checking volume information. ** The volume untitled appears to be OK Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20250610231609.551930-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2025-08-31hfs: fix KMSAN uninit-value issue in hfs_find_set_zero_bits()Viacheslav Dubeyko
The syzbot reported issue in hfs_find_set_zero_bits(): ===================================================== BUG: KMSAN: uninit-value in hfs_find_set_zero_bits+0x74d/0xb60 fs/hfs/bitmap.c:45 hfs_find_set_zero_bits+0x74d/0xb60 fs/hfs/bitmap.c:45 hfs_vbm_search_free+0x13c/0x5b0 fs/hfs/bitmap.c:151 hfs_extend_file+0x6a5/0x1b00 fs/hfs/extent.c:408 hfs_get_block+0x435/0x1150 fs/hfs/extent.c:353 __block_write_begin_int+0xa76/0x3030 fs/buffer.c:2151 block_write_begin fs/buffer.c:2262 [inline] cont_write_begin+0x10e1/0x1bc0 fs/buffer.c:2601 hfs_write_begin+0x85/0x130 fs/hfs/inode.c:52 cont_expand_zero fs/buffer.c:2528 [inline] cont_write_begin+0x35a/0x1bc0 fs/buffer.c:2591 hfs_write_begin+0x85/0x130 fs/hfs/inode.c:52 hfs_file_truncate+0x1d6/0xe60 fs/hfs/extent.c:494 hfs_inode_setattr+0x964/0xaa0 fs/hfs/inode.c:654 notify_change+0x1993/0x1aa0 fs/attr.c:552 do_truncate+0x28f/0x310 fs/open.c:68 do_ftruncate+0x698/0x730 fs/open.c:195 do_sys_ftruncate fs/open.c:210 [inline] __do_sys_ftruncate fs/open.c:215 [inline] __se_sys_ftruncate fs/open.c:213 [inline] __x64_sys_ftruncate+0x11b/0x250 fs/open.c:213 x64_sys_call+0xfe3/0x3db0 arch/x86/include/generated/asm/syscalls_64.h:78 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xd9/0x210 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f Uninit was created at: slab_post_alloc_hook mm/slub.c:4154 [inline] slab_alloc_node mm/slub.c:4197 [inline] __kmalloc_cache_noprof+0x7f7/0xed0 mm/slub.c:4354 kmalloc_noprof include/linux/slab.h:905 [inline] hfs_mdb_get+0x1cc8/0x2a90 fs/hfs/mdb.c:175 hfs_fill_super+0x3d0/0xb80 fs/hfs/super.c:337 get_tree_bdev_flags+0x6e3/0x920 fs/super.c:1681 get_tree_bdev+0x38/0x50 fs/super.c:1704 hfs_get_tree+0x35/0x40 fs/hfs/super.c:388 vfs_get_tree+0xb0/0x5c0 fs/super.c:1804 do_new_mount+0x738/0x1610 fs/namespace.c:3902 path_mount+0x6db/0x1e90 fs/namespace.c:4226 do_mount fs/namespace.c:4239 [inline] __do_sys_mount fs/namespace.c:4450 [inline] __se_sys_mount+0x6eb/0x7d0 fs/namespace.c:4427 __x64_sys_mount+0xe4/0x150 fs/namespace.c:4427 x64_sys_call+0xfa7/0x3db0 arch/x86/include/generated/asm/syscalls_64.h:166 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0xd9/0x210 arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x77/0x7f CPU: 1 UID: 0 PID: 12609 Comm: syz.1.2692 Not tainted 6.16.0-syzkaller #0 PREEMPT(none) Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 07/12/2025 ===================================================== The HFS_SB(sb)->bitmap buffer is allocated in hfs_mdb_get(): HFS_SB(sb)->bitmap = kmalloc(8192, GFP_KERNEL); Finally, it can trigger the reported issue because kmalloc() doesn't clear the allocated memory. If allocated memory contains only zeros, then everything will work pretty fine. But if the allocated memory contains the "garbage", then it can affect the bitmap operations and it triggers the reported issue. This patch simply exchanges the kmalloc() on kzalloc() with the goal to guarantee the correctness of bitmap operations. Because, newly created allocation bitmap should have all available blocks free. Potentially, initialization bitmap's read operation could not fill the whole allocated memory and "garbage" in the not initialized memory will be the reason of volume coruptions and file system driver bugs. Reported-by: syzbot <syzbot+773fa9d79b29bd8b6831@syzkaller.appspotmail.com> Closes: https://syzkaller.appspot.com/bug?extid=773fa9d79b29bd8b6831 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/20250820230636.179085-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2025-08-31hfs: make proper initalization of struct hfs_find_dataViacheslav Dubeyko
Potenatially, __hfs_ext_read_extent() could operate by not initialized values of fd->key after hfs_brec_find() call: static inline int __hfs_ext_read_extent(struct hfs_find_data *fd, struct hfs_extent *extent, u32 cnid, u32 block, u8 type) { int res; hfs_ext_build_key(fd->search_key, cnid, block, type); fd->key->ext.FNum = 0; res = hfs_brec_find(fd); if (res && res != -ENOENT) return res; if (fd->key->ext.FNum != fd->search_key->ext.FNum || fd->key->ext.FkType != fd->search_key->ext.FkType) return -ENOENT; if (fd->entrylength != sizeof(hfs_extent_rec)) return -EIO; hfs_bnode_read(fd->bnode, extent, fd->entryoffset, sizeof(hfs_extent_rec)); return 0; } This patch changes kmalloc() on kzalloc() in hfs_find_init() and intializes fd->record, fd->keyoffset, fd->keylength, fd->entryoffset, fd->entrylength for the case if hfs_brec_find() has been found nothing in the b-tree node. 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/20250818225252.126427-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2025-07-28Merge tag 'hfs-v6.17-tag1' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs Pull hfs/hfsplus updates from Viacheslav Dubeyko: "Johannes Thumshirn has made nice cleanup in hfsplus_submit_bio(). Tetsuo Handa has fixed the syzbot reported issue in hfsplus_create_attributes_file() for the case of corruption the Attributes File's metadata. Yangtao Li has fixed the syzbot reported issue by removing the uneccessary WARN_ON() in hfsplus_free_extents(). Other fixes: - restore generic/001 successful execution by erasing deleted b-tree nodes - eliminate slab-out-of-bounds issue in hfs_bnode_read() and hfsplus_bnode_read() by checking correctness of offset and length when accessing b-tree node contents - eliminate slab-out-of-bounds read in hfsplus_uni2asc() if the b-tree node record has corrupted length of a name that could be bigger than HFSPLUS_MAX_STRLEN - eliminate general protection fault in hfs_find_init() for the case of initial b-tree object creation" * tag 'hfs-v6.17-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs: hfs: fix general protection fault in hfs_find_init() hfs: fix slab-out-of-bounds in hfs_bnode_read() hfsplus: fix slab-out-of-bounds in hfsplus_bnode_read() hfsplus: fix slab-out-of-bounds read in hfsplus_uni2asc() hfsplus: don't use BUG_ON() in hfsplus_create_attributes_file() hfsplus: don't set REQ_SYNC for hfsplus_submit_bio() hfsplus: remove mutex_lock check in hfsplus_free_extents hfs: make splice write available again hfsplus: make splice write available again hfs: fix not erasing deleted b-tree node issue
2025-07-28Merge tag 'vfs-6.17-rc1.mmap_prepare' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs Pull mmap_prepare updates from Christian Brauner: "Last cycle we introduce f_op->mmap_prepare() in c84bf6dd2b83 ("mm: introduce new .mmap_prepare() file callback"). This is preferred to the existing f_op->mmap() hook as it does require a VMA to be established yet, thus allowing the mmap logic to invoke this hook far, far earlier, prior to inserting a VMA into the virtual address space, or performing any other heavy handed operations. This allows for much simpler unwinding on error, and for there to be a single attempt at merging a VMA rather than having to possibly reattempt a merge based on potentially altered VMA state. Far more importantly, it prevents inappropriate manipulation of incompletely initialised VMA state, which is something that has been the cause of bugs and complexity in the past. The intent is to gradually deprecate f_op->mmap, and in that vein this series coverts the majority of file systems to using f_op->mmap_prepare. Prerequisite steps are taken - firstly ensuring all checks for mmap capabilities use the file_has_valid_mmap_hooks() helper rather than directly checking for f_op->mmap (which is now not a valid check) and secondly updating daxdev_mapping_supported() to not require a VMA parameter to allow ext4 and xfs to be converted. Commit bb666b7c2707 ("mm: add mmap_prepare() compatibility layer for nested file systems") handles the nasty edge-case of nested file systems like overlayfs, which introduces a compatibility shim to allow f_op->mmap_prepare() to be invoked from an f_op->mmap() callback. This allows for nested filesystems to continue to function correctly with all file systems regardless of which callback is used. Once we finally convert all file systems, this shim can be removed. As a result, ecryptfs, fuse, and overlayfs remain unaltered so they can nest all other file systems. We additionally do not update resctl - as this requires an update to remap_pfn_range() (or an alternative to it) which we defer to a later series, equally we do not update cramfs which needs a mixed mapping insertion with the same issue, nor do we update procfs, hugetlbfs, syfs or kernfs all of which require VMAs for internal state and hooks. We shall return to all of these later" * tag 'vfs-6.17-rc1.mmap_prepare' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: doc: update porting, vfs documentation to describe mmap_prepare() fs: replace mmap hook with .mmap_prepare for simple mappings fs: convert most other generic_file_*mmap() users to .mmap_prepare() fs: convert simple use of generic_file_*_mmap() to .mmap_prepare() mm/filemap: introduce generic_file_*_mmap_prepare() helpers fs/xfs: transition from deprecated .mmap hook to .mmap_prepare fs/ext4: transition from deprecated .mmap hook to .mmap_prepare fs/dax: make it possible to check dev dax support without a VMA fs: consistently use can_mmap_file() helper mm/nommu: use file_has_valid_mmap_hooks() helper mm: rename call_mmap/mmap_prepare to vfs_mmap/mmap_prepare
2025-07-28Merge tag 'vfs-6.17-rc1.misc' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs Pull misc VFS updates from Christian Brauner: "This contains the usual selections of misc updates for this cycle. Features: - Add ext4 IOCB_DONTCACHE support This refactors the address_space_operations write_begin() and write_end() callbacks to take const struct kiocb * as their first argument, allowing IOCB flags such as IOCB_DONTCACHE to propagate to the filesystem's buffered I/O path. Ext4 is updated to implement handling of the IOCB_DONTCACHE flag and advertises support via the FOP_DONTCACHE file operation flag. Additionally, the i915 driver's shmem write paths are updated to bypass the legacy write_begin/write_end interface in favor of directly calling write_iter() with a constructed synchronous kiocb. Another i915 change replaces a manual write loop with kernel_write() during GEM shmem object creation. Cleanups: - don't duplicate vfs_open() in kernel_file_open() - proc_fd_getattr(): don't bother with S_ISDIR() check - fs/ecryptfs: replace snprintf with sysfs_emit in show function - vfs: Remove unnecessary list_for_each_entry_safe() from evict_inodes() - filelock: add new locks_wake_up_waiter() helper - fs: Remove three arguments from block_write_end() - VFS: change old_dir and new_dir in struct renamedata to dentrys - netfs: Remove unused declaration netfs_queue_write_request() Fixes: - eventpoll: Fix semi-unbounded recursion - eventpoll: fix sphinx documentation build warning - fs/read_write: Fix spelling typo - fs: annotate data race between poll_schedule_timeout() and pollwake() - fs/pipe: set FMODE_NOWAIT in create_pipe_files() - docs/vfs: update references to i_mutex to i_rwsem - fs/buffer: remove comment about hard sectorsize - fs/buffer: remove the min and max limit checks in __getblk_slow() - fs/libfs: don't assume blocksize <= PAGE_SIZE in generic_check_addressable - fs_context: fix parameter name in infofc() macro - fs: Prevent file descriptor table allocations exceeding INT_MAX" * tag 'vfs-6.17-rc1.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (24 commits) netfs: Remove unused declaration netfs_queue_write_request() eventpoll: fix sphinx documentation build warning ext4: support uncached buffered I/O mm/pagemap: add write_begin_get_folio() helper function fs: change write_begin/write_end interface to take struct kiocb * drm/i915: Refactor shmem_pwrite() to use kiocb and write_iter drm/i915: Use kernel_write() in shmem object create eventpoll: Fix semi-unbounded recursion vfs: Remove unnecessary list_for_each_entry_safe() from evict_inodes() fs/libfs: don't assume blocksize <= PAGE_SIZE in generic_check_addressable fs/buffer: remove the min and max limit checks in __getblk_slow() fs: Prevent file descriptor table allocations exceeding INT_MAX fs: Remove three arguments from block_write_end() fs/ecryptfs: replace snprintf with sysfs_emit in show function fs: annotate suspected data race between poll_schedule_timeout() and pollwake() docs/vfs: update references to i_mutex to i_rwsem fs/buffer: remove comment about hard sectorsize fs_context: fix parameter name in infofc() macro VFS: change old_dir and new_dir in struct renamedata to dentrys proc_fd_getattr(): don't bother with S_ISDIR() check ...
2025-07-25hfs: fix general protection fault in hfs_find_init()Viacheslav Dubeyko
The hfs_find_init() method can trigger the crash if tree pointer is NULL: [ 45.746290][ T9787] Oops: general protection fault, probably for non-canonical address 0xdffffc0000000008: 0000 [#1] SMP KAI [ 45.747287][ T9787] KASAN: null-ptr-deref in range [0x0000000000000040-0x0000000000000047] [ 45.748716][ T9787] CPU: 2 UID: 0 PID: 9787 Comm: repro Not tainted 6.16.0-rc3 #10 PREEMPT(full) [ 45.750250][ T9787] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 45.751983][ T9787] RIP: 0010:hfs_find_init+0x86/0x230 [ 45.752834][ T9787] Code: c1 ea 03 80 3c 02 00 0f 85 9a 01 00 00 4c 8d 6b 40 48 c7 45 18 00 00 00 00 48 b8 00 00 00 00 00 fc [ 45.755574][ T9787] RSP: 0018:ffffc90015157668 EFLAGS: 00010202 [ 45.756432][ T9787] RAX: dffffc0000000000 RBX: 0000000000000000 RCX: ffffffff819a4d09 [ 45.757457][ T9787] RDX: 0000000000000008 RSI: ffffffff819acd3a RDI: ffffc900151576e8 [ 45.758282][ T9787] RBP: ffffc900151576d0 R08: 0000000000000005 R09: 0000000000000000 [ 45.758943][ T9787] R10: 0000000080000000 R11: 0000000000000001 R12: 0000000000000004 [ 45.759619][ T9787] R13: 0000000000000040 R14: ffff88802c50814a R15: 0000000000000000 [ 45.760293][ T9787] FS: 00007ffb72734540(0000) GS:ffff8880cec64000(0000) knlGS:0000000000000000 [ 45.761050][ T9787] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 45.761606][ T9787] CR2: 00007f9bd8225000 CR3: 000000010979a000 CR4: 00000000000006f0 [ 45.762286][ T9787] Call Trace: [ 45.762570][ T9787] <TASK> [ 45.762824][ T9787] hfs_ext_read_extent+0x190/0x9d0 [ 45.763269][ T9787] ? submit_bio_noacct_nocheck+0x2dd/0xce0 [ 45.763766][ T9787] ? __pfx_hfs_ext_read_extent+0x10/0x10 [ 45.764250][ T9787] hfs_get_block+0x55f/0x830 [ 45.764646][ T9787] block_read_full_folio+0x36d/0x850 [ 45.765105][ T9787] ? __pfx_hfs_get_block+0x10/0x10 [ 45.765541][ T9787] ? const_folio_flags+0x5b/0x100 [ 45.765972][ T9787] ? __pfx_hfs_read_folio+0x10/0x10 [ 45.766415][ T9787] filemap_read_folio+0xbe/0x290 [ 45.766840][ T9787] ? __pfx_filemap_read_folio+0x10/0x10 [ 45.767325][ T9787] ? __filemap_get_folio+0x32b/0xbf0 [ 45.767780][ T9787] do_read_cache_folio+0x263/0x5c0 [ 45.768223][ T9787] ? __pfx_hfs_read_folio+0x10/0x10 [ 45.768666][ T9787] read_cache_page+0x5b/0x160 [ 45.769070][ T9787] hfs_btree_open+0x491/0x1740 [ 45.769481][ T9787] hfs_mdb_get+0x15e2/0x1fb0 [ 45.769877][ T9787] ? __pfx_hfs_mdb_get+0x10/0x10 [ 45.770316][ T9787] ? find_held_lock+0x2b/0x80 [ 45.770731][ T9787] ? lockdep_init_map_type+0x5c/0x280 [ 45.771200][ T9787] ? lockdep_init_map_type+0x5c/0x280 [ 45.771674][ T9787] hfs_fill_super+0x38e/0x720 [ 45.772092][ T9787] ? __pfx_hfs_fill_super+0x10/0x10 [ 45.772549][ T9787] ? snprintf+0xbe/0x100 [ 45.772931][ T9787] ? __pfx_snprintf+0x10/0x10 [ 45.773350][ T9787] ? do_raw_spin_lock+0x129/0x2b0 [ 45.773796][ T9787] ? find_held_lock+0x2b/0x80 [ 45.774215][ T9787] ? set_blocksize+0x40a/0x510 [ 45.774636][ T9787] ? sb_set_blocksize+0x176/0x1d0 [ 45.775087][ T9787] ? setup_bdev_super+0x369/0x730 [ 45.775533][ T9787] get_tree_bdev_flags+0x384/0x620 [ 45.775985][ T9787] ? __pfx_hfs_fill_super+0x10/0x10 [ 45.776453][ T9787] ? __pfx_get_tree_bdev_flags+0x10/0x10 [ 45.776950][ T9787] ? bpf_lsm_capable+0x9/0x10 [ 45.777365][ T9787] ? security_capable+0x80/0x260 [ 45.777803][ T9787] vfs_get_tree+0x8e/0x340 [ 45.778203][ T9787] path_mount+0x13de/0x2010 [ 45.778604][ T9787] ? kmem_cache_free+0x2b0/0x4c0 [ 45.779052][ T9787] ? __pfx_path_mount+0x10/0x10 [ 45.779480][ T9787] ? getname_flags.part.0+0x1c5/0x550 [ 45.779954][ T9787] ? putname+0x154/0x1a0 [ 45.780335][ T9787] __x64_sys_mount+0x27b/0x300 [ 45.780758][ T9787] ? __pfx___x64_sys_mount+0x10/0x10 [ 45.781232][ T9787] do_syscall_64+0xc9/0x480 [ 45.781631][ T9787] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 45.782149][ T9787] RIP: 0033:0x7ffb7265b6ca [ 45.782539][ T9787] Code: 48 8b 0d c9 17 0d 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 [ 45.784212][ T9787] RSP: 002b:00007ffc0c10cfb8 EFLAGS: 00000206 ORIG_RAX: 00000000000000a5 [ 45.784935][ T9787] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007ffb7265b6ca [ 45.785626][ T9787] RDX: 0000200000000240 RSI: 0000200000000280 RDI: 00007ffc0c10d100 [ 45.786316][ T9787] RBP: 00007ffc0c10d190 R08: 00007ffc0c10d000 R09: 0000000000000000 [ 45.787011][ T9787] R10: 0000000000000048 R11: 0000000000000206 R12: 0000560246733250 [ 45.787697][ T9787] R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 [ 45.788393][ T9787] </TASK> [ 45.788665][ T9787] Modules linked in: [ 45.789058][ T9787] ---[ end trace 0000000000000000 ]--- [ 45.789554][ T9787] RIP: 0010:hfs_find_init+0x86/0x230 [ 45.790028][ T9787] Code: c1 ea 03 80 3c 02 00 0f 85 9a 01 00 00 4c 8d 6b 40 48 c7 45 18 00 00 00 00 48 b8 00 00 00 00 00 fc [ 45.792364][ T9787] RSP: 0018:ffffc90015157668 EFLAGS: 00010202 [ 45.793155][ T9787] RAX: dffffc0000000000 RBX: 0000000000000000 RCX: ffffffff819a4d09 [ 45.794123][ T9787] RDX: 0000000000000008 RSI: ffffffff819acd3a RDI: ffffc900151576e8 [ 45.795105][ T9787] RBP: ffffc900151576d0 R08: 0000000000000005 R09: 0000000000000000 [ 45.796135][ T9787] R10: 0000000080000000 R11: 0000000000000001 R12: 0000000000000004 [ 45.797114][ T9787] R13: 0000000000000040 R14: ffff88802c50814a R15: 0000000000000000 [ 45.798024][ T9787] FS: 00007ffb72734540(0000) GS:ffff8880cec64000(0000) knlGS:0000000000000000 [ 45.799019][ T9787] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 45.799822][ T9787] CR2: 00007f9bd8225000 CR3: 000000010979a000 CR4: 00000000000006f0 [ 45.800747][ T9787] Kernel panic - not syncing: Fatal exception The hfs_fill_super() calls hfs_mdb_get() method that tries to construct Extents Tree and Catalog Tree: HFS_SB(sb)->ext_tree = hfs_btree_open(sb, HFS_EXT_CNID, hfs_ext_keycmp); if (!HFS_SB(sb)->ext_tree) { pr_err("unable to open extent tree\n"); goto out; } HFS_SB(sb)->cat_tree = hfs_btree_open(sb, HFS_CAT_CNID, hfs_cat_keycmp); if (!HFS_SB(sb)->cat_tree) { pr_err("unable to open catalog tree\n"); goto out; } However, hfs_btree_open() calls read_mapping_page() that calls hfs_get_block(). And this method calls hfs_ext_read_extent(): static int hfs_ext_read_extent(struct inode *inode, u16 block) { struct hfs_find_data fd; int res; if (block >= HFS_I(inode)->cached_start && block < HFS_I(inode)->cached_start + HFS_I(inode)->cached_blocks) return 0; res = hfs_find_init(HFS_SB(inode->i_sb)->ext_tree, &fd); if (!res) { res = __hfs_ext_cache_extent(&fd, inode, block); hfs_find_exit(&fd); } return res; } The problem here that hfs_find_init() is trying to use HFS_SB(inode->i_sb)->ext_tree that is not initialized yet. It will be initailized when hfs_btree_open() finishes the execution. The patch adds checking of tree pointer in hfs_find_init() and it reworks the logic of hfs_btree_open() by reading the b-tree's header directly from the volume. The read_mapping_page() is exchanged on filemap_grab_folio() that grab the folio from mapping. Then, sb_bread() extracts the b-tree's header content and copy it into the folio. Reported-by: Wenzhi Wang <wenzhi.wang@uwaterloo.ca> 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/20250710213657.108285-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2025-07-25hfs: fix slab-out-of-bounds in hfs_bnode_read()Viacheslav Dubeyko
This patch introduces is_bnode_offset_valid() method that checks the requested offset value. Also, it introduces check_and_correct_requested_length() method that checks and correct the requested length (if it is necessary). These methods are used in hfs_bnode_read(), hfs_bnode_write(), hfs_bnode_clear(), hfs_bnode_copy(), and hfs_bnode_move() with the goal to prevent the access out of allocated memory and triggering the crash. Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20250703214912.244138-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2025-07-16fs: change write_begin/write_end interface to take struct kiocb *Taotao Chen
Change the address_space_operations callbacks write_begin() and write_end() to take struct kiocb * as the first argument instead of struct file *. Update all affected function prototypes, implementations, call sites, and related documentation across VFS, filesystems, and block layer. Part of a series refactoring address_space_operations write_begin and write_end callbacks to use struct kiocb for passing write context and flags. Signed-off-by: Taotao Chen <chentaotao@didiglobal.com> Link: https://lore.kernel.org/20250716093559.217344-4-chentaotao@didiglobal.com Signed-off-by: Christian Brauner <brauner@kernel.org>
2025-07-06hfs: make splice write available againYangtao Li
Since 5.10, splice() or sendfile() return EINVAL. This was caused by commit 36e2c7421f02 ("fs: don't allow splice read/write without explicit ops"). This patch initializes the splice_write field in file_operations, like most file systems do, to restore the functionality. Fixes: 36e2c7421f02 ("fs: don't allow splice read/write without explicit ops") Signed-off-by: Yangtao Li <frank.li@vivo.com> Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com> Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20250529140033.2296791-2-frank.li@vivo.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2025-07-06hfs: fix not erasing deleted b-tree node issueViacheslav Dubeyko
The generic/001 test of xfstests suite fails and corrupts the HFS volume: sudo ./check generic/001 FSTYP -- hfs PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.15.0-rc2+ #3 SMP PREEMPT_DYNAMIC Fri Apr 25 17:13:00 PDT 2> MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/001 32s ... _check_generic_filesystem: filesystem on /dev/loop50 is inconsistent (see /home/slavad/XFSTESTS-2/xfstests-dev/results//generic/001.full for details) Ran: generic/001 Failures: generic/001 Failed 1 of 1 tests fsck.hfs -d -n ./test-image.bin ** ./test-image.bin (NO WRITE) Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. Executing fsck_hfs (version 540.1-Linux). ** Checking HFS volume. The volume name is untitled ** Checking extents overflow file. ** Checking catalog file. Unused node is not erased (node = 2) Unused node is not erased (node = 4) <skipped> Unused node is not erased (node = 253) Unused node is not erased (node = 254) Unused node is not erased (node = 255) Unused node is not erased (node = 256) ** Checking catalog hierarchy. ** Checking volume bitmap. ** Checking volume information. Verify Status: VIStat = 0x0000, ABTStat = 0x0000 EBTStat = 0x0000 CBTStat = 0x0004 CatStat = 0x00000000 ** The volume untitled was found corrupt and needs to be repaired. volume type is HFS primary MDB is at block 2 0x02 alternate MDB is at block 20971518 0x13ffffe primary VHB is at block 0 0x00 alternate VHB is at block 0 0x00 sector size = 512 0x200 VolumeObject flags = 0x19 total sectors for volume = 20971520 0x1400000 total sectors for embedded volume = 0 0x00 This patch adds logic of clearing the deleted b-tree node. sudo ./check generic/001 FSTYP -- hfs PLATFORM -- Linux/x86_64 hfsplus-testing-0001 6.15.0-rc2+ #3 SMP PREEMPT_DYNAMIC Fri Apr 25 17:13:00 PDT 2025 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/001 9s ... 32s Ran: generic/001 Passed all 1 tests fsck.hfs -d -n ./test-image.bin ** ./test-image.bin (NO WRITE) Using cacheBlockSize=32K cacheTotalBlock=1024 cacheSize=32768K. Executing fsck_hfs (version 540.1-Linux). ** Checking HFS volume. The volume name is untitled ** Checking extents overflow file. ** Checking catalog file. ** Checking catalog hierarchy. ** Checking volume bitmap. ** Checking volume information. ** The volume untitled appears to be OK. Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Link: https://lore.kernel.org/r/20250430001211.1912533-1-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
2025-06-17fs: convert simple use of generic_file_*_mmap() to .mmap_prepare()Lorenzo Stoakes
Since commit c84bf6dd2b83 ("mm: introduce new .mmap_prepare() file callback"), the f_op->mmap() hook has been deprecated in favour of f_op->mmap_prepare(). We have provided generic .mmap_prepare() equivalents, so update all file systems that specify these directly in their file_operations structures. This updates 9p, adfs, affs, bfs, fat, hfs, hfsplus, hostfs, hpfs, jffs2, jfs, minix, omfs, ramfs and ufs file systems directly. It updates generic_ro_fops which impacts qnx4, cramfs, befs, squashfs, frebxfs, qnx6, efs, romfs, erofs and isofs file systems. There are remaining file systems which use generic hooks in a less direct way which we address in a subsequent commit. Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> Link: https://lore.kernel.org/c7dc90e44a9e75e750939ea369290d6e441a18e6.1750099179.git.lorenzo.stoakes@oracle.com Reviewed-by: Jan Kara <jack@suse.cz> Reviewed-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com> Signed-off-by: Christian Brauner <brauner@kernel.org>
2025-06-10new helper: set_default_d_op()Al Viro
... to be used instead of manually assigning to ->s_d_op. All in-tree filesystem converted (and field itself is renamed, so any out-of-tree ones in need of conversion will be caught by compiler). Reviewed-by: Christian Brauner <brauner@kernel.org> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2025-04-07hfs/hfsplus: fix slab-out-of-bounds in hfs_bnode_read_keyVasiliy Kovalev
Syzbot reported an issue in hfs subsystem: BUG: KASAN: slab-out-of-bounds in memcpy_from_page include/linux/highmem.h:423 [inline] BUG: KASAN: slab-out-of-bounds in hfs_bnode_read fs/hfs/bnode.c:35 [inline] BUG: KASAN: slab-out-of-bounds in hfs_bnode_read_key+0x314/0x450 fs/hfs/bnode.c:70 Write of size 94 at addr ffff8880123cd100 by task syz-executor237/5102 Call Trace: <TASK> __dump_stack lib/dump_stack.c:94 [inline] dump_stack_lvl+0x241/0x360 lib/dump_stack.c:120 print_address_description mm/kasan/report.c:377 [inline] print_report+0x169/0x550 mm/kasan/report.c:488 kasan_report+0x143/0x180 mm/kasan/report.c:601 kasan_check_range+0x282/0x290 mm/kasan/generic.c:189 __asan_memcpy+0x40/0x70 mm/kasan/shadow.c:106 memcpy_from_page include/linux/highmem.h:423 [inline] hfs_bnode_read fs/hfs/bnode.c:35 [inline] hfs_bnode_read_key+0x314/0x450 fs/hfs/bnode.c:70 hfs_brec_insert+0x7f3/0xbd0 fs/hfs/brec.c:159 hfs_cat_create+0x41d/0xa50 fs/hfs/catalog.c:118 hfs_mkdir+0x6c/0xe0 fs/hfs/dir.c:232 vfs_mkdir+0x2f9/0x4f0 fs/namei.c:4257 do_mkdirat+0x264/0x3a0 fs/namei.c:4280 __do_sys_mkdir fs/namei.c:4300 [inline] __se_sys_mkdir fs/namei.c:4298 [inline] __x64_sys_mkdir+0x6c/0x80 fs/namei.c:4298 do_syscall_x64 arch/x86/entry/common.c:52 [inline] do_syscall_64+0xf3/0x230 arch/x86/entry/common.c:83 entry_SYSCALL_64_after_hwframe+0x77/0x7f RIP: 0033:0x7fbdd6057a99 Add a check for key length in hfs_bnode_read_key to prevent out-of-bounds memory access. If the key length is invalid, the key buffer is cleared, improving stability and reliability. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: syzbot+5f3a973ed3dfb85a6683@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=5f3a973ed3dfb85a6683 Cc: stable@vger.kernel.org Signed-off-by: Vasiliy Kovalev <kovalev@altlinux.org> Link: https://lore.kernel.org/20241019191303.24048-1-kovalev@altlinux.org Reviewed-by: Cengiz Can <cengiz.can@canonical.com> Signed-off-by: Christian Brauner <brauner@kernel.org>
2025-02-27Change inode_operations.mkdir to return struct dentry *NeilBrown
Some filesystems, such as NFS, cifs, ceph, and fuse, do not have complete control of sequencing on the actual filesystem (e.g. on a different server) and may find that the inode created for a mkdir request already exists in the icache and dcache by the time the mkdir request returns. For example, if the filesystem is mounted twice the directory could be visible on the other mount before it is on the original mount, and a pair of name_to_handle_at(), open_by_handle_at() calls could instantiate the directory inode with an IS_ROOT() dentry before the first mkdir returns. This means that the dentry passed to ->mkdir() may not be the one that is associated with the inode after the ->mkdir() completes. Some callers need to interact with the inode after the ->mkdir completes and they currently need to perform a lookup in the (rare) case that the dentry is no longer hashed. This lookup-after-mkdir requires that the directory remains locked to avoid races. Planned future patches to lock the dentry rather than the directory will mean that this lookup cannot be performed atomically with the mkdir. To remove this barrier, this patch changes ->mkdir to return the resulting dentry if it is different from the one passed in. Possible returns are: NULL - the directory was created and no other dentry was used ERR_PTR() - an error occurred non-NULL - this other dentry was spliced in This patch only changes file-systems to return "ERR_PTR(err)" instead of "err" or equivalent transformations. Subsequent patches will make further changes to some file-systems to return a correct dentry. Not all filesystems reliably result in a positive hashed dentry: - NFS, cifs, hostfs will sometimes need to perform a lookup of the name to get inode information. Races could result in this returning something different. Note that this lookup is non-atomic which is what we are trying to avoid. Placing the lookup in filesystem code means it only happens when the filesystem has no other option. - kernfs and tracefs leave the dentry negative and the ->revalidate operation ensures that lookup will be called to correctly populate the dentry. This could be fixed but I don't think it is important to any of the users of vfs_mkdir() which look at the dentry. The recommendation to use d_drop();d_splice_alias() is ugly but fits with current practice. A planned future patch will change this. Reviewed-by: Jeff Layton <jlayton@kernel.org> Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: NeilBrown <neilb@suse.de> Link: https://lore.kernel.org/r/20250227013949.536172-2-neilb@suse.de Signed-off-by: Christian Brauner <brauner@kernel.org>
2025-01-30Merge tag 'pull-revalidate' of ↵Linus Torvalds
git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs Pull vfs d_revalidate updates from Al Viro: "Provide stable parent and name to ->d_revalidate() instances Most of the filesystem methods where we care about dentry name and parent have their stability guaranteed by the callers; ->d_revalidate() is the major exception. It's easy enough for callers to supply stable values for expected name and expected parent of the dentry being validated. That kills quite a bit of boilerplate in ->d_revalidate() instances, along with a bunch of races where they used to access ->d_name without sufficient precautions" * tag 'pull-revalidate' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: 9p: fix ->rename_sem exclusion orangefs_d_revalidate(): use stable parent inode and name passed by caller ocfs2_dentry_revalidate(): use stable parent inode and name passed by caller nfs: fix ->d_revalidate() UAF on ->d_name accesses nfs{,4}_lookup_validate(): use stable parent inode passed by caller gfs2_drevalidate(): use stable parent inode and name passed by caller fuse_dentry_revalidate(): use stable parent inode and name passed by caller vfat_revalidate{,_ci}(): use stable parent inode passed by caller exfat_d_revalidate(): use stable parent inode passed by caller fscrypt_d_revalidate(): use stable parent inode passed by caller ceph_d_revalidate(): propagate stable name down into request encoding ceph_d_revalidate(): use stable parent inode passed by caller afs_d_revalidate(): use stable name and parent inode passed by caller Pass parent directory inode and expected name to ->d_revalidate() generic_ci_d_compare(): use shortname_storage ext4 fast_commit: make use of name_snapshot primitives dissolve external_name.u into separate members make take_dentry_name_snapshot() lockless dcache: back inline names with a struct-wrapped array of unsigned long make sure that DNAME_INLINE_LEN is a multiple of word size
2025-01-27Pass parent directory inode and expected name to ->d_revalidate()Al Viro
->d_revalidate() often needs to access dentry parent and name; that has to be done carefully, since the locking environment varies from caller to caller. We are not guaranteed that dentry in question will not be moved right under us - not unless the filesystem is such that nothing on it ever gets renamed. It can be dealt with, but that results in boilerplate code that isn't even needed - the callers normally have just found the dentry via dcache lookup and want to verify that it's in the right place; they already have the values of ->d_parent and ->d_name stable. There is a couple of exceptions (overlayfs and, to less extent, ecryptfs), but for the majority of calls that song and dance is not needed at all. It's easier to make ecryptfs and overlayfs find and pass those values if there's a ->d_revalidate() instance to be called, rather than doing that in the instances. This commit only changes the calling conventions; making use of supplied values is left to followups. NOTE: some instances need more than just the parent - things like CIFS may need to build an entire path from filesystem root, so they need more precautions than the usual boilerplate. This series doesn't do anything to that need - these filesystems have to keep their locking mechanisms (rename_lock loops, use of dentry_path_raw(), private rwsem a-la v9fs). One thing to keep in mind when using name is that name->name will normally point into the pathname being resolved; the filename in question occupies name->len bytes starting at name->name, and there is NUL somewhere after it, but it the next byte might very well be '/' rather than '\0'. Do not ignore name->len. Reviewed-by: Jeff Layton <jlayton@kernel.org> Reviewed-by: Gabriel Krisman Bertazi <gabriel@krisman.be> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>