| Age | Commit message (Collapse) | Author |
|
exfat_alloc_new_dir() allocates a cluster for a new directory before
zeroing it. If exfat_zeroed_cluster() fails, the function returns the
error but leaves the allocated cluster in use.
Free the newly allocated cluster before returning the zeroing error.
Signed-off-by: Yichong Chen <chenyichong@uniontech.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
In afs_make_call(), there's a race with async call reception and
destruction. If a call is dispatched that doesn't have call->write_iter
set (used to specify the data content for FS.StoreData), then the first
rxrpc_kernel_send_data() will not set MSG_MORE in the msghdr.
Once rxrpc_send_data() queues the last request packet, the response could
come in at any time and cause the call to be completed and put. However,
afs_make_call() will look at the call again to see it ->write_iter should
be handled - something it's only allowed to do if it has its own ref on the
call. Whilst this is the case for synchronous calls, it isn't true for
async calls such as FS.FetchData.
There's also a potential UAF in afs_make_call() in the event that an
asynchronous call is being sent, but the call fails in some way (e.g. it
gets aborted from the server). The problem there is that afs_make_call()
tries to abort a call if the rxrpc send fails, but the asynchronous
notification from rxrpc may have caused the afs_call to be torn down.
generic/650 plays games with randomly taking CPUs offline, and can
interject a significant delay such that the call is deallocated before
afs_make_call() gets to check call->write_iter - and a UAF ensues (caught
by KASAN).
BUG: KASAN: slab-use-after-free in afs_make_call+0x1c90/0x2210 [kafs]
Read of size 8 at addr ffff888035e050e8 by task fsstress/1409
Fix this by making afs_make_op_call() give the op->call its own ref rather
than transferring the caller's ref to it and then dropping the ref when
afs_make_call() returns.
This also means that the afs_make_call() func never loses its ref on the
call now.
Fixes: eddf51f2bb2c ("afs: Make {Y,}FS.FetchData an asynchronous operation")
Fixes: e49c7b2f6de7 ("afs: Build an abstraction around an "operation" concept")
Link: https://sashiko.dev/#/patchset/20260702144919.172295-1-dhowells%40redhat.com
Reported-by: Marc Dionne <marc.dionne@auristor.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://patch.msgid.link/20260723113452.566619-4-dhowells@redhat.com
cc: Jeffrey Altman <jaltman@auristor.com>
cc: linux-afs@lists.infradead.org
cc: stable@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Fix afs_fs_fetch_data() to subtract subreq->transferred from subreq->len
rather than adding it.
Fixes: f28fc2010d62 ("afs: Eliminate afs_read")
Link: https://sashiko.dev/#/patchset/20260713081022.2186481-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://patch.msgid.link/20260723113452.566619-3-dhowells@redhat.com
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Jeffrey Altman <jaltman@auristor.com>
cc: linux-afs@lists.infradead.org
cc: stable@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Fix afs_fs_fetch_data() to set call->async on an async operation as does
afs_fs_fetch_data64().
Fixes: eddf51f2bb2c ("afs: Make {Y,}FS.FetchData an asynchronous operation")
Link: https://sashiko.dev/#/patchset/20260702144919.172295-1-dhowells%40redhat.com
Signed-off-by: David Howells <dhowells@redhat.com>
Link: https://patch.msgid.link/20260723113452.566619-2-dhowells@redhat.com
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Jeffrey Altman <jaltman@auristor.com>
cc: linux-afs@lists.infradead.org
cc: stable@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
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>
|
|
Several code paths update the VFS inode size by calling
netfs_resize_file() and cifs_setsize(), but omit the corresponding
fscache_resize_cookie() call, leaving the fscache cookie out of sync
with the actual file size:
- cifs_file_set_size() in inode.c: server-side truncation via setattr
- cifs_do_truncate() in file.c: truncates to zero on O_TRUNC open
- smb2_duplicate_extents() in smb2ops.c: file clone extending EOF
- smb3_simple_falloc() in smb2ops.c: two branches that extend EOF
via write-range and SMB2_set_eof respectively
Since every caller of cifs_setsize() must resize the fscache cookie,
add the call to cifs_setsize() itself, consistent with how
truncate_pagecache() is already consolidated there.
Fixes: 70431bfd825d ("cifs: Support fscache indexing rewrite")
Fixes: 93a43155127f ("cifs: Fix missing set of remote_i_size")
Fixes: 110fee6b9bb5 ("smb: client: fix missing timestamp updates with O_TRUNC")
Fixes: 7a06d3b816d7 ("smb/client: emulate small EOF-extending mode 0 fallocate ranges")
Cc: stable@vger.kernel.org
Cc: David Howells <dhowells@redhat.com>
Cc: Paulo Alcantara <pc@manguebit.org>
Cc: Huiwen He <hehuiwen@kylinos.cn>
Signed-off-by: Frank Sorenson <sorenson@redhat.com>
Reviewed-by: Paulo Alcantara <pc@manguebit.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
find_in_level() gets a dentry folio with f2fs_find_data_folio() before
calling find_in_block(). If find_in_block() returns an error, the
function stores the error in res_folio and breaks out of the loop without
dropping the dentry folio.
This leaks the folio reference on the find_in_block() error path. Drop
the dentry folio before returning the error to the caller.
Fixes: 7ad08a58bf67 ("f2fs: Handle casefolding with Encryption")
Cc: stable@vger.kernel.org
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Guanghui Yang <3497809730@qq.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
|
|
kfree() safely handles NULL pointers, so the explicit NULL check
before calling kfree() is unnecessary.
This issue was reported by ifnullfree.cocci.
Signed-off-by: Mohammad Shahid <mdshahid03@gmail.com>
Link: https://lore.kernel.org/r/20260726064228.248199-1-mdshahid03@gmail.com
Reviewed-by: Viacheslav Dubeyko <slava@dubeyko.com>
Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
|
|
Our v6.18 based Android system is continuely suffering livelock and bad
page stat as shown in[1] which related to broken xarray slot status. By
investigating big folio operations within f2fs, we find below races and
fix it by get the nr_pages before drop the refcount and folio_lock.
f2fs_get_read_data_folio() calls f2fs_folio_put() before
folio_nr_pages() when invalidating a large folio from the page cache.
That unlocks the folio and drops the caller reference, leaving a window
where a concurrent truncate or folio split can shrink the compound folio
or free it before the invalidate range is computed. An undersized range
then leaves split sub-folios in mapping->i_pages, which can later
interact badly with truncate and reclaim (stale xarray entries and bad
page state when folio->mapping no longer matches the mapping being
truncated).
[1]
PID: 2594 TASK: ffffff8169b81580 CPU: 7 COMMAND: "Thread-3"
#0 [ffffffc08ef2b8a0] xas_load at ffffffe52d1f42a4
#1 [ffffffc08ef2b900] find_get_entries at ffffffe52c185798
#2 [ffffffc08ef2bb60] truncate_inode_pages_range at ffffffe52c19e83c
#3 [ffffffc08ef2bbc0] truncate_inode_pages_final at ffffffe52c19ec2c
#4 [ffffffc08ef2bc20] f2fs_evict_inode at ffffffe52c4c8400
#5 [ffffffc08ef2bcc0] evict at ffffffe52c2de9f4
#6 [ffffffc08ef2bd00] iput at ffffffe52c2db1b4
#7 [ffffffc08ef2bd30] dentry_unlink_inode at ffffffe52c2d7204
#8 [ffffffc08ef2bd50] __dentry_kill at ffffffe52c2d3dcc
#9 [ffffffc08ef2bd80] dput at ffffffe52c2d3c3c
#10 [ffffffc08ef2bda0] __fput at ffffffe52c2b0a7c
#11 [ffffffc08ef2bde0] ____fput at ffffffe52c2b1034
#12 [ffffffc08ef2bdf0] task_work_run at ffffffe52beea200
#13 [ffffffc08ef2be20] exit_to_user_mode_loop at ffffffe52bfbc17c
#14 [ffffffc08ef2be80] el0_svc at ffffffe52d1f8e54
#15 [ffffffc08ef2beb0] el0t_64_sync_handler at ffffffe52d1f8d10
Cc: stable@kernel.org
Fixes: 05e65c14ea59 ("f2fs: support large folio for immutable non-compressed case")
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Zhaoyang Huang <zhaoyang.huang@unisoc.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
|
|
Blocks of pinfile may not aligned to section size due to wrong use
on pinfile, result in heavy overhead of GC, let avoid this by
adding additional check condition in f2fs_setattr().
- truncate -s 8mb pinfile
: random checkpoint may persist filesize w/ inode
- fallocate -o 0 -l 8mb pinfile
- f2fs_fallocate
- f2fs_expand_inode_data
- f2fs_allocate_pinning_section
- f2fs_map_blocks
- f2fs_map_lock
- __allocate_data_block
- file_need_truncate
: w/ FADVISE_TRUNC_BIT, we can expect unaligned mapping can be
truncated while open() if f2fs is not umount abnormally
- f2fs_map_unlock
: following f2fs checkpoint and sudden power-cut
- mount
- open pinfile
- f2fs_file_open
- finish_preallocate_blocks
- truncate_setsize
: filesize is 8mb
- f2fs_truncate
: can only truncate block outside filesize, rather than truncating
unaligned blocks inside filesize
Fixes: f5a53edcf01e ("f2fs: support aligned pinned file")
Cc: stable@kernel.org
Cc: Daeho Jeong <daehojeong@google.com>
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
|
|
Instead of allocating f2fs_gc_kthread dynamically, embed it in
f2fs_sb_info. This simplifies lifetime management and prepares for
fixing race conditions during teardown.
- __sbi_store - remount|shutdown
- f2fs_stop_gc_thread
- access sbi->gc_thread
- sbi->gc_thread = NULL
- access sbi->gc_thread->f2fs_gc_task
Fixes: 52190933c37a ("f2fs: sysfs: introduce critical_task_priority")
Fixes: 7950e9ac638e ("f2fs: stop gc/discard thread after fs shutdown")
Cc: stable@kernel.org
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
|
|
Commit 02117b8ae9c0 ("f2fs: Set GF_NOFS in read_cache_page_gfp while doing
f2fs_quota_read") adds GFP_NOFS in f2fs_quota_read() to avoid below deadlock:
- do_sys_open
- vfs_open
- dquot_file_open
- dquot_initialize
- dqget
- dquot_acquire
: locks &dqopt->dqio_mutex (VFS Quota Mutex)
- qtree_read_dquot
- f2fs_quota_read
- read_mapping_page (GFP_KERNEL / allows GFP_FS)
- __alloc_pages_nodemask
- try_to_free_pages (Direct Reclaim)
- prune_icache_sb
- evict
- f2fs_evict_inode
- dquot_drop
- dqput
- dquot_commit
: tries to lock &dqopt->dqio_mutex again
==> DEADLOCK (waiting for itself)
As Jan Kara mentioned, quota system has fixed this issue w/ commit
537e11cdc7a6 ("quota: Prevent memory allocation recursion while holding
dq_lock"), so this GFP_NOFS flag should be relic, let's use GFP_KERNEL
instead.
Cc: Jan Kara <jack@suse.cz>
Cc: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Chao Yu <chao@kernel.org>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
|
|
This patch proposes to drop FGP_NOFS from f2fs_filemap_get_folio()
in f2fs_write_begin(), I don't see there is potential deadlock issue
when __filemap_get_folio() calling into filesystem reclaim interfaces,
e.g. .writepages, evict_inode, shrinker.
Cc: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
|
|
cifs_file_set_size() calls cifs_setsize() on success, which calls
i_size_write(), updating i_size to the new value. The subsequent
check attrs->ia_size != i_size_read() in both cifs_setattr_unix()
and cifs_setattr_nounix() therefore always evaluates false after a
successful cifs_file_set_size(), making the smp_store_release() of
time_last_write dead code. The truncate path was unprotected against
stale readdir size updates.
Move the stamp to before the cifs_file_set_size() RPC call, guarded
by attrs->ia_size != i_size_read() to exclude no-op same-size
ftruncate(2) calls from stamping time_last_write unnecessarily.
On the error path the stamp remains rather than being restored:
restoring a stale snapshot (prev_tlw) could silently erase a
concurrent _cifsFileInfo_put() close stamp if that close arrived
between the READ_ONCE and the smp_store_release. readdir is
suppressed until the stamp expires, which extends beyond one acregmax
if the caller retries failed truncations. stat() is unaffected: the
cifs_revalidate_dentry_attr() path calls cifs_fattr_to_inode() with
from_readdir=false, which bypasses the time_last_write check in
is_size_safe_to_change() entirely and always writes the authoritative
QUERY_INFO result to i_size.
Remove the now-unreachable stamp from the dead block in both functions.
Fixes: e8a8d54c2d50 ("cifs: prevent readdir from changing file size due to stale directory metadata")
Signed-off-by: Frank Sorenson <sorenson@redhat.com>
Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
The time_last_write stamp was scattered across cifs_close(),
smb2_deferred_work_close(), and the three drain functions in misc.c.
This missed the case where background I/O holds the final reference
after userspace close() returns, and required explicit maintenance at
each close-path site.
Move the smp_store_release() into _cifsFileInfo_put(), immediately
before releasing open_file_lock. This single location covers all
close paths unconditionally: normal close, background I/O dropping the
final reference, deferred close via timer or external drain. The
spinlock's store-release/load-acquire pairing with is_inode_writable()
already provides the ordering guarantee documented in
is_size_safe_to_change().
Remove the now-redundant stamps from cifs_close(),
smb2_deferred_work_close(), and all six stamp sites in the misc.c
deferred-close drain functions.
Fixes: e8a8d54c2d50 ("cifs: prevent readdir from changing file size due to stale directory metadata")
Signed-off-by: Frank Sorenson <sorenson@redhat.com>
Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
Avoid redundant 'strlen()' and use the convenient 'strreplace()'
to simplify 'cifs_fscache_get_super_cookie()'.
Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
netfs_alloc_folioq_buffer() may leave a partially allocated folio
queue attached to the caller's buffer pointer when it returns an error.
smb3_init_transform_rq() stores the buffer in the request only after
allocation succeeds, so the common error path cannot free a partial
allocation. Store the buffer pointer before checking the return value so
err_free releases it.
Signed-off-by: Yichong Chen <chenyichong@uniontech.com>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
Pull misc fixes from Andrew Morton:
"13 hotfixes. All are cc:stable. 11 are for MM. All are singletons -
please see the changelogs for details"
* tag 'mm-hotfixes-stable-2026-07-27-14-18' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm:
fs/proc/task_mmu: fix PAGEMAP_SCAN written state for PMD holes
mm/hugetlb: fix list corruption in allocate_file_region_entries()
mm: mglru: fix stale batch updates after memcg reparenting
selftest: fix headers in fclog.c
ocfs2: fix boundary check in ocfs2_check_dir_entry() to use buffer offset
mm/percpu-km: fix bitmap overflow and accounting in pcpu_create_chunk()
mm/util: don't read __page_2 for order-1 folios in snapshot_page()
mm/hugetlb: fix swap entry corruption when clearing uffd-wp at fork()
mm: migrate_device: fix pte_pfn/pte_dirty called on non-present PTE
fs/proc/task_mmu: fix PAGEMAP_SCAN written state for unpopulated ptes
userfaultfd: wait on source PMD during UFFDIO_MOVE
lib: test_hmm: use device devt for coherent device range selection
mm/vmstat: fold stranded per-cpu node stats when a node comes online
|
|
CONFIG_PRINT_QUOTA_WARNING was marked as BROKEN in 2023 by 36d532d713db
("quota: mark PRINT_QUOTA_WARNING as BROKEN").
The code is apparently unused and uninteresting, so remove it all, incl.
the abuse of TTY.
Signed-off-by: Jiri Slaby (SUSE) <jirislaby@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jan Kara <jack@suse.com>
Cc: Yangtao Li <frank.li@vivo.com>
Link: https://patch.msgid.link/20260722060155.1111519-1-jirislaby@kernel.org
Signed-off-by: Jan Kara <jack@suse.cz>
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs
Pull erofs fixes from Gao Xiang:
"Fix a regression in page cache sharing which can cause a NULL pointer
dereference, and limit LZMA stream memory usage on systems with many
CPUs.
- Keep a valid f_path for page cache sharing to fix a recent
mincore() NULL pointer dereference
- Limit LZMA stream pool size when too many processors are available
- Sync up with Hongbo Li's latest email address"
* tag 'erofs-for-7.2-rc6-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs:
erofs: cap LZMA stream pool size
erofs: ensure valid f_path for page cache sharing
MAINTAINERS: update Hongbo Li's email address
|
|
In udf_do_extend_file() the total extent length is rounded up to a block
boundary with:
iinfo->i_lenExtents = (iinfo->i_lenExtents + sb->s_blocksize - 1) &
~(sb->s_blocksize - 1);
i_lenExtents is a __u64, but sb->s_blocksize is unsigned long. On 32-bit
kernels unsigned long is 32-bit, so ~(sb->s_blocksize - 1) is a 32-bit
value (e.g. 0xfffff800 for a 2 KiB block) that is zero-extended in the AND,
clearing the upper 32 bits of i_lenExtents. For UDF files whose total
extent length exceeds 4 GiB this truncates i_lenExtents when the file is
extended, corrupting the tracked extent length.
Cast the block size to 64-bit before forming the mask. 64-bit kernels are
unaffected.
Fixes: 48d6d8ff7dca ("udf: cache struct udf_inode_info")
Cc: stable@vger.kernel.org
Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
Link: https://patch.msgid.link/20260722082425.213311-1-zhanxusheng@xiaomi.com
Signed-off-by: Jan Kara <jack@suse.cz>
|
|
Allow a process to move its root directory into failfs via
fchroot(FD_FAILFS_ROOT). From that point on every absolute path lookup
and every absolute symlink fails with EOPNOTSUPP. Combined with
fchdir(FD_FAILFS_ROOT) this leaves the process with lookups anchored
at explicit directory file descriptors only. It is the fs_struct
equivalent of RESOLVE_BENEATH. This allows taks to drop their filesystem
state completely.
Callers with CAP_SYS_CHROOT in their user namespace may always do
this, mirroring chroot(2). Unprivileged callers are subject to three
requirements (which may be loosened later):
(1) no_new_privs must be set
After entering failfs suid binaries on regular mounts remain
reachable via inherited directory file descriptors or the working
directory. A setuid program executing with an unusable root
directory might be tricked by this. I'm not 100% convinced that this
is needed but it feels more secure initially and it also forces more
no_new_privs on userspace. So win-win imo.
(2) The caller must not already be chrooted.
The root directory is what confines .. resolution. The failfs root
can never be reached by walking up a real mount tree. A task whose
root is failfs has no .. barrier left below the top of its mount
tree. A .. walk from any real directory fd it still holds climbs
to the mount-namespace root. Which is kinda the point if you want to
do fd-based lookup only. If failfs prevented you from doing that
then it doesn't make a lot of sense.
A task that a privileged manager chrooted into a subtree could use
chroot()ing into failfs as a way to allow for an inherited fd to
resolve it again.
So reject already-chrooted callers closing that issue without losing
anything for the intended self-sandboxing use case.
(3) The caller must not share its fs_struct.
Requirement (1) is checked on the calling thread, but the root
lives in the fs_struct which may be shared via CLONE_FS. A sibling
thread without no_new_privs could then execute a setuid binary with
the failfs root and defeat (1). setns() to a mount or user namespace
refuses a shared fs_struct for the same kind of reason, so do the
same here and require fs->users == 1. no_new_privs is inherited
across clone() and can never be cleared, so any CLONE_FS child
created afterwards carries it too and the guarantee holds.
Privileged callers (CAP_SYS_CHROOT) are not subject to these
requirements and may share the fs_struct. They can already chroot and
exec a setuid binary today, so failfs hands them nothing new.
Backing out is currently hard, but that is a property of the current
implementation and not a promise. current_chrooted() treats a failfs
root as chrooted so for now the task cannot create user namespaces to
regain CAP_SYS_CHROOT and chroot()/fchroot() back out require
CAP_SYS_CHROOT. This is not guaranteed though. current_chrooted() may
change, or an unprivileged no_new_privs task could be allowed to chroot
to a real directory, either of which would loosen this. So don't treat
it as a permanent one-way door.
The remaining way out today is setns() to a mount namespace file
descriptor which requires CAP_SYS_ADMIN over the target namespace plus
CAP_SYS_CHROOT and CAP_SYS_ADMIN in the caller's user namespace and
resets both root and working directory. A task that closes or never had
such file descriptors and restricts *chdir()/*chroot()/setns() via
seccomp currently cannot get back out.
Link: https://patch.msgid.link/20260724-work-failfs-v2-4-485dabbae185@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Add a file descriptor based counterpart to chroot(2). This has been
overdue for a long time. It is the natural companion to fchdir() and
avoids re-resolving a path that the caller already holds a file
descriptor to. No TOCTOU between resolving the target and changing the
root. It composes with modern fd-based APIs meaning it works with O_PATH
file descriptors and file descriptors to detached mount trees created
via open_tree(OPEN_TREE_CLONE).
The permission model is identical to chroot(2). The caller must have
CAP_SYS_CHROOT in its user namespace, must pass MAY_EXEC | MAY_CHDIR
permission checks on the target directory, and LSMs are consulted via
the same security_path_chroot() hook.
The system call takes a flags argument for future extensibility which
must currently be zero.
Link: https://patch.msgid.link/20260724-work-failfs-v2-3-485dabbae185@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Add a new file descriptor sentinel FD_FAILFS_ROOT following
FD_PIDFS_ROOT and FD_NSFS_ROOT and teach fchdir() to accept it. A
process calling fchdir(FD_FAILFS_ROOT) moves its working directory
into failfs. Every AT_FDCWD-relative lookup afterwards fails with
EOPNOTSUPP including "." and ".." and getcwd() reports the working
directory as unreachable from the process root by returning a path
prefixed with "(unreachable)". Lookups relative to explicit directory
file descriptors are unaffected.
The sentinel is the only way in. No privilege or gating is required.
Setting the working directory to a directory in which every operation
fails grants nothing and loses nothing that closing file descriptors
couldn't lose. An unlinked working directory behaves the same way today
modulo errno. The working directory also plays no role in confining ".."
resolution so no boundary is weakened.
Link: https://patch.msgid.link/20260724-work-failfs-v2-2-485dabbae185@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
nullfs provides a permanently empty and immutable directory. Lookups
fail with ENOENT. The directory can be opened, read, stat, mounted upon.
It behaves like nothing is there.
Add its counterpart failfs where the semantics are not "there is
nothing here" but "nothing is supported here". Every operation that
reaches the filesystem fails with EOPNOTSUPP. Even statfs()/fstatfs()
fail so the filesystem cannot be discovered through an fd to it.
EOPNOTSUPP rather than a permission errno keeps that coherent. There
is no permission model in which anything could ever be allowed and
EACCES or EPERM would merely suggest that different credentials might
succeed while EIO would suggest corruption. It also makes hitting the
failfs boundary mostly quite dinstinguishable. A task anchoring its
lookups at real directory file descriptors may be able to tell a failfs
refusal from an ordinary permission failure. I wouldn't go so far as
guaranteeing that but it should mostly work.
No path lookup can open the root, not even with O_PATH. It is never
reached by a lookup in a parent directory. The only way to a path-walk
terminal at the root is a jump through a /proc/<pid>/{root,cwd} magic
link or by mountpoint traversal. The root also refuses
->d_weak_revalidate() which the VFS calls for jumped terminals. That
covers the jump-based references too: an O_PATH open is refused,
name_to_handle_at() cannot encode it into a file handle, and following a
magic link into it fails. A plain readlink() of such a link still works
and shows "failfs:/".
There is a single instance of failfs mounted during early boot via
kern_mount() making it logically distinct from every mount namespace.
Since the mount is a member of no mount namespace mounting onto it
fails. So nothing can ever be mounted on top of it. It cannot be cloned
via OPEN_TREE_CLONE and it does not show up in statmount()/listmount()
or /proc/<pid>/mountinfo. The filesystem is not registered so it is
not visible in /proc/filesystems and cannot be mounted from userspace.
This lets tasks shed their filesystem state completely. A process with
its root directory or working directory in failfs must anchor every path
lookup at an explicit file descriptor or is doomed to fail any lookup.
Absolute paths, absolute symlinks, and AT_FDCWD-relative lookups
simply fail. Followup patches will expose it via a new FD_FAILFS_ROOT
file descriptor sentinel understood by fchdir() and the new fchroot()
system call.
Link: https://patch.msgid.link/20260724-work-failfs-v2-1-485dabbae185@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Buffers containing the directory entries of a directory's children are
tracked in the directory inode's metadata bh list. Before commit
525da4f40a7c ("fat: Fix missed inode writeback during fsync(2)")
fsync(2) of a directory wrote that list out unconditionally via
mmb_fsync_noflush(). Now the list is written by
fat_sync_inode_metadata() which __writeback_single_inode() only
invokes when the inode has I_METADATA_WRITEBACK set. The root inode
never gets I_METADATA_WRITEBACK - __fat_write_inode() returns early
for it since the root directory has no directory entry of its own -
and fat_sync_inode_metadata() returns early for it as well. Hence
fsync(2) on the root directory returns success without writing out the
directory entries of its children.
Set I_METADATA_WRITEBACK for the root inode in __fat_write_inode() and
make fat_sync_inode_metadata() only skip the nonexistent directory
entry for the root inode but still sync the metadata bh list.
Fixes: 525da4f40a7c ("fat: Fix missed inode writeback during fsync(2)")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
fat_sync_inode_metadata() ignores the result of writing the buffer
containing the inode's directory entry. Before commit 525da4f40a7c
("fat: Fix missed inode writeback during fsync(2)") a write error was
propagated to fsync(2) via __fat_write_inode() -> sync_dirty_buffer(),
now fsync(2) reports success even though the inode's directory entry
could not be written. Check buffer_write_io_error() after
sync_dirty_buffer() like the other ->sync_inode_metadata
implementations do.
Fixes: 525da4f40a7c ("fat: Fix missed inode writeback during fsync(2)")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Commit e668e0668181 ("fat: Replace fat_sync_inode() with
sync_inode_metadata()") hoisted mark_inode_dirty() in front of the
IS_DIRSYNC conditional in all converted callers except for the main
rename path of do_msdos_rename(). There old_inode is generally still
clean when the target directory has DIRSYNC set and, unlike
fat_sync_inode(), sync_inode_metadata() does nothing for a clean inode.
Thus the directory entry at the new location is never updated with the
contents of old_inode: it stays the way msdos_add_entry() created it,
with start cluster 0 and size 0 (or, when the rename replaced an
existing target, it keeps describing the deleted target). Since
old_inode is also never marked dirty, later writeback doesn't update
the entry either and the stale directory entry ends up on disk even on
a clean unmount, so the renamed file loses its contents.
Mark old_inode dirty before calling sync_inode_metadata() like all the
other call sites do.
Fixes: e668e0668181 ("fat: Replace fat_sync_inode() with sync_inode_metadata()")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
zisofs_fill_pages() reads the compressed block pointer table. The error
paths release the current buffer_head, the loop also releases the old
buffer_head when it advances. However, the success path leaves the last
buffer_head referenced. Release it before returning success.
Fixes: 59bc055211b8 ("zisofs: Implement reading of compressed files when PAGE_CACHE_SIZE > compress block size")
Signed-off-by: Yichong Chen <chenyichong@uniontech.com>
Link: https://patch.msgid.link/20260721091152.1450622-1-chenyichong@uniontech.com
Signed-off-by: Jan Kara <jack@suse.cz>
|
|
Now that everybody has been converted from mmb_fsync() (and it's variant
mmb_fsync_noflush()) to simple_fsync(), we can delete these calls.
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-40-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Use generic sync_inode_metadata() instead of fat_sync_inode() for
persisting inode metadata changes for DIRSYNC inodes. This slightly
simplifies code and also addresses a theoretical race where
fat_sync_inode() could return before all metadata buffers associated
with the inode were properly written out when racing with fsync(2).
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-39-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
FAT could fail to properly write out inode on fsync(2) due to races with
WB_SYNC_NONE writeback. Several racing fsyncs could also result in some
fsync returning earlier than all metadata buffers were properly
persisted.
Fix these issues by using new .sync_inode_metadata method which makes
sure all inode related metadata is written to disk during any
WB_SYNC_ALL writeback. The slight disadvantage of this approach is that
when fsync(2) of an inode races with rename(2) of the inode, the window
during which inode isn't properly persisted becomes wider.
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-38-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Several racing fsyncs on ext4 in nojournal mode could result in some
fsync returning earlier than all metadata buffers were properly
persisted. Also ext4_fsync() in nojournal mode was somewhat inefficient
because it was always writing out the inode regardless whether it was
dirty or not.
Fix these issues by using new .sync_inode_metadata method which makes
sure all inode related metadata is written to disk during any
WB_SYNC_ALL writeback in nojournal mode. This also somewhat simplifies
the nojournal mode fsync handling.
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-37-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Minix could fail to properly write out inode on fsync(2) due to races
with WB_SYNC_NONE writeback. Several racing fsyncs could also result in
some fsync returning earlier than all metadata buffers were properly
persisted. Furthermore DIRSYNC handling missed writing inode related
metadata.
Fix all these issues by using new .sync_inode_metadata method which
makes sure all inode related metadata is written to disk during any
WB_SYNC_ALL writeback.
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-36-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
BFS could fail to properly write out inode on fsync(2) due to races with
WB_SYNC_NONE writeback. Several racing fsyncs could also result in some
fsync returning earlier than all metadata buffers were properly
persisted.
Fix all these issues by using new .sync_inode_metadata method which
makes sure all inode related metadata is written to disk during any
WB_SYNC_ALL writeback.
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-35-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
There is no point in udf_update_inode() anymore as it has a single
caller. Just fold udf_update_inode() into it.
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-34-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Instead of opencoding inode update in udf_evict_inode() just use
sync_inode_metadata().
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-33-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
The only place using udf_sync_inode() is now inode_getblk() for flushing
IS_SYNC inodes after write and page_mkwrite allocating blocks. For write
the flushing is actually taken care of by generic_write_sync() so it
isn't needed here. For page_mkwrite it does have effect however none of
the other filesystems seem to bother with flushing IS_SYNC inode on page
fault and properly synchronizing such writeback with standard inode
writeback would be slightly complex due to locking constraints. So just
drop IS_SYNC inode handling from inode_getblk().
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-32-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
When setting inode size we directly writeout inode in udf_setsize().
This misses proper writeout of other inode related metadata. Use
sync_inode_metadata() instead and move the flushing to udf_setattr() to
avoid it for udf_evict_inode() where it would be pointless.
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-31-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
UDF could fail to properly write out inode on fsync(2) due to races
with WB_SYNC_NONE writeback. Several racing fsyncs could also result in
some fsync returning earlier than all metadata buffers were properly
persisted.
Fix all these issues by using new .sync_inode_metadata method which
makes sure all inode related metadata is written to disk during any
WB_SYNC_ALL writeback.
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-30-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Ext2 could fail to properly write out inode on fsync(2) due to races
with WB_SYNC_NONE writeback. Several racing fsyncs could also result in
some fsync returning earlier than all metadata buffers were properly
persisted. Finally DIRSYNC handling was not properly persisting all
inode related metadata.
Fix all these issues by using new .sync_inode_metadata method which
makes sure all inode related metadata is written to disk during any
WB_SYNC_ALL writeback.
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-29-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
For sync(2) the generic code calls sync_blockdev_nowait() and later
sync_blockdev() to persist all metadata buffers. Thus there's no need
for ext2_write_inode() to do that which speeds up sync(2) writeback.
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-28-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Fold special helper __ext2_write_inode() into ext2_write_inode() and
just learn the single caller of __ext2_write_inode() to pass proper wbc
instead. No functional changes.
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-27-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
ext2_setsize() and ext2_xattr_set2() had a construct like:
if (IS_SYNC(inode)) {
sync_inode_metadata(inode, 1);
} else {
mark_inode_dirty(inode);
}
which leads to lost inode updates for IS_SYNC inodes because
sync_inode_metadata() does anything only if the inode is already dirty
and hence inode updates may be simply lost. Fix the problem by
unconditionally marking the inode dirty and *then* call
sync_inode_metadata().
CC: stable@vger.kernel.org
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-26-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Currently, inode and in general metadata writeback is handled in a lazy
manner. When inode is dirty, __writeback_single_inode() calls
.write_inode method which for lots of filesystems just copies inode
metadata into the underlying block buffer. Writeback of other metadata
associated with the inode (as well as buffers underlying inodes) is
usually handled completely separately and implicitely during writeback
of block device inode. This is good for efficiency of WB_SYNC_NONE
writeback or sync(2). However it becomes problematic for situations
where we want to make sure inode and its metadata is really persistent
on disk. fsync(2) is the most pronounced example of this and thus we
have grown a special file operation and various helper functions to
assist with this task. However fsync(2) is not the only case, For
example directories with DIRSYNC flag need similar functionality and
current use of sync_inode_metadata() for this task in filesystems
generally misses writeout of necessary metadata.
Furthermore even fsync(2) handling as implemented by simple_fsync() or
similar helpers is racy and can fail to properly persist the inode. The
problem is that WB_SYNC_NONE writeback can copy inode metadata into
underlying buffer and clean inode dirty bits. Following fsync(2) will
see inode is clean and will fail to make sure underlying buffer is
written out.
When multiple fsync(2) calls race, there's also another type of race
involving mmb_fsync(). There the problem is buffers already submitted to
the disk are no longer tracked in the mmb list and so racing mmb_sync()
can return before all of the IO completes.
Provide a new inode state bit I_METADATA_WRITEBACK tracking whether
writeback of inode related metadata may be needed for successful data
integrity sync and if this bit is set __writeback_single_inode() for
data integrity writeback will call new superblock operation
.sync_inode_metadata whose task is to make sure all metadata associated
with the inode (including the inode itself) is properly persisted. This
will allow filesystems to address the data integrity issues described
above and at the same time somewhat simplify our fsync implementations.
Issues with racing fsync(2) calls will be addressed by synchronization on
I_SYNC inode state which is set while calling .sync_inode_metadata, issues
with missed inode buffer writeback are fixed by filesystems looking up
corresponding buffer head and writing it out if needed.
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-25-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
Currently every ext4 inode gets mapping_metadata_bhs struct although it
is only needed when running without a journal and only for inodes where
any metadata was dirtied. Allocate mapping_metadata_bhs struct on demand
when dirtying the first metadata buffer for the inode.
Acked-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-24-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
When mmb_fsync_noflush() or simple_fsync_noflush() race with another
writeback of the same inode, they can see inode dirty bits are already
clear and skip inode writeback although the racing
__writeback_single_inode() didn't yet get to writing anything. This can
result in fsync(2) returning without properly persisting the inode.
We already have I_SYNC bit for this synchronization and
writeback_single_inode() properly uses it so just fix
mmb_fsync_noflush() and simple_fsync_noflush() to take it into account
as well.
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-23-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
When filesystem is freeing inode it calls mmb_invalidate() which removes
bhs from inode's metadata bh tracking and clears b_mmb for them. However
if the inode is getting deleted, we don't bother with calling mmb_sync()
before and thus these buffers can be under IO and we can be racing with
IO completion handler calling mark_buffer_write_io_error(). This race
can lead to mark_buffer_write_io_error() either hitting NULL pointer
reference or trying to operate on already freed inode. Protect the
mapping handling with RCU to make sure mmb and inode aren't freed before
we are done with them.
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-22-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
AFFS did all the hard work of tracking metadata bhs dirtied for an inode
but it actually never used this information as affs_file_fsync() just
calls sync_blockdev() to writeback all filesystem metadata bhs. After a
discussion with AFFS maintainer nobody cares about AFFS performance
so let's keep this affs_file_fsync() behavior and just drop all the
pointless tracking from AFFS.
CC: David Sterba <dsterba@suse.com>
Acked-by: David Sterba <dsterba@suse.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260727104923.3828017-21-jack@suse.cz
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
|
exfat_move_file() removes the old directory entry before the new entry
has been written. If writing the new entry fails, rename returns an
error after the source entry has already been marked deleted.
Write the new entry first, then remove the old entry and update the
cached inode location. This keeps the source entry intact if creating
the destination entry fails.
Signed-off-by: Yichong Chen <chenyichong@uniontech.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|