| Age | Commit message (Collapse) | Author | Files | Lines |
|
Add a iomap_bio_submit_read_endio helper factored out of
iomap_bio_submit_read to that all ->submit_read implementations for
iomap_read_ops that use iomap_bio_read_folio_range can shared the
logic.
Right now that logic is mostly trivial, but already has a bug for XFS
because the XFS version is too trivial: file system integrity validation
needs a workqueue context and thus can't happen from the default iomap
bi_end_io I/O handler. Unfortunately the iomap refactoring just before
fs integrity landed moved code around here and the call go misplaced,
meaning it never got called. The PI information still is verified by
the block layer, but the offloading is less efficient (and the future
userspace interface can't get at it).
Fixes: 0b10a370529c ("iomap: support T10 protection information")
Cc: stable@vger.kernel.org # v7.1
Signed-off-by: Christoph Hellwig <hch@lst.de>
Link: https://patch.msgid.link/20260629121750.3392300-2-hch@lst.de
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
https://github.com/Paragon-Software-Group/linux-ntfs3
Pull ntfs3 updates from Konstantin Komarov:
"Added:
- depth limit to indx_find_buffer() to prevent stack overflow
- validate split-point offset in indx_insert_into_buffer()
- bounds check to run_get_highest_vcn()
- fileattr_get() and fileattr_set() support
- zero stale pagecache beyond valid data length
- handle delayed allocation overlap in run lookup
- validate lcns_follow in log_replay() conversion
- cap RESTART_TABLE free-chain walker at rt->used
- resize log->one_page_buf when adopting on-disk page size
- reject direct userspace writes to reserved $LX* xattrs
Fixed:
- out-of-bounds read in decompress_lznt()
- avoid -Wmaybe-uninitialized warnings
- hold ni_lock across readdir metadata walk
- preserve non-DOS attribute bits in system.dos_attrib
- validate index entry key bounds
- syncing wrong inode on DIRSYNC cross-directory rename
- validate Dirty Page Table capacity in log_replay() copy_lcns
- wrong LCN in run_remove_range() when splitting a run
- allocate iomap inline_data using alloc_page
- mount failure on 64K page-size kernels
- out-of-bounds read in ntfs_dir_emit() and hdr_find_e()
- bound attr_off in UpdateResidentValue against data_off
- bound DeleteIndexEntryAllocation memmove length
- bound copy_lcns dp->page_lcns[] index in analysis pass
- bound NTFS_DE view.data_off in UpdateRecordData{Root,Allocation}
- prevent potential lcn remains uninitialized
Changed:
- bound to_move in indx_insert_into_root() before hdr_insert_head()
- call _ntfs_bad_inode() when failing to rename
- fold resident writeback into writepages loop
- force waiting for direct I/O completion
- fold file size handling into ntfs_set_size()
- reject SEEK_DATA and SEEK_HOLE past EOF early
- format code, add descriptive comments and remove non-useful"
* tag 'ntfs3_for_7.2' of https://github.com/Paragon-Software-Group/linux-ntfs3: (34 commits)
ntfs3: reject direct userspace writes to reserved $LX* xattrs
fs/ntfs3: resize log->one_page_buf when adopting on-disk page size
fs/ntfs3: prevent potential lcn remains uninitialized
ntfs3: cap RESTART_TABLE free-chain walker at rt->used
fs/ntfs3: bound NTFS_DE view.data_off in UpdateRecordData{Root,Allocation}
fs/ntfs3: validate lcns_follow in log_replay conversion
fs/ntfs3: bound copy_lcns dp->page_lcns[] index in analysis pass
fs/ntfs3: bound DeleteIndexEntryAllocation memmove length
fs/ntfs3: bound attr_off in UpdateResidentValue against data_off
ntfs3: fix out-of-bounds read in ntfs_dir_emit() and hdr_find_e()
fs/ntfs3: fix mount failure on 64K page-size kernels
ntfs3: avoid another -Wmaybe-uninitialized warning
ntfs3: Allocate iomap inline_data using alloc_page
fs/ntfs3: format code, deal with comments
fs/ntfs3: reject SEEK_DATA and SEEK_HOLE past EOF early
fs/ntfs3: fold file size handling into ntfs_set_size()
fs/ntfs3: force waiting for direct I/O completion
fs/ntfs3: fold resident writeback into writepages loop
fs/ntfs3: handle delayed allocation overlap in run lookup
fs/ntfs3: zero stale pagecache beyond valid data length
...
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull misc vfs updates from Christian Brauner:
"Features:
- Reduce pipe->mutex contention by pre-allocating pages outside the
lock in anon_pipe_write().
anon_pipe_write() called alloc_page() once per page while holding
pipe->mutex. The allocation can sleep doing direct reclaim and runs
memcg charging, which extends the critical section and stalls any
concurrent reader on the same mutex. Now up to 8 pages are
pre-allocated before the mutex is taken, leftovers are recycled
into the per-pipe tmp_page[] cache before unlock, and any remainder
is released after unlock, keeping the allocator out of the critical
section on both sides. On a writers x readers sweep with 64KB
writes against a 1 MB pipe throughput improves 6-28% and average
write latency drops 5-22%; under memory pressure - when the cost of
holding the mutex across reclaim is highest - throughput improves
21-48% and latency drops 17-33%. The microbenchmark is added to
selftests.
- uaccess/sockptr: fix the ignored_trailing logic in
copy_struct_to_user() to behave as documented and the usize check
in copy_struct_from_sockptr() for user pointers, and add
copy_struct_{from,to}_bounce_buffer() and copy_struct_to_sockptr()
helpers for upcoming users (IPPROTO_SMBDIRECT, IPPROTO_QUIC).
- bpf: add a sleepable bpf_real_inode() kfunc that resolves the real
inode backing a dentry via d_real_inode(). On overlayfs the inode
attached to the dentry doesn't carry the underlying device
information; this is used by the filesystem restriction BPF program
that was merged into systemd.
- docs: add guidelines for submitting new filesystems, motivated by
the maintenance burden abandoned and untestable filesystems impose
on VFS developers, blocking infrastructure work like folio
conversions and iomap migration.
Fixes:
- libfs: set SB_I_NOEXEC and SB_I_NODEV by default in init_pseudo()
and drop the now-redundant assignments in callers. This began as a
one-line dma-buf fix for a path_noexec() warning; a pseudo
filesystem has no reason not to set SB_I_NOEXEC. All init_pseudo()
callers were audited: the only visible effect is on dma-buf where
SB_I_NOEXEC silences the warning.
- Handle set_blocksize() failures in legacy filesystems (bfs, hpfs,
qnx4, jfs, befs, affs, isofs, minix, ntfs3, omfs). Mounting a
device with a sector size > PAGE_SIZE crashed roughly half of them;
the rest had the same missing error handling pattern. Plus a
follow-up releasing the superblock buffer_head when setting the
minix v3 block size fails.
- mount: honour SB_NOUSER in the new mount API.
- fs/fcntl: fix a SOFTIRQ-unsafe lock order in fasync signaling by
switching the process-group paths of send_sigio() and send_sigurg()
from read_lock(&tasklist_lock) to RCU, matching the single-PID
path.
- vfs: add an FS_USERNS_DELEGATABLE flag and set it for NFS, fixing
delegated NFS mounts (fsopen() in a container with the mount
performed by a privileged daemon) that broke when non-init
s_user_ns was tied to FS_USERNS_MOUNT.
- selftests/namespaces: fix a hang in nsid_test where an unreaped
grandchild kept the TAP pipe write-end open, a waitpid(-1) race in
listns_efault_test, and a false FAIL on kernels without listns()
where the tests should SKIP.
- filelock: fix the break_lease() stub signature for
CONFIG_FILE_LOCKING=n.
- init/initramfs_test: wait for the async initramfs unpacking before
running; the test and do_populate_rootfs() share the parser state.
- fs/coredump: reduce redundant log noise in
validate_coredump_safety().
- iomap: pass the correct length to fserror_report_io() in
__iomap_write_begin().
- backing-file: fix the backing_file_open() kerneldoc.
Cleanups:
- initramfs: refactor the cpio hex header parsing to use hex2bin()
instead of the hand-rolled simple_strntoul() which is reverted, and
extend the initramfs KUnit tests to cover header fields with 0x
prefixes.
- Replace __get_free_pages() and friends with kmalloc()/kzalloc()
across quota, proc, ocfs2/dlm, nilfs2, nfs, nfsd, libfs, jfs, jbd2,
isofs, fuse, select, namespace, configfs, binfmt_misc, bfs, and the
do_mounts init code - part of the larger work of replacing page
allocator calls with kmalloc().
- Use clear_and_wake_up_bit() in unlock_buffer() and
journal_end_buffer_io_sync() instead of open-coding the sequence.
- Drop unused VFS exports: unexport drop_super_exclusive(), remove
start_removing_user_path_at(), and fold __start_removing_path()
into start_removing_path().
- fs/read_write: narrow the __kernel_write() export with
EXPORT_SYMBOL_FOR_MODULES().
- vfs: uapi: retire octal and hex constants in favor of (1 << n) for
the O_ flags. Finding a free bit for a new flag across the
architectures was needlessly hard with the mixed bases.
- dcache: add extra sanity checks of dead dentries in dentry_free()
via a new DENTRY_WARN_ONCE() that also prints d_flags.
- iov_iter: use kmemdup_array() in dup_iter() to harden the
allocation against multiplication overflow.
- fs/pipe: write to ->poll_usage only once.
- vfs: remove an always-taken if-branch in find_next_fd().
- dcache: use kmalloc_flex() for struct external_name in __d_alloc().
- namei: use QSTR() instead of QSTR_INIT() in path_pts().
- sync_file_range: delete dead S_ISLNK code.
- Comment fixes: retire a stale comment in fget_task_next() and fix
assorted spelling mistakes"
* tag 'vfs-7.2-rc1.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (73 commits)
backing-file: fix backing_file_open() kerneldoc parameter
iomap: pass the correct len to fserror_report_io in __iomap_write_begin
vfs: add FS_USERNS_DELEGATABLE flag and set it for NFS
filelock: fix break_lease() stub signature for CONFIG_FILE_LOCKING=n
vfs: uapi: retire octal and hex numbers in favor of (1 << n) for O_ flags
bpf: add bpf_real_inode() kfunc
fs/read_write: Do not export __kernel_write() to the entire world
libfs: drop redundant SB_I_NOEXEC/SB_I_NODEV in init_pseudo() callers
libfs: set SB_I_NOEXEC and SB_I_NODEV by default in init_pseudo()
mount: honour SB_NOUSER in the new mount API
fs/fcntl: fix SOFTIRQ-unsafe lock order in fasync signaling
selftests/pipe: add pipe_bench microbenchmark
fs/pipe: pre-allocate pages outside pipe->mutex in anon_pipe_write
fs: retire stale comment in fget_task_next()
fs: fix spelling mistakes in comment
bfs: replace get_zeroed_page() with kzalloc()
binfmt_misc: replace __get_free_page() with kmalloc()
configfs: replace __get_free_pages() with kzalloc()
fs/namespace: use __getname() to allocate mntpath buffer
fs/select: replace __get_free_page() with kmalloc()
...
|
|
NTFS3 uses $LXUID, $LXGID, $LXMOD and $LXDEV as internal WSL
permission metadata and reloads them into i_uid, i_gid and i_mode
from ntfs_get_wsl_perm().
Because the empty-prefix xattr handler also lets file owners call
setxattr() on these names directly, an unprivileged writer on a
writable ntfs3 mount can plant root ownership and S_ISUID on their own
file and gain euid 0 after inode reload.
Reject direct userspace writes to the reserved $LX* names. Internal
ntfs3 metadata updates are unchanged because ntfs_save_wsl_perm()
writes them via ntfs_set_ea() directly.
Signed-off-by: Zhen Yan <sdjasjbuaa@gmail.com>
[almaz.alexandrovich@paragon-software.com: added an additional check for non privileged users]
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
log_replay() allocates log->one_page_buf using the page size that was
chosen from the host PAGE_SIZE:
log->one_page_buf = kmalloc(log->page_size, GFP_NOFS);
Later, when a restart area is found, the log page size recorded on disk
is adopted:
t32 = le32_to_cpu(log->rst_info.r_page->sys_page_size);
if (log->page_size != t32) {
log->l_size = log->orig_file_size;
log->page_size = norm_file_page(t32, &log->l_size,
t32 == DefaultLogPageSize);
}
If the on-disk page size is larger than the size used for the initial
allocation, log->page_size grows but one_page_buf is left at its
original, smaller size. A subsequent unaligned read_log_page() then
reads log->page_size bytes into the undersized scratch buffer:
page_buf = page_off ? log->one_page_buf : *buffer;
err = ntfs_read_run_nb_ra(ni->mi.sbi, &ni->file.run, page_vbo, page_buf,
log->page_size, NULL, &log->read_ahead);
overflowing the allocation. This is reachable when mounting a dirty
NTFS volume whose log was formatted with a page size larger than the
buffer initially allocated on the mounting host (for example a 64K-log
volume mounted on a host that allocated a 4K scratch buffer).
Grow one_page_buf when the adopted on-disk page size exceeds the size
used for the initial allocation. On krealloc() failure the original
buffer is left intact and freed by the existing error path.
Fixes: b46acd6a6a627 ("fs/ntfs3: Add NTFS journal")
Reported-by: Carol L Soto <csoto@nvidia.com>
Signed-off-by: Jamie Nguyen <jamien@nvidia.com>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
The target VCN being sought was not found within runs[0], causing
run_lookup() to return false. This causes run_lookup_entry() to return
false, which in turn results in a len value of 0, and the new parameter
passed to attr_data_get_block() is NULL. Collectively, these factors
ultimately cause attr_data_get_block_locked() to exit prematurely without
initializing lcn, thereby triggering [1].
To prevent [1], the clen check within ni_seek_data_or_hole() has been
moved to occur before the lcn check.
[1]
BUG: KMSAN: uninit-value in ni_seek_data_or_hole+0x24f/0x5f0 fs/ntfs3/frecord.c:2862
ni_seek_data_or_hole+0x24f/0x5f0 fs/ntfs3/frecord.c:2862
ntfs_llseek+0x22a/0x4a0 fs/ntfs3/file.c:1530
vfs_llseek fs/read_write.c:391 [inline]
Fixes: c61326967728 ("fs/ntfs3: implement llseek SEEK_DATA/SEEK_HOLE by scanning data runs")
Reported-by: syzbot+c2cfe997245202e46f10@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=c2cfe997245202e46f10
Signed-off-by: Edward Adam Davis <eadavis@qq.com>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
A crafted NTFS3 disk image triggers an in-kernel infinite loop at
mount time, hanging the mounting thread and firing the soft-lockup
watchdog within ~22s on multi-CPU hosts (panic with
kernel.softlockup_panic=1). The bug is reachable from desktop USB
auto-mount on distributions where udisks2 routes the NTFS signature
to the in-tree ntfs3 driver (Arch family and an increasing fraction
of Fedora / openSUSE / RHEL deployments); CAP_SYS_ADMIN-class manual
mount elsewhere.
check_rstbl()'s second walker iterates the free-entry singly-linked
list headed by rt->first_free with no upper bound on iteration count:
for (off = ff; off;) {
if (off == RESTART_ENTRY_ALLOCATED)
return false;
off = le32_to_cpu(*(__le32 *)Add2Ptr(rt, off));
if (off > ts - sizeof(__le32))
return false;
}
The existing guards cover three exits: end-of-list (off == 0), the
in-use marker (off == RESTART_ENTRY_ALLOCATED), and out-of-bounds
(off > ts - sizeof(__le32)). None of the three prevents an
in-bounds cycle.
A crafted on-disk RESTART_TABLE whose free chain contains a
self-loop or A->B->A cycle whose offsets satisfy:
- in range [sizeof(struct RESTART_TABLE), ts - sizeof(__le32)]
- (off - sizeof(struct RESTART_TABLE)) % rsize == 0
passes all existing guards and spins the mount-time thread forever.
Reproduced in UML by hand-forging a 2 MB NTFS3 image whose journal
RESTART_TABLE first_free = 0x18 and whose entry at offset 0x18
stores 0x18 as its next pointer; mount of the forged image with
the in-tree ntfs3 driver never returns.
Bound the walker by rt->used. Each entry on a legitimate free
chain is unique, and the total slot count is ne = le16_to_cpu
(rt->used). A traversal that visits more than ne slots is by
construction malformed; reject it as a corrupt RESTART_TABLE.
After this patch, mount of the forged image returns with -EINVAL
and a log_replay failure message, and mkntfs-produced legitimate
images mount cleanly (verified in the same UML harness).
Fixes: b46acd6a6a62 ("fs/ntfs3: Add NTFS journal")
Cc: stable@vger.kernel.org
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
In do_action()'s UpdateRecordDataRoot (fslog.c:3489) and
UpdateRecordDataAllocation (fslog.c:3697) cases, the memmove
destination is `Add2Ptr(e, le16_to_cpu(e->view.data_off))`,
where e->view.data_off comes from an on-disk NTFS_DE inside
an INDEX_ROOT or INDEX_BUFFER. Neither case validates
view.data_off + dlen against e->size; the existing
check_if_index_root / check_if_alloc_index helpers walk the
entry chain and validate the entry's offset, but not its
internal view fields.
The neighbouring read sites (e.g., fs/ntfs3/index.c when
iterating view entries) check view.data_off + view.data_size
<= e->size. Apply the same bound at the two memmove sites.
Reproduced under UML+KASAN on mainline 8d90b09e6741 via
pr_warn-only probe instrumentation: with view.data_off forced
to 0xFFFC, the memmove writes 32 bytes past the end of the
NTFS_DE.
This is similar in shape to Pavitra Jha's 2026-05-02 patch
"fs/ntfs3: prevent oob in case UpdateRecordDataRoot"
(<20260502105008.21827-1-jhapavitra98@gmail.com>) which
proposes calling ntfs3_bad_de_range(); that helper does not
exist in mainline. This patch uses inline checks.
Fixes: b46acd6a6a62 ("fs/ntfs3: Add NTFS journal")
Cc: stable@vger.kernel.org
Reported-by: Pavitra Jha <jhapavitra98@gmail.com>
Closes: https://lore.kernel.org/ntfs3/20260502105008.21827-1-jhapavitra98@gmail.com/
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
log_replay() converts DIR_PAGE_ENTRY_32 records into DIR_PAGE_ENTRY
records when replaying version 0 restart tables.
During this conversion, the memmove() length is derived directly from
the on-disk lcns_follow field:
memmove(&dp->vcn, &dp0->vcn_low,
2 * sizeof(u64) +
le32_to_cpu(dp->lcns_follow) * sizeof(u64));
check_rstbl() validates restart table structure, but does not constrain
per-entry lcns_follow values relative to the entry size. A malformed
filesystem image can provide an oversized lcns_follow value, causing
the conversion memmove() to access memory beyond the bounds of the
allocated restart table buffer.
The same field is later used to bound iteration over page_lcns[],
so validating lcns_follow during conversion also prevents downstream
out-of-bounds access from the same malformed metadata.
Compute the maximum valid lcns_follow from the already-validated
restart table entry size and reject entries that exceed this bound.
Reuse the existing t16/t32 scratch variables already declared in
log_replay() to avoid introducing new declarations.
Fixes: b46acd6a6a62 ("fs/ntfs3: Add NTFS journal")
Cc: stable@vger.kernel.org
Signed-off-by: Pavitra Jha <jhapavitra98@gmail.com>
[almaz.alexandrovich@paragon-software.com: fixed the conflicts]
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
In log_replay()'s analysis pass, after find_dp() returns a
valid DIR_PAGE_ENTRY for the (target_attr, target_vcn) tuple,
the copy_lcns block walks lrh->lcns_follow further entries:
t16 = le16_to_cpu(lrh->lcns_follow);
for (i = 0; i < t16; i++) {
size_t j = (size_t)(le64_to_cpu(lrh->target_vcn) -
le64_to_cpu(dp->vcn));
dp->page_lcns[j + i] = lrh->page_lcns[i];
}
find_dp() only validates that target_vcn falls within
[dp->vcn, dp->vcn + dp->lcns_follow), i.e., that the FIRST
cluster is covered. The walk through the further entries is
not bounded against dp->lcns_follow. For a malformed LRH
where target_vcn = dp->vcn + dp->lcns_follow - 1 and
lrh->lcns_follow > 1, the i > 0 writes overflow the dp's
allocated page_lcns[] array.
Add the missing j + lrh->lcns_follow <= dp->lcns_follow guard.
Reproduced under UML+KASAN on mainline 8d90b09e6741 as a
slab-out-of-bounds write of size 8 from log_replay+0x68d4 on
the mount path.
This is distinct from Pavitra Jha's 2026-05-02 patch
("fs/ntfs3: validate lcns_follow in log_replay conversion",
<20260502154252.164586-1-jhapavitra98@gmail.com>) which
addresses the separate version-0 dirty-page-table conversion
path's memmove(&dp->vcn, ...) call. The two fixes are
complementary; both should land.
Fixes: b46acd6a6a62 ("fs/ntfs3: Add NTFS journal")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
[almaz.alexandrovich@paragon-software.com: clang-formatted the changes,
fixed conflicts]
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
In do_action()'s DeleteIndexEntryAllocation case, e->size comes
from an on-disk INDEX_BUFFER entry. When e->size makes
e + e->size point past hdr + hdr->used,
PtrOffset(e1, Add2Ptr(hdr, used)) returns a negative ptrdiff_t
that is silently cast to a quasi-infinite size_t when passed
to memmove(). The memmove then walks past the destination
buffer.
The sibling DeleteIndexEntryRoot case at fslog.c:3540-3543
already carries the corresponding guard:
if (PtrOffset(e1, Add2Ptr(hdr, used)) < esize ||
Add2Ptr(e, esize) > Add2Ptr(lrh, rec_len) ||
used + esize > le32_to_cpu(hdr->total)) {
goto dirty_vol;
}
Apply the same shape to the allocation-path case. Also reject
esize == 0: memmove(e, e, ...) is a no-op and leaves
hdr->used unchanged, hiding a malformed entry from the
existing check_index_header() walk.
Reproduced under UML+KASAN on mainline 8d90b09e6741 by
mounting a crafted NTFS image: the unguarded memmove takes a
length of 0xffffffffffffff00 and the kernel oopses in
memmove+0x81/0x1a0 on the do_action+0x36a2 frame.
Fixes: b46acd6a6a62 ("fs/ntfs3: Add NTFS journal")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
[almaz.alexandrovich@paragon-software.com: clang-formatted the changes]
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
In do_action()'s UpdateResidentValue case (fslog.c:3307),
lrh->attr_off and lrh->redo_len come from the on-disk LRH.
When they satisfy aoff + dlen < attr->res.data_off, the
assignment
attr->res.data_size = cpu_to_le32(aoff + dlen - data_off);
underflows to ~4 GiB (e.g. 0xFFFFFFF9 when aoff=0x10, dlen=1,
data_off=0x18). Subsequent code that reads attr->res.data_size
to walk the resident attribute payload would then read up to
4 GiB past the 1024-byte MFT record allocation.
The existing mi_enum_attr() defense in fs/ntfs3/record.c:287
catches the corrupted data_size on the next attribute walk
and fails the mount, but only on the path that walks all
attributes. A read site that picks an attribute by name and
reads its data_size without re-validating is not covered.
Validate aoff against data_off and asize at the source.
Reproduced under UML+KASAN on mainline 8d90b09e6741 via
pr_warn-only probe: with aoff=0x10 and data_off=0x18, the
post-assignment data_size is 0xfffffff9 (mount then fails
at -22 from mi_enum_attr).
Fixes: b46acd6a6a62 ("fs/ntfs3: Add NTFS journal")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
[almaz.alexandrovich@paragon-software.com: clang-formatted the changes]
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
The bounds check in ntfs_dir_emit() compares fname->name_len (a
character count) against e->size (a byte count) without accounting
for the 2-byte-per-character UTF-16LE encoding or the ATTR_FILE_NAME
header size:
if (fname->name_len + sizeof(struct NTFS_DE) > le16_to_cpu(e->size))
This computes: name_len + 16 > e_size
The correct check must account for the ATTR_FILE_NAME header (66 bytes
before the name) and the UTF-16LE character size (2 bytes each):
sizeof(NTFS_DE) + offsetof(ATTR_FILE_NAME, name) +
name_len * sizeof(short) > e_size
Which computes: 16 + 66 + name_len * 2 > e_size
The correct calculation already exists as fname_full_size() in ntfs.h
and is used in cmp_fnames(), namei.c, and fslog.c, but was not used
in the readdir path.
A crafted NTFS image with an index entry containing a small e->size
but large fname->name_len bypasses the current check, causing
ntfs_utf16_to_nls() to read past the entry boundary.
Additionally, add a key_size validation in hdr_find_e() to ensure the
declared key_size does not exceed the available entry data, preventing
comparison functions from reading past entry boundaries on the lookup
path.
Signed-off-by: Alessandro Schino <7991aleschino@gmail.com>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
On 64K page-size kernels, mounting NTFS volumes smaller than ~650 MB
fails with EINVAL. The issue is in log_replay(): the initial log page
size probe uses PAGE_SIZE (65536) instead of DefaultLogPageSize (4096)
when PAGE_SIZE exceeds DefaultLogPageSize * 2.
This makes norm_file_page() require the $LogFile to be at least
50 * 65536 = 3.2 MB, but mkfs.ntfs creates a $LogFile of only ~1.5 MB
for a typical 300 MB volume. norm_file_page() returns 0 and the mount
is rejected with EINVAL.
On 4K kernels the #if guard evaluates to true, so use_default=true is
passed and DefaultLogPageSize (4096) is used, requiring only ~200 KB.
This path works fine.
Fix this by always passing use_default=true, which forces the initial
probe to use DefaultLogPageSize regardless of the kernel's PAGE_SIZE.
This is safe because, after reading the on-disk restart area, log_replay()
already re-adjusts log->page_size to match the volume's actual
sys_page_size.
Also fix read_log_page() to pass log->page_size instead of PAGE_SIZE to
ntfs_fix_post_read(), matching the actual buffer size.
Fixes: b46acd6a6a62 ("fs/ntfs3: Add NTFS journal")
Tested-by: Matthew R. Ochs <mochs@nvidia.com>
Signed-off-by: Jamie Nguyen <jamien@nvidia.com>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
The ntfs3 specific -Wmaybe-uninitialized flag found one more false-postive,
this time with gcc-10 on s390:
fs/ntfs3/frecord.c: In function 'ni_expand_list':
fs/ntfs3/frecord.c:1370:16: error: 'ins_attr' may be used uninitialized in this function [-Werror=maybe-uninitialized]
Add an explicit NULL pointer check before using the pointer, and
initialize it to NULL.
Fixes: 48d9b57b169f ("fs/ntfs3: add a subset of W=1 warnings for stricter checks")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
This fixes a BUG reported in iomap_write_end_inline:
iomap_inline_data_valid checks that the inline_data fits within
a page. If the inline_data is allocated with kmemdup there's no
guarantee that it's page-aligned, so the check sometimes fails.
Allocate it with alloc_page to ensure it's page-aligned.
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221446
Fixes: 099ef9ab9203 ("fs/ntfs3: implement iomap-based file operations")
Signed-off-by: Mihai Brodschi <m.brodschi@gmail.com>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
format code according to .clang-format, add useful comments and remove
non-useful comments.
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
Handle non-data/hole seeks through generic_file_llseek_size() and return
-ENXIO immediately when SEEK_DATA or SEEK_HOLE is requested at or past
EOF. Handle compressed files in such cases properly as well.
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
Remove the separate ntfs_extend() and ntfs_truncate() helpers and route
file size changes through ntfs_set_size().
This consolidates ntfs3 size updates in one place and lets the write,
fallocate, and setattr paths share the same logic for updating i_size,
valid data length, and preallocated extents.
This patch fixes a few issues found during internal tests.
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
It makes ntfs3 wait for direct I/O completion before returning to the
caller, instead of allowing the write path to complete asynchronously.
The issue was discovered during internal tests.
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
Remove the separate ntfs_resident_writepage() helper and handle resident
writeback directly from ntfs_writepages(). This simplifies the resident
writeback path and keeps the folio handling local to ntfs_writepages().
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
Introduce run_lookup_entry_da() to look up data runs while taking
delayed allocation into account.
ntfs3 may have both committed extents and delayed allocation extents for
the same VCN range. The new helper checks delayed allocation first and
falls back to the real run, then corrects the returned range when a real
run overlaps with a delayed allocation run.
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
Zero cached folios beyond the valid data length when closing a writable
mapping. This keeps cached data beyond initialized file contents zeroed
and prevents stale pagecache exposure after mmap-based writes.
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
Implement fileattr_get() and fileattr_set() to fix a problem found
during the internal testing.
This allows ntfs3 to expose and modify inode flags through the generic
file attribute interface used by FS_IOC_GETFLAGS and FS_IOC_SETFLAGS.
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
It is safe to call _ntfs_bad_inode on live inodes since:
commit 519b078998ce ("fs/ntfs3: Exclude call make_bad_inode for live nodes.")
The WARN_ON was added when it wasn't safe by:
commit d99208b91933 ("fs/ntfs3: cancle set bad inode after removing name fails")
Replace the WARN_ON with a call to _ntfs_bad_inode() to prevent further
operations on the inconsistent inode.
Reported-by: syzbot+4d8e30dbafb5c1260479@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=4d8e30dbafb5c1260479
Fixes: 519b078998ce ("fs/ntfs3: Exclude call make_bad_inode for live nodes.")
Signed-off-by: Helen Koike <koike@igalia.com>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
When run_remove_range() removes a middle portion of a non-sparse run,
it splits the run into head and tail parts. The tail is inserted via
run_add_entry() but uses the original r->lcn as its starting LCN
instead of advancing it by the split offset.
For example, removing VCN range [10, 20) from a run
{vcn=0, lcn=100, len=30} should produce:
{vcn=0, lcn=100, len=10} (head)
{vcn=20, lcn=120, len=10} (tail, lcn advanced by 20)
But the current code produces:
{vcn=0, lcn=100, len=10}
{vcn=20, lcn=100, len=10} (wrong: points to same physical clusters)
This creates overlapping physical mappings in the in-memory run tree,
which can corrupt cluster allocation decisions and lead to data
corruption.
The correct pattern is already used in run_insert_range():
CLST lcn2 = r->lcn == SPARSE_LCN ? SPARSE_LCN : (r->lcn + len1);
Apply the same logic in run_remove_range().
Fixes: 10d7c95af043 ("fs/ntfs3: add delayed-allocation (delalloc) support")
Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
In the analysis pass of $LogFile journal replay, log_replay() copies
LCNs from each action log record into an existing Dirty Page Table
(DPT) entry without bounding the destination index. A crafted NTFS
image with DPT entry lcns_follow=1 and an action log record with
lcns_follow=2 produces a kernel slab out-of-bounds write at mount
time:
BUG: KASAN: slab-out-of-bounds in log_replay+0x654c/0xdb60
Write of size 8 at addr ffff8880095e1040 by task mount
Two attacker-controlled fields can drive j+i past the allocated
page_lcns[] array:
1. dp->lcns_follow (capacity) can be smaller than lrh->lcns_follow.
2. lrh->target_vcn may be smaller than dp->vcn, making the u64
subtraction wrap to a huge size_t.
Validate target VCN delta and per-record LCN count against the
DPT entry capacity, bail via the existing out: cleanup label with
-EINVAL.
This mirrors the bounds-check pattern added in commit b2bc7c44ed17
("fs/ntfs3: Fix slab-out-of-bounds read in DeleteIndexEntryRoot")
and commit 0ca0485e4b2e ("fs/ntfs3: validate rec->used in
journal-replay file record check").
Fixes: b46acd6a6a62 ("fs/ntfs3: Add NTFS journal")
Reported-by: Yunpeng Tian <shionthanatos@gmail.com>
Reported-by: Mingda Zhang <npczmd@qq.com>
Reported-by: Gongming Wang <gmwgg05@gmail.com>
Reported-by: Peiyuan Xu <paulbucket12@gmail.com>
Reported-by: Qinrun Dai <jupmouse@gmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: Yunpeng Tian <shionthanatos@gmail.com>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
In ntfs3_rename(), when IS_DIRSYNC(new_dir) is true, the code syncs
the renamed file inode instead of the target directory new_dir:
if (IS_DIRSYNC(new_dir))
ntfs_sync_inode(inode); /* should be new_dir */
DIRSYNC requires that directory metadata changes are written to disk
synchronously. Since new_dir was modified (a new directory entry was
added), it is new_dir that must be synced to satisfy the guarantee,
not the renamed file itself.
This bug has existed since the initial ntfs3 implementation and was
carried through the refactoring in commit 78ab59fee07f
("fs/ntfs3: Rework file operations").
Fix by syncing new_dir instead of inode.
Fixes: 4342306f0f0d ("fs/ntfs3: Add file operations and implementation")
Cc: stable@vger.kernel.org
Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
[BUG]
A malformed NTFS directory index entry can advertise a key_size larger
than the bytes actually present in its NTFS_DE payload. Directory lookup
then passes that malformed key to cmp_fnames(), which can read past the
end of the kmalloc'ed index buffer.
BUG: KASAN: slab-out-of-bounds in fname_full_size fs/ntfs3/ntfs.h:590 [inline]
BUG: KASAN: slab-out-of-bounds in cmp_fnames+0x1ea/0x230 fs/ntfs3/index.c:46
Read of size 1 at addr ffff88801c313018 by task syz.6.3365/9279
Call Trace:
__dump_stack lib/dump_stack.c:94 [inline]
dump_stack_lvl+0xbe/0x130 lib/dump_stack.c:120
print_address_description mm/kasan/report.c:378 [inline]
print_report+0xd1/0x650 mm/kasan/report.c:482
kasan_report+0xfb/0x140 mm/kasan/report.c:595
__asan_report_load1_noabort+0x14/0x30 mm/kasan/report_generic.c:378
fname_full_size fs/ntfs3/ntfs.h:590 [inline]
cmp_fnames+0x1ea/0x230 fs/ntfs3/index.c:46
hdr_find_e.isra.0+0x3ed/0x670 fs/ntfs3/index.c:762
indx_find+0x4b5/0x900 fs/ntfs3/index.c:1186
dir_search_u+0x2c0/0x460 fs/ntfs3/dir.c:254
ntfs_lookup+0x1cc/0x2a0 fs/ntfs3/namei.c:85
__lookup_slow+0x241/0x450 fs/namei.c:1816
lookup_slow fs/namei.c:1833 [inline]
walk_component+0x31c/0x570 fs/namei.c:2151
link_path_walk+0x592/0xd60 fs/namei.c:2519
path_lookupat+0x138/0x660 fs/namei.c:2675
filename_lookup+0x1f3/0x560 fs/namei.c:2705
filename_setxattr+0xad/0x1c0 fs/xattr.c:660
path_setxattrat+0x1d8/0x280 fs/xattr.c:713
__do_sys_lsetxattr fs/xattr.c:754 [inline]
__se_sys_lsetxattr fs/xattr.c:750 [inline]
__x64_sys_lsetxattr+0xd0/0x150 fs/xattr.c:750
...
Allocated by task 9279:
kasan_save_stack+0x39/0x70 mm/kasan/common.c:56
kasan_save_track+0x14/0x40 mm/kasan/common.c:77
kasan_save_alloc_info+0x37/0x60 mm/kasan/generic.c:573
poison_kmalloc_redzone mm/kasan/common.c:400 [inline]
__kasan_kmalloc+0xc3/0xd0 mm/kasan/common.c:417
kasan_kmalloc include/linux/kasan.h:262 [inline]
__do_kmalloc_node mm/slub.c:5650 [inline]
__kmalloc_noprof+0x2bd/0x900 mm/slub.c:5662
kmalloc_noprof include/linux/slab.h:961 [inline]
indx_read+0x41d/0xad0 fs/ntfs3/index.c:1059
indx_find+0x447/0x900 fs/ntfs3/index.c:1179
dir_search_u+0x2c0/0x460 fs/ntfs3/dir.c:254
ntfs_lookup+0x1cc/0x2a0 fs/ntfs3/namei.c:85
__lookup_slow+0x241/0x450 fs/namei.c:1816
lookup_slow fs/namei.c:1833 [inline]
walk_component+0x31c/0x570 fs/namei.c:2151
link_path_walk+0x592/0xd60 fs/namei.c:2519
path_lookupat+0x138/0x660 fs/namei.c:2675
filename_lookup+0x1f3/0x560 fs/namei.c:2705
filename_setxattr+0xad/0x1c0 fs/xattr.c:660
path_setxattrat+0x1d8/0x280 fs/xattr.c:713
__do_sys_lsetxattr fs/xattr.c:754 [inline]
__se_sys_lsetxattr fs/xattr.c:750 [inline]
__x64_sys_lsetxattr+0xd0/0x150 fs/xattr.c:750
...
[CAUSE]
The index-header validators only validated INDEX_HDR-level geometry.
They did not walk each NTFS_DE to verify entry alignment, subnode
layout, or that key_size fit inside the entry payload. They also
allowed a last sentinel entry to carry a non-zero key_size.
[FIX]
Walk every NTFS_DE in ntfs3's index-header validators and reject
entries with invalid layout, mismatched subnode state, oversized
key_size, or non-zero sentinel keys before lookup or log replay can
consume them.
Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
[BUG]
A corrupted ntfs3 image can hit a NULL function pointer call in
generic_perform_write() after toggling system.ntfs_attrib and then
overwriting system.dos_attrib on the same file.
BUG: kernel NULL pointer dereference, address: 0000000000000000
\#PF: supervisor instruction fetch in kernel mode
\#PF: error_code(0x0010) - not-present page
PGD bed5067 P4D bed5067 PUD 0
Oops: Oops: 0010 [#1] SMP KASAN NOPTI
RIP: 0010:0x0
Code: Unable to access opcode bytes at 0xffffffffffffffd6.
RSP: 0018:ffff88801025f988 EFLAGS: 00010246
Call Trace:
generic_perform_write+0x409/0x8c0 mm/filemap.c:4255
__generic_file_write_iter+0x1bb/0x200 mm/filemap.c:4372
ntfs_file_write_iter+0xcd9/0x1c20 fs/ntfs3/file.c:1253
new_sync_write fs/read_write.c:593 [inline]
vfs_write+0x63b/0xf70 fs/read_write.c:686
ksys_write+0x133/0x250 fs/read_write.c:738
__do_sys_write fs/read_write.c:749 [inline]
__se_sys_write fs/read_write.c:746 [inline]
__x64_sys_write+0x77/0xc0 fs/read_write.c:746
...
[CAUSE]
system.ntfs_attrib updates ATTR_DATA flags via ni_new_attr_flags()
and switches i_mapping->a_ops to ntfs_aops_cmpr when
FILE_ATTRIBUTE_COMPRESSED is set. system.dos_attrib then overwrites
ni->std_fa from a one-byte DOS attribute value, clearing the compression
bit without updating ATTR_DATA or the mapping operations.
Old buffered writes use is_compressed(ni) to choose
__generic_file_write_iter(). That leaves generic_perform_write() calling
a NULL write_begin callback from ntfs_aops_cmpr.
[FIX]
Treat system.dos_attrib as a low-byte DOS attribute update and preserve the
existing non-DOS attribute bits in ni->std_fa. This keeps compressed and
sparse state consistent with ATTR_DATA and the mapping operations while
keeping the existing DOS attribute semantics intact.
Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
[BUG]
KASAN reports a slab-use-after-free during getdents(2):
BUG: KASAN: slab-use-after-free in ntfs_read_mft fs/ntfs3/inode.c:79 [inline]
BUG: KASAN: slab-use-after-free in ntfs_iget5+0x59b/0x3450 fs/ntfs3/inode.c:541
Read of size 2 at addr ffff88800b7a5a4e by task syz.0.1061/2354
Call Trace:
__dump_stack lib/dump_stack.c:94 [inline]
dump_stack_lvl+0xbe/0x130 lib/dump_stack.c:120
print_address_description mm/kasan/report.c:378 [inline]
print_report+0xd1/0x650 mm/kasan/report.c:482
kasan_report+0xfb/0x140 mm/kasan/report.c:595
__asan_report_load2_noabort+0x14/0x30 mm/kasan/report_generic.c:379
ntfs_read_mft fs/ntfs3/inode.c:79 [inline]
ntfs_iget5+0x59b/0x3450 fs/ntfs3/inode.c:541
ntfs_dir_emit fs/ntfs3/dir.c:337 [inline]
ntfs_read_hdr+0x714/0x930 fs/ntfs3/dir.c:385
ntfs_readdir+0xaad/0x1010 fs/ntfs3/dir.c:458
iterate_dir+0x276/0x9e0 fs/readdir.c:108
__do_sys_getdents fs/readdir.c:326 [inline]
__se_sys_getdents fs/readdir.c:312 [inline]
__x64_sys_getdents+0x143/0x290 fs/readdir.c:312
...
Allocated by task 2160:
kasan_save_stack+0x39/0x70 mm/kasan/common.c:56
kasan_save_track+0x14/0x40 mm/kasan/common.c:77
kasan_save_alloc_info+0x37/0x60 mm/kasan/generic.c:573
poison_kmalloc_redzone mm/kasan/common.c:400 [inline]
__kasan_kmalloc+0xc3/0xd0 mm/kasan/common.c:417
kasan_kmalloc include/linux/kasan.h:262 [inline]
__do_kmalloc_node mm/slub.c:5650 [inline]
__kmalloc_noprof+0x2bd/0x900 mm/slub.c:5662
kmalloc_noprof include/linux/slab.h:961 [inline]
mi_init+0x9d/0x110 fs/ntfs3/record.c:105
mi_format_new+0x6b/0x500 fs/ntfs3/record.c:422
ni_add_subrecord+0x129/0x540 fs/ntfs3/frecord.c:321
ntfs_look_free_mft+0x238/0xd90 fs/ntfs3/fsntfs.c:715
ni_create_attr_list+0x8e6/0x1690 fs/ntfs3/frecord.c:826
ni_ins_attr_ext+0x5ec/0x9d0 fs/ntfs3/frecord.c:924
ni_insert_attr+0x2bf/0x830 fs/ntfs3/frecord.c:1091
ni_insert_resident+0xec/0x3d0 fs/ntfs3/frecord.c:1475
ni_add_name+0x4b2/0x8a0 fs/ntfs3/frecord.c:2987
ni_rename+0xa6/0x160 fs/ntfs3/frecord.c:3026
ntfs_rename+0xa19/0xe00 fs/ntfs3/namei.c:332
vfs_rename+0xd42/0x1d50 fs/namei.c:5216
do_renameat2+0x715/0xb60 fs/namei.c:5364
__do_sys_rename fs/namei.c:5411 [inline]
__se_sys_rename fs/namei.c:5409 [inline]
__x64_sys_rename+0x83/0xb0 fs/namei.c:5409
x64_sys_call+0x8c4/0x26a0 arch/x86/include/generated/asm/syscalls_64.h:83
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x93/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x76/0x7e
Freed by task 85:
kasan_save_stack+0x39/0x70 mm/kasan/common.c:56
kasan_save_track+0x14/0x40 mm/kasan/common.c:77
__kasan_save_free_info+0x3b/0x60 mm/kasan/generic.c:587
kasan_save_free_info mm/kasan/kasan.h:406 [inline]
poison_slab_object mm/kasan/common.c:252 [inline]
__kasan_slab_free+0x6f/0xa0 mm/kasan/common.c:284
kasan_slab_free include/linux/kasan.h:234 [inline]
slab_free_hook mm/slub.c:2543 [inline]
slab_free mm/slub.c:6642 [inline]
kfree+0x2bf/0x6b0 mm/slub.c:6849
mi_clear fs/ntfs3/ntfs_fs.h:1107 [inline]
mi_put+0x10e/0x1a0 fs/ntfs3/record.c:97
ni_write_inode+0x479/0x2a00 fs/ntfs3/frecord.c:3320
ntfs3_write_inode+0x51/0x70 fs/ntfs3/inode.c:1042
write_inode fs/fs-writeback.c:1564 [inline]
__writeback_single_inode+0x8c9/0xc30 fs/fs-writeback.c:1784
writeback_sb_inodes+0x5e6/0xf60 fs/fs-writeback.c:2015
__writeback_inodes_wb+0x10c/0x2d0 fs/fs-writeback.c:2086
wb_writeback+0x63f/0x900 fs/fs-writeback.c:2197
wb_check_old_data_flush fs/fs-writeback.c:2301 [inline]
wb_do_writeback fs/fs-writeback.c:2354 [inline]
wb_workfn+0x8cc/0xd60 fs/fs-writeback.c:2382
process_one_work+0x8e0/0x1980 kernel/workqueue.c:3263
process_scheduled_works kernel/workqueue.c:3346 [inline]
worker_thread+0x683/0xf80 kernel/workqueue.c:3427
kthread+0x3f0/0x850 kernel/kthread.c:463
ret_from_fork+0x50f/0x610 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
The faulting address sits 590 bytes inside a freed kmalloc-1k object
allocated by ni_add_subrecord() and freed from ni_write_inode()
writeback.
[CAUSE]
ntfs_readdir() loads all subrecords once, but then drops ni_lock()
before it starts walking the directory metadata through ntfs_read_hdr().
That leaves the current NTFS_DE pointer backed by parent-directory
subrecord memory that concurrent writeback is still allowed to compact
and free.
The later ntfs_dir_emit() -> ntfs_iget5() call exposes the stale e->ref,
but the lifetime bug starts earlier: readdir is still consuming
parent-directory metadata after releasing the lock that protects it.
[FIX]
Keep ni_lock() held from the point where ntfs_readdir() starts
consuming the directory metadata until the walk over root/index entries
is finished.
This closes the parent-directory lifetime hole directly and keeps the
existing readdir d_type behaviour unchanged.
Signed-off-by: ZhengYuan Huang <gality369@gmail.com>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|
|
This warning shows up with gcc-10 now:
In file included from fs/ntfs3/index.c:15:
fs/ntfs3/index.c: In function 'indx_add_allocate':
fs/ntfs3/ntfs_fs.h:463:9: error: 'bmp_size' may be used uninitialized in this function [-Werror=maybe-uninitialized]
463 | return attr_set_size_ex(ni, type, name, name_len, run, new_size,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
464 | new_valid, keep_prealloc, NULL, false);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fs/ntfs3/index.c:1498:6: note: 'bmp_size' was declared here
1498 | u64 bmp_size, bmp_size_v;
| ^~~~~~~~
The warning does look correct, as the 'out2' label can be reached
without initializing bmp_size and bmp_size_v. Initialize these at
the same place as bmp.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
|