| Age | Commit message (Collapse) | Author |
|
For encrypting and decrypting file contents on block-based filesystems
(i.e., ext4 and f2fs, but not ceph and ubifs), always use blk-crypto
instead of fs-layer crypto (direct use of crypto_skcipher).
Since the blk-crypto API provides a fallback to CPU-based encryption,
it's all that's needed on block-based filesystems. The support for two
alternative block-based file contents encryption implementations,
fs-layer and blk-crypto, existed mainly for historical reasons, as the
fs-layer path came first. Some of it is also still needed for the
non-block-based filesystems, but a lot of it isn't.
Removing the duplicate fs-layer code paths greatly simplifies the code,
most of which is done in later commits.
Specific implementation details:
- SB_INLINECRYPT now controls whether blk_crypto_config::allow_hw is set
to true, instead of whether blk-crypto is used at all. The effect is
that the semantics are preserved: the inlinecrypt mount option selects
the use of inline encryption hardware instead of the CPU.
- Set up a blk_crypto_key iff the file is a regular file on a
block-based filesystem. To determine whether the filesystem is
block-based, add a bit fscrypt_operations::is_block_based.
- Remove fscrypt_select_encryption_impl(). Move the logging logic that
was previously there into fscrypt_prepare_inline_crypt_key(). Note
that blk_crypto_config_supported() is no longer needed.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://patch.msgid.link/20260713023708.9245-6-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
|
|
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 with s_blocksize != PAGE_SIZE works
only with the fs-layer implementation of file contents encryption, not
blk-crypto. This is a problem for standardizing on blk-crypto.
Fortunately, no one should be using this combination anyway. It doesn't
make sense because the entire point of IV_INO_LBLK_32 is to support
inline encryption hardware that is limited to 32-bit DUNs.
Thus, fully disallow IV_INO_LBLK_32 with s_blocksize != PAGE_SIZE.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://patch.msgid.link/20260713023708.9245-5-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
|
|
fscrypt uses inline encryption hardware only when the "inlinecrypt"
mount option is given. I'd like to keep that behavior even after
standardizing on the blk-crypto API for file contents encryption. That
is, the default should continue to be the well-tested CPU-based
encryption code, and the use of inline encryption hardware should
continue to be an opt-in feature for systems where it's beneficial and
has been fully validated (including verifying ciphertext correctness).
To support this use case, extend blk_crypto_config with a new flag
BLK_CRYPTO_CFG_ALLOW_HW.
For now it's always set. Later commits will change that.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://patch.msgid.link/20260713023708.9245-4-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
|
|
Since the kernel's minimum gcc version is now 8.1, the workaround for a
strange gcc bug in fscrypt_ioctl_set_policy() is no longer needed.
Link: https://patch.msgid.link/20260619051008.51223-1-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
|
|
Since CONFIG_FS_ENCRYPTION is a bool, not a tristate, fs/crypto/ can
only be builtin or absent entirely; it can't be a loadable module.
Therefore, the error code that gets returned from the fscrypt_init()
initcall is never used. If any part of the initcall does fail, which
should never happen, the kernel will be left in a bad state.
Following the usual convention for builtin code, just panic the kernel
if any of part of the initcall fails. This simplifies the code.
This closely mirrors commit e77000ccc531 ("fsverity: simplify handling
of errors during initcall").
Link: https://patch.msgid.link/20260619000030.166851-1-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
|
|
Now that the arrays of per-mode keys in struct fscrypt_master_key have
been replaced by a linked list, the definition of FSCRYPT_MODE_MAX
doesn't do anything useful. (Previously it was used to size these
arrays.) Remove it.
Link: https://patch.msgid.link/20260618231404.132829-1-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
|
|
When a blk_crypto_key starts being used or is evicted, fs/crypto/ calls
fscrypt_get_devices() to get the filesystem's list of block devices,
then iterates over them and calls blk_crypto_config_supported(),
blk_crypto_start_using_key(), or blk_crypto_evict_key() on each one.
Currently, the block device pointers are placed in a dynamically
allocated array. This dynamic allocation is problematic because:
- It can fail, especially at the fscrypt_destroy_inline_crypt_key() call
site when it's invoked for inode eviction under direct reclaim.
- fscrypt_destroy_inline_crypt_key() doesn't handle the failure. It
just zeroizes and frees the blk_crypto_key without calling
blk_crypto_evict_key(). That causes a use-after-free.
For now, let's fix this in the straightforward and easily-backportable
way by switching to an on-stack array. Currently the fscrypt
multi-device functionality is used only by f2fs, which has a hardcoded
limit of 8 block devices. An on-stack array works fine for that.
(Of course, this solution won't scale up to large number of block
devices. For that we'd need a different solution, like moving the block
device iteration into the filesystem. Or in the case of btrfs, which
will only support blk-crypto-fallback, we should make it just call
blk-crypto-fallback directly, so the block devices won't be needed.)
Fixes: 22e9947a4b2b ("fscrypt: stop holding extra request_queue references")
Cc: stable@vger.kernel.org
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260713023708.9245-1-ebiggers%40kernel.org
Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://patch.msgid.link/20260719055602.78828-1-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
|
|
Replace all remaining calls to mutex_lock() and mutex_unlock() in
fs/crypto/ with lock guards. No functional change.
Link: https://patch.msgid.link/20260618184852.3469301-1-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
|
|
The legacy 'fscrypt_direct_keys' table caches master keys that are used
by v1 encryption policies that have FSCRYPT_POLICY_FLAG_DIRECT_KEY.
It's just a global table for all filesystems (since the keys can be
provided by the legacy process-subscribed keyrings mechanism, which
makes it difficult to reuse super_block::s_master_keys).
The entries in it ('struct fscrypt_direct_key') do contain a super_block
pointer, though, for passing to fscrypt_destroy_inline_crypt_key() when
the last inode that references the key is evicted.
However, when finding the fscrypt_direct_key for an inode, we weren't
actually comparing the super_block pointer. As a result, inodes with
different super_blocks could point to the same fscrypt_direct_key. That
could extend the lifetime of a fscrypt_direct_key beyond the
super_block it points to, causing a use-after-free later.
Fix this by creating distinct fscrypt_direct_key structs for distinct
super_block structs.
Note that this problem doesn't exist in the v2 policy equivalent
("per-mode keys"), since the data structures there are per super_block.
Fixes: 22e9947a4b2b ("fscrypt: stop holding extra request_queue references")
Cc: stable@vger.kernel.org
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260717044303.425265-1-ebiggers%40kernel.org
Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://patch.msgid.link/20260719033120.122120-1-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
|
|
I noticed that we were immediately exiting this function if the
allocation fails, leaving the client and server object refcounts bumped.
Fix this by creating a common exit point to clean up dangling
references.
Fixes: 576acc259146 ("nfs4: take a reference on the nfs_client when running FREE_STATEID")
Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
|
|
Dan Aloni reports that he was able to hit a use-after-free bug if a
FREE_STATEID operation gets delayed for whatever reason. Fix this by
bumping the refcount of the 'struct nfs_server' object for the duration
of the FREE_STATEID so it doesn't get cleaned up from underneath us
while operations are still in flight.
Reported-by: Dan Aloni <dan.aloni@vastdata.com>
Fixes: 7c1d5fae4a87 ("NFSv4: Convert nfs41_free_stateid to use an asynchronous RPC call")
Tested-by: Dan Aloni <dan.aloni@vastdata.com>
Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
|
|
xfs_rtginode_ensure() treats every xfs_rtginode_load() error other than
-ENOENT as success. This can leave the realtime group inode unset after an
I/O, allocation, or corruption error. Growfs then continues as though the
inode had been loaded.
Only -ENOENT means that the inode needs to be created. Return all other
errors to the growfs caller.
Fixes: ae897e0bed0f ("xfs: support creating per-RTG files in growfs")
Cc: stable@vger.kernel.org
Signed-off-by: Guanghui Yang <3497809730@qq.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
|
|
cifs_filldir() copies the entry name out of an SMB1 TRANS2_FIND_FIRST /
FIND_NEXT response using a length (de.namelen) supplied by the server.
The kmalloc'd SMB response buffer is bounded, but nothing checks that
de.name + de.namelen still lies inside that buffer before the eventual
filldir64() -> verify_dirent_name() -> memchr() reads namelen bytes.
A hostile SMB1 server that returns an oversized FileNameLength in a
directory entry therefore causes memchr() to read past the end of the
response slab buffer. Reachable from any user who can list a directory
on a CIFS mount served by an attacker-controlled server (getdents64()
on the mounted directory):
BUG: KASAN: slab-out-of-bounds in memchr+0x71/0x80
Read of size 1 at addr ffff88800e0640cc by task poc/115
Call Trace:
dump_stack_lvl+0x64/0x80
print_report+0xce/0x620
kasan_report+0xec/0x120
memchr+0x71/0x80
filldir64+0x4c/0x6a0
cifs_filldir.constprop.0+0x9bb/0x1e00
cifs_readdir+0x2101/0x3380
iterate_dir+0x19c/0x520
__x64_sys_getdents64+0x126/0x210
do_syscall_64+0x107/0x5a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Pass the end-of-response pointer down to cifs_filldir() and reject
entries whose name would extend past that boundary.
This bug was discovered by Artiphishell's vTriage pipeline, which
generated a userspace reproducer (an emulated hostile SMB1 server plus
a getdents64() client) that reliably triggers the KASAN report on an
unpatched kernel. The fix below was drafted with the Claude coding
assistant; a userspace reproducer is available on request.
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Jay Vadayath <jay@artiphishell.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
parse_dfs_referrals() validates that the response contains the fixed
referral entry array and, on for-next, the per-referral string offsets.
However, the response also contains a PathConsumed value that is later
used for DFS path parsing.
If a malformed response provides a PathConsumed value larger than the
search name, later DFS parsing can advance beyond the end of the path.
Validate PathConsumed against the search name length before storing it in
the parsed referral.
Fixes: 4ecce920e13a ("CIFS: move DFS response parsing out of SMB1 code")
Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
Signed-off-by: Yichong Chen <chenyichong@uniontech.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
We are no longer keeping unreferences glocks around, so remove the
now-obsolete glock lru list and shrinker.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
|
|
When we were still caching unreferenced glocks, evicting all the cached inodes
in gfs2_kill_sb() did put the unreferenced glocks onto the glock lru list, and
they would be freed in gfs2_gl_hash_clear(). We could set the
SDF_SKIP_DLM_UNLOCK flag in gfs2_gl_hash_clear() to indicate to gdlm_put_lock()
to skip unlocking glocks explicitly when possible. Now, glocks are demoted and
dropped immediately though, so to allow gdlm_put_lock() to skip unnecessary
unlocking, we need to set some "unmount" flag before calling
gfs2_evict_inodes(). We can use the existing SDF_KILL flag for that if we set
it before calling gfs2_evict_inodes() in gfs2_kill_sb().
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
|
|
Currently, gfs2 caches unreferenced glocks until memory pressure sets in or the
filesystem is unmounted. This was supposedly done to avoid excessive log
flushing: when a glock still has outstanding revokes, freeing it requires an
extra log flush, and we want to avoid too many of those extra log flushes.
Since commit 9287c6452d2b1 ("gfs2: Fix occasional glock use-after-free"),
outstanding revokes are accounted for in the glock reference count and glocks
with outstanding revokes will never be freed anymore, so this is no longer an
issue.
This also means that we won't need a glock LRU list anymore, but we leave
removing that list to a later patch for better readability.
It might seem that glocks that are not referenced anymore can be dropped
immediately without unlocking them first, but that isn't true for inode glocks
that have an address space attached (the "gfs2_glock(aspace)" slab cache): that
address space is only truncated when the associated glock is unlocked. So
unlock those glocks when they become unreferenced.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
|
|
All of the examiner functions passed to glock_hash_walk() can deal with glock
hash table resizes and the resulting repeat visiting of glocks, so we can allow
automatic glock hash table shrinking.
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
|
|
Improve debugfs_start_creating() to warn if it was used before debugfs
initialization. It silently returned ERR_PTR(-ENOENT) before, but it is
hard to find the cause of failure especially if it was called by
debugfs_create_dir(), because the document of the function says:
> NOTE: it's expected that most callers should _ignore_ the errors returned
> by this function. Other debugfs functions handle the fact that the "dentry"
> passed to them could be an error and they don't crash in that case.
> Drivers should generally work fine even if debugfs fails to init anyway.
Signed-off-by: Yohei Kojima <yk@y-koj.net>
Link: https://patch.msgid.link/6d1dc775f7d5e754d734907514534054f682bac5.1781171918.git.yk@y-koj.net
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
The code has already checked there is enough room.
Use memcpy() to avoid compiler warnings from possibly unbounded strcpy().
Signed-off-by: David Laight <david.laight.linux@gmail.com>
Link: https://patch.msgid.link/20260606202633.5018-6-david.laight.linux@gmail.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
In 'kernfs_name_hash()', 'name' is NUL-terminated so it may be
directly scanned up to end without an extra call to 'strlen()'.
Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
Link: https://patch.msgid.link/20260617073941.472337-1-dmantipov@yandex.ru
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
Pull smb server fixes from Steve French:
"ksmbd server fixes, mostly addressing malformed SMB request
handling and connection/session lifetime issues, including
two information-disclosure or memory-safety bugs in the SMB2
request/response paths.
- validate FILE_ALLOCATION_INFORMATION before block rounding to
prevent a client-controlled overflow from truncating a file.
- pin connections while asynchronous oplock and lease-break
notifications are pending.
- initialize compound SMB2 READ alignment padding, preventing
disclosure of uninitialized heap bytes.
- release the allocated alternate-stream xattr name after rename.
- size multichannel binding session-key buffers for the largest
permitted key, avoiding a stack buffer overflow.
- remove a disconnecting connection's channels from every session,
including channels whose binding state has since changed.
- serialize binding preauthentication-session lookup and update
against its teardown.
- check that every compound request element contains StructureSize2
before reading it"
* tag 'v7.2-rc3-smb3-server-fixes' of git://git.samba.org/ksmbd:
ksmbd: validate compound request size before reading StructureSize2
ksmbd: lock the binding preauth session in smb3_preauth_hash_rsp
ksmbd: remove stale channels from all sessions on teardown
ksmbd: fix stack buffer overflow in multichannel session-key copy
ksmbd: fix memory leak of xattr_stream_name in smb2_rename()
ksmbd: zero the smb2_read alignment tail to avoid an infoleak
ksmbd: pin conn during async oplock break notification
ksmbd: fix integer overflow in set_file_allocation_info()
|
|
When creating a WSL special file (socket, fifo, character or block
device), __ntfs_create() sets FILE_ATTRIBUTE_RECALL_ON_OPEN in ni->flags
as valid_reparse_data() requires for these tags. This flag is
intentionally absent from $FILE_NAME, so the subsequent reload
ni->flags = fn->file_attributes;
drops it from ni->flags, the authoritative copy written back to
$STANDARD_INFORMATION. The on-disk file_attributes becomes 0x00000404
instead of 0x00040404, and after a remount valid_reparse_data() rejects
the reparse point while fsck reports "$REPARSE_POINT data is corrupted".
Preserve the RECALL_ON_OPEN bit across the reload. Symlinks do not set
that bit, so they are unaffected.
Fixes: af0db57d4293 ("ntfs: update inode operations")
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ecryptfs_exorcise_daemon() drops queued messages from a dying daemon
without holding ecryptfs_msg_ctx_lists_mux, but
ecryptfs_msg_ctx_alloc_to_free() requires that lock.
Take the list lock while moving the queued contexts back to the free
list to avoid racing with other global msg ctx list users.
Fixes: f66e883eb618 ("eCryptfs: integrate eCryptfs device handle into the module.")
Cc: <stable@vger.kernel.org>
Signed-off-by: Yichong Chen <chenyichong@uniontech.com>
Signed-off-by: Tyler Hicks <code@tyhicks.com>
|
|
ecryptfs_send_message_locked() moves a message context from the free
list to the allocated list before sending the request to the userspace
daemon.
If ecryptfs_send_miscdev() fails, the context is left on the
allocated list and cannot be reused. Move it back to the free list on
failure and clear the caller's pointer.
Fixes: f66e883eb618 ("eCryptfs: integrate eCryptfs device handle into the module.")
Cc: <stable@vger.kernel.org>
Signed-off-by: Yichong Chen <chenyichong@uniontech.com>
Signed-off-by: Tyler Hicks <code@tyhicks.com>
|
|
parse_tag_3_packet() set encrypted_key_size from the Tag 3 packet body
without bounding it against ECRYPTFS_MAX_KEY_BYTES (64). When
encrypted_key_size > 64, decrypt_passphrase_encrypted_session_key()
sets decrypted_key_size = encrypted_key_size and performs two
out-of-bounds writes:
1. crypto_skcipher_decrypt() writes encrypted_key_size bytes into
decrypted_key[64] via scatterlist, overflowing into the parent
ecryptfs_auth_tok struct.
2. memcpy(crypt_stat->key, decrypted_key, decrypted_key_size) writes
into crypt_stat->key[64], corrupting root_iv, keysig_list, and
mutexes in ecryptfs_crypt_stat.
Only AES-192 (cipher code 0x08) enables this because it sets
crypt_stat->key_size = 24 independently of encrypted_key_size,
allowing crypto_skcipher_setkey() to succeed while encrypted_key_size
exceeds ECRYPTFS_MAX_KEY_BYTES.
The PKI decryption path (parse_tag_65_packet) already validates
decrypted_key_size <= ECRYPTFS_MAX_KEY_BYTES; the passphrase path
omits this check.
Bound encrypted_key_size against ECRYPTFS_MAX_KEY_BYTES (64) rather
than ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES (512). The 64-byte limit also
protects the 512-byte encrypted_key[] buffer, so the former 512-byte
check is removed as redundant.
Fixes: 237fead61998 ("[PATCH] ecryptfs: fs/Makefile and fs/Kconfig")
Cc: <stable@vger.kernel.org>
Signed-off-by: HanQuan <eilaimemedsnaimel@gmail.com>
[tyhicks: Adjust the code comment to refer to macros representing the
buffer sizes rather than mentioning the buffer size values since they
may change in the future]
Signed-off-by: Tyler Hicks <code@tyhicks.com>
|
|
GRANTED_MSG is a server-to-client callback, so it runs on the client,
where nfsd never registers nlmsvc_ops. The nlm3svc_lookup_host()
helper is for the server-side request handlers
(TEST/LOCK/CANCEL/UNLOCK), which reach nlmsvc_ops->fopen and must
reject requests when nfsd isn't running. GRANTED_MSG only calls
nlmclnt_grant(). Instead, of calling nlm3svc_lookup_host(), which
results in a client failing a GRANTED_MSG call, call
nlmsvc_lookup_host().
Fixes: 6c534ad999b6 ("lockd: Use xdrgen XDR functions for the NLMv3 GRANTED_MSG procedure")
Cc: stable@vger.kernel.org
Signed-off-by: Olga Kornievskaia <okorniev@redhat.com>
Reviewed-by: NeilBrown <neil@brown.name>
Link: https://patch.msgid.link/20260625211852.31972-1-okorniev@redhat.com
Signed-off-by: Chuck Lever <cel@kernel.org>
|
|
A FUSE server that advertises a large max_pages and max_write (e.g.
max_pages=256, max_write=1MB) cannot currently obtain matching
FUSE_READ request sizes from the kernel. Buffered sequential writes
arrive at the server at the negotiated max_write size, but a large
buffered read() is split into several smaller FUSE_READ requests.
For a buffered read, filemap_get_pages() -> page_cache_sync_ra() sizes
the read against ractl_max_pages():
max_pages = ractl->ra->ra_pages;
if (req_size > max_pages && bdi->io_pages > max_pages)
max_pages = min(req_size, bdi->io_pages);
fuse leaves bdi->io_pages at the default VM_READAHEAD_PAGES (128KB), so
a 1MB read() (req_size = 256 pages) is clamped to the readahead window
(128KB, or 256KB for POSIX_FADV_SEQUENTIAL), producing four 256KB
FUSE_READ round-trips instead of one.
Set bdi->io_pages to fc->max_pages after feature negotiation. As the
code above shows, io_pages only raises the limit when the request size
already exceeds the readahead window, so it enlarges explicitly
requested reads without enlarging the speculative readahead window.
This avoids increasing speculative page-cache readahead on behalf of
an unprivileged server. NFS does the same, setting io_pages from
rpages while leaving ra_pages at the default.
fc->max_pages is already bounded by fc->max_pages_limit (and, for
virtio-fs, by the virtqueue descriptor count), so io_pages inherits
the same bound.
Suggested-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Jim Harris <jim.harris@nvidia.com>
Assisted-by: Cursor:claude-opus-4.8
Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
|
|
udf_symlink_filler() can enter udf_pc_to_char() with a partial pathComponent header.
Validate that enough input remains for a complete pathComponent header
before accessing it. Reject malformed symlink data that would otherwise
make udf_pc_to_char() perform an out-of-bounds read.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: David Lee <david.lee@trailofbits.com>
Assisted-by: Codex:gpt-5.5
Link: https://patch.msgid.link/20260717104722.41446-1-david.lee@trailofbits.com
Signed-off-by: Jan Kara <jack@suse.cz>
|
|
fuse_uring_create_queue() initializes a fuse_ring_queue and then
publishes the pointer into ring->queues[qid] with WRITE_ONCE() under the
fch->lock. There are several readers that may concurrently be fetching
that pointer locklessly and then deferencing it.
WRITE_ONCE() doesn't ensure ordering of the queue's field
initialization before the ring->queues[qid] pointer assignment. The
queue must be published with smp_store_release() so the field
initialization is guaranteed to happen before.
Readers in paths where the read may happen concurrently with the store
need to use READ_ONCE() because any race involving a plain access is
undefined.
Fixes: 24fe962c86f5 ("fuse: {io-uring} Handle SQEs - register commands")
Cc: stable@vger.kernel.org
Reviewed-by: Bernd Schubert <bernd@bsbernd.com>
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
|
|
fuse_chan_set_initialized() sets values for the connection state and
then sets fch->initialized to true, but lockless readers read
fch->initialized and if true, go to read the connection state values,
without using any barriers.
There are a few instances where this happens (fuse_uring_cmd() before
dispatching register / commit-and-fetch cmds, fuse_dev_do_wriite() for
handling notify retrieves, etc).
To make this as simple as possible, use release/acquire semantics for
writing/reading fch->initialized. Add the missing read barriers.
This is not marked for stable as these are not realistically reachable
on a well-behaved server, and buggy/malicious servers who trigger this
path fail benignly rather than crash or deadlock the kernel.
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
|
|
fuse_block_alloc() reads fch->initialized and then fch->io_uring.
fch->io_uring is set before fch->initialized, ordered by the smp_wmb()
in fuse_chan_set_intialized(), but fuse_block_alloc() has no matching
read barrier between the two loads.
This may lead a CPU to observe fch->initialized=1 but fch->io_uring=0,
and skip the check that blocks request allocation until the io-uring
queues are ready. This can reintroduce the lock-order inversion deadlock
that commit 3393ff964e0f prevents.
Add an smp_rmb() barrier to pair with the smp_wmb() in
fuse_chan_set_initialized() to prevent this.
Fixes: 3393ff964e0f ("fuse: block request allocation until io-uring init is complete")
Cc: stable@vger.kernel.org
Reviewed-by: Bernd Schubert <bernd@bsbernd.com>
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
|
|
Pull smb client fixes from Steve French:
- fallocate fixes
- unit test fixes
- fix allocation size after duplicate extents
- fix check for overlapping data areas
* tag 'v7.2-rc3-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6:
smb/client: flush dirty data before punching a hole
smb/client: Use EXPORT_SYMBOL_IF_KUNIT() to export symbols in SMB2
smb/client: Use EXPORT_SYMBOL_IF_KUNIT() to export symbols
smb: client: reject overlapping data areas in SMB2 responses
smb/client: refresh allocation after EOF-extending fallocate
smb/client: emulate small EOF-extending mode 0 fallocate ranges
smb/client: reduce fallocate zero buffer allocation
smb/client: handle overlapping allocated ranges in fallocate
smb/client: refresh allocation size after duplicate extents
smb: client: use kvzalloc() for megabyte buffer in simple fallocate
|
|
Pull xfs fixes from Carlos Maiolino:
"This contains mostly a series of bug fixes found by different LLM
models"
* tag 'xfs-fixes-7.2-rc4' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux: (21 commits)
xfs: don't zap bmbt forks if they are MAXLEVELS tall
xfs: clamp timestamp nanoseconds correctly
xfs: fully check the parent handle when it points to the rootdir
xfs: handle non-inode owners for rtrmap record checking
xfs: fix off-by-one error when calling xchk_xref_has_rt_owner
xfs: set xfarray killable sort correctly
xfs: grab rtrmap btree when checking rgsuper
xfs: write the rg superblock when fixing it
xfs: use the rt version of the cow staging checker
xfs: use rtrefcount btree cursor in xchk_xref_is_rt_cow_staging
xfs: don't wrap around quota ids in dqiterate
xfs: move cow_replace_mapping to xfs_bmap_util.c
xfs: make cow repair somewhat flaky when debugging knob enabled
xfs: don't replace the wrong part of the cow fork
xfs: resample the data fork mapping after cycling ILOCK
xfs: fix null pointer dereference in tracepoint
xfs: use xfs_csn_t for xlog_cil_push_now() push_seq parameter
xfs: tie zoned sysfs lifetime to zone info
xfs: fail recovery on a committed log item with no regions
xfs: splice unsorted log items back to the transaction after the loop
...
|
|
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs
Pull erofs fixes from Gao Xiang:
- Fix sanity checks for ztailpacking tail pclusters to avoid
false corruption reports
- Use more informative s_id for file-backed mounts
- Hide the meaningless "cache_strategy=" mount option on plain
(uncompressed) filesystems
- Remove the unneeded erofs_is_ishare_inode() helper
* tag 'erofs-for-7.2-rc4-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs:
erofs: hide "cache_strategy=" for plain filesystems
erofs: get rid of erofs_is_ishare_inode() helper
erofs: relax sanity check for tail pclusters due to ztailpacking
erofs: use more informative s_id for file-backed mounts
|
|
When ksmbd validates a compound (chained) SMB2 request,
ksmbd_smb2_check_message() reads pdu->StructureSize2 without first
checking that the compound element is large enough to contain it.
StructureSize2 is a 2-byte field at offset 64
(__SMB2_HEADER_STRUCTURE_SIZE) from the start of each element.
The compound-walking logic only guarantees that a full 64-byte SMB2
header is present for the trailing element: when NextCommand is 0, len is
reduced to the number of bytes remaining after next_smb2_rcv_hdr_off. A
remote client can craft a compound request whose last element has exactly
64 bytes, so the 2-byte StructureSize2 read at offset 64 extends one byte
past the receive buffer, producing a slab-out-of-bounds read.
BUG: KASAN: slab-out-of-bounds in ksmbd_smb2_check_message (fs/smb/server/smb2misc.c:402)
Read of size 2 at addr ffff888012ae31ac by task kworker/0:1/14
The buggy address is located 172 bytes inside of allocated 173-byte region
Workqueue: ksmbd-io handle_ksmbd_work
Call Trace:
...
kasan_report (mm/kasan/report.c:595)
ksmbd_smb2_check_message (fs/smb/server/smb2misc.c:402)
handle_ksmbd_work (fs/smb/server/server.c:119)
process_one_work (kernel/workqueue.c:3314)
worker_thread (kernel/workqueue.c:3397)
kthread (kernel/kthread.c:436)
ret_from_fork (arch/x86/kernel/process.c:158)
ret_from_fork_asm (arch/x86/entry/entry_64.S:245)
Reject any compound element that is too small to hold StructureSize2
before dereferencing it.
Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
Reported-by: AutonomousCodeSecurity@microsoft.com
Signed-off-by: Xiang Mei (Microsoft) <xmei5@asu.edu>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
smb3_preauth_hash_rsp() computes the SMB3.1.1 preauth integrity hash on
the response path. For a binding SESSION_SETUP it looks up the
per-connection preauth_session and reads its Preauth_HashValue.
smb2_sess_setup() frees that preauth_session under ksmbd_conn_lock().
Two SMB2 requests on one connection can run concurrently, so an unlocked
lookup and hash can use a preauth_session after another worker frees it.
Take ksmbd_conn_lock() before selecting conn->binding and hold it across
the selected preauth hash lookup and update. This preserves the existing
hash selection while preventing the lookup-to-use lifetime race.
Fixes: 1c5daa2ea924 ("ksmbd: handle channel binding with a different user")
Signed-off-by: Gil Portnoy <dddhkts1@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
ksmbd_sessions_deregister() removes a connection's channels from other
sessions' channel lists only while conn->binding is still set:
if (conn->binding) {
hash_for_each_safe(sessions_table, ...)
ksmbd_chann_del(conn, sess);
}
conn->binding is a transient flag: it is cleared once a binding
SESSION_SETUP completes, and also by a subsequent non-binding
SESSION_SETUP on the same connection (a reauthentication on a bound
channel, or a new SessionId==0 setup). A connection that has bound a
channel into another session's ksmbd_chann_list and then clears
conn->binding leaves that channel behind when it disconnects: the
channel, whose chann->conn points at the now freed struct ksmbd_conn,
stays on the owner session's list.
When the owning connection later tears down, the second loop
dereferences the stale channel:
xa_for_each(&sess->ksmbd_chann_list, chann_id, chann)
if (chann->conn != conn)
ksmbd_conn_set_exiting(chann->conn); /* freed */
which is a use-after-free write into the freed ksmbd_conn (the same
stale channel is also walked by show_proc_session() through /proc). The
session is leaked as well, because its channel list never empties.
Remove the conn->binding gate so a connection always removes its
channels from every session on teardown.
Fixes: faf8578c77f3 ("ksmbd: find bound sessions during reauthentication")
Signed-off-by: Gil Portnoy <dddhkts1@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
Commit 4b706360ffb7 ("ksmbd: fix multichannel binding and enforce channel
limit") moved the binding-path session key out of the session-wide
sess->sess_key (CIFS_KEY_SIZE = 40) into a new per-channel buffer, and
sized both that buffer and the on-stack copy used during binding with
SMB2_NTLMV2_SESSKEY_SIZE (16):
struct channel {
char sess_key[SMB2_NTLMV2_SESSKEY_SIZE]; /* 16 */
...
};
ntlm_authenticate() / krb5_authenticate():
char channel_key[SMB2_NTLMV2_SESSKEY_SIZE] = {}; /* 16 */
char *auth_key = conn->binding ? channel_key : sess->sess_key;
The two writers that fill this destination still bound the copy length
against CIFS_KEY_SIZE (40), not against the 16-byte buffer:
ksmbd_decode_ntlmssp_auth_blob() (NTLM key exchange):
if (sess_key_len > CIFS_KEY_SIZE) /* 40 */
return -EINVAL;
arc4_crypt(ctx_arc4, sess_key,
(char *)authblob + sess_key_off, sess_key_len);
ksmbd_krb5_authenticate():
if (resp->session_key_len > sizeof(sess->sess_key)) /* 40 */
...
memcpy(sess_key, resp->payload, resp->session_key_len);
On a binding SESSION_SETUP, auth_key points at the 16-byte channel_key,
so a client that supplies an NTLM EncryptedRandomSessionKey of up to 40
bytes (with NTLMSSP_NEGOTIATE_KEY_EXCH), or a Kerberos ticket whose
session key is longer than 16 bytes (a normal AES256 key is 32), writes
past the 16-byte stack buffer -- up to a 24-byte kernel stack overflow.
KASAN reports it as a stack-out-of-bounds write in arc4_crypt() called
from ksmbd_decode_ntlmssp_auth_blob().
The destinations must be able to hold the full session key the length
checks already permit. Size the per-channel key buffer and the two
on-stack channel_key buffers with CIFS_KEY_SIZE, matching sess->sess_key.
Fixes: 4b706360ffb7 ("ksmbd: fix multichannel binding and enforce channel limit")
Signed-off-by: Gil Portnoy <dddhkts1@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
On an SMB2 SET_INFO(FileRenameInformation) whose target names an alternate
data stream, smb2_rename() obtains a formatted stream-name string from
ksmbd_vfs_xattr_stream_name(), which allocates it with kasprintf() and
returns it through an out-param:
rc = ksmbd_vfs_xattr_stream_name(stream_name, &xattr_stream_name, ...);
if (rc)
goto out;
rc = ksmbd_vfs_setxattr(..., xattr_stream_name, ...);
if (rc < 0) {
...
goto out;
}
goto out;
xattr_stream_name is declared inside the alternate-data-stream block, but
the out: label is outside that block and frees only new_name, so it cannot
release xattr_stream_name. ksmbd_vfs_setxattr() takes a const char * and
only reads the name, so it does not take ownership either. Both the
setxattr-failure and the success path therefore leak the kasprintf()'d
string. An authenticated client with a writable share can leak kernel
memory on every stream rename, exhausting kernel memory over time.
Free xattr_stream_name after its use, before the block's goto out. The
two earlier goto out paths never assign the variable, so there is no
double-free.
Signed-off-by: Gil Portnoy <dddhkts1@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
Commit 6b9a2e09d4cc ("ksmbd: avoid zeroing the read buffer in smb2_read()")
switched the SMB2 READ payload buffer from kvzalloc() to kvmalloc(), on the
premise that only the nbytes actually read are ever transmitted, so the
ALIGN(length, 8) tail need not be initialized.
That premise does not hold for a compound response. ksmbd_vfs_read() fills
only nbytes, leaving [nbytes, ALIGN(length, 8)) uninitialized. The aux
payload is pinned as the last response iov with iov_len == nbytes, but when
the READ is a member of a compound, init_chained_smb2_rsp() 8-byte-aligns
the previous member by extending that same iov:
new_len = ALIGN(len, 8);
work->iov[work->iov_idx].iov_len += (new_len - len);
inc_rfc1001_len(work->response_buf, new_len - len);
so up to 7 uninitialized bytes of the kvmalloc()'d slab tail are sent
to the client. When the read length is small the buffer is served from
a general kmalloc slab, so those bytes can be stale kernel-heap
contents, including pointer values -- an information leak usable to
defeat KASLR.
An authenticated client triggers it with a compound request containing a
READ whose returned nbytes is not 8-aligned (for example [READ, CLOSE] with
a 1-byte read).
Zero only the alignment tail after the read, preserving the bulk
no-zeroing optimization of 6b9a2e09d4cc.
Fixes: 6b9a2e09d4cc ("ksmbd: avoid zeroing the read buffer in smb2_read()")
Cc: stable@vger.kernel.org
Signed-off-by: Gil Portnoy <dddhkts1@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
smb2_oplock_break_noti() and smb2_lease_break_noti() store a ksmbd_conn
pointer in an async ksmbd_work and then queue that work on ksmbd-io. The
work only increments conn->r_count, which prevents teardown from passing
the pending-request wait after the increment, but it does not pin the
struct ksmbd_conn object.
If connection teardown races with an oplock break notification, the last
conn reference can be dropped before the queued worker finishes. The
worker then uses the freed conn in ksmbd_conn_write() and
ksmbd_conn_r_count_dec().
Take a real conn reference when publishing the conn pointer to the async
work item, and drop it after the notification work has decremented
r_count. Apply the same lifetime rule to lease break notification, which
uses the same work->conn pattern.
Fixes: 3aa660c05924 ("ksmbd: prevent connection release during oplock break notification")
Signed-off-by: Qihang <q.h.hack.winter@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
set_file_allocation_info() converts the client-supplied
FILE_ALLOCATION_INFORMATION::AllocationSize into a 512-byte block
count with:
alloc_blks = (le64_to_cpu(file_alloc_info->AllocationSize) + 511) >> 9;
AllocationSize is a fully client-controlled __le64 field; the only
validation performed by the caller (smb2_set_info_file(), case
FILE_ALLOCATION_INFORMATION) is that the fixed buffer is at least
sizeof(struct smb2_file_alloc_info) == 8 bytes. The value itself is
never range-checked before this arithmetic.
When AllocationSize is close to U64_MAX (e.g. 0xffffffffffffffff),
"AllocationSize + 511" wraps around mod 2^64 to a small number
(0xffffffffffffffff + 511 = 510), so alloc_blks becomes 0. Since any
existing regular file has stat.blocks > 0, the function then takes
the "shrink" branch and calls:
ksmbd_vfs_truncate(work, fp, alloc_blks * 512); /* == 0 */
silently truncating the file to size 0, even though the client asked
to grow the allocation to (what looks like) the maximum possible
size. The trailing "if (size < alloc_blks * 512) i_size_write(inode,
size);" restore is guarded by a comparison that is never true once
alloc_blks == 0, so the truncation is not undone. This lets an
authenticated SMB client that already holds an open handle with
FILE_WRITE_DATA on a file silently truncate that same file to size 0
via a single crafted SET_INFO(FILE_ALLOCATION_INFORMATION) request
advertising a near-U64_MAX AllocationSize, even though the request
asks to grow the file's allocation rather than shrink it. This is a
functional/data-loss bug, not a privilege-boundary
violation: the same client could already truncate the file via
FILE_END_OF_FILE_INFORMATION or a plain write.
Fix it by validating AllocationSize against MAX_LFS_FILESIZE, the
same upper bound the VFS itself uses to reject unrepresentable file
sizes, before doing the "+511" rounding, and rejecting oversized
values with -EINVAL. Bounding AllocationSize to
MAX_LFS_FILESIZE - 511 guarantees the "+511" addition cannot wrap,
and that the subsequent "alloc_blks * 512" values passed to
vfs_fallocate() and ksmbd_vfs_truncate() stay within a representable
loff_t as well.
No legitimate SMB client asks for an allocation size anywhere near
2^64 bytes, so this only rejects a value that was previously
silently misinterpreted as zero.
Runtime-verified on a v6.19 KASAN test stand: sending SET_INFO
(FILE_ALLOCATION_INFORMATION) with AllocationSize = 0xffffffffffffffff
against ksmbd now returns -EINVAL and leaves the target file's size
unchanged, where the unpatched kernel truncated it from 4096 to 0
bytes.
Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
Cc: stable@vger.kernel.org
Signed-off-by: Ibrahim Hashimov <security@auditcode.ai>
Assisted-by: AuditCode-AI:2026.07
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
Punching a hole after a large buffered write may leave the range
reported as data. Reproduce it with:
xfs_io -f \
-c "pwrite -b 3m -S 0x61 0 3m" \
-c "fpunch 1m 1m" \
-c "seek -h 0" \
-c "seek -d 1m" \
/mnt/test/repro
Punching 1 MiB at offset 1 MiB should produce:
0 1 MiB 2 MiB 3 MiB
| DATA | HOLE | DATA | EOF
Instead, the entire file is reported as data. SEEK_HOLE(0) returns EOF,
and SEEK_DATA(1M) returns 1M.
This happens because a dirty folio spanning the punched range can be
written back after the punch and refill the hole.
Fix this by flushing and waiting for dirty data in the punched range
before invalidating the page cache and issuing FSCTL_SET_ZERO_DATA.
The xfstests generic/539 pass against Samba/ksmbd with this change.
Signed-off-by: Huiwen He <hehuiwen@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
Replace EXPORT_SYMBOL_FOR_MODULES() with EXPORT_SYMBOL_IF_KUNIT()
to mark the symbols as visible only if CONFIG_KUNIT is enabled.
Kunit test should import the namespace EXPORTED_FOR_KUNIT_TESTING to
use these marked symbols. This is the standard way for all KUnit
tests.
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
Replace EXPORT_SYMBOL_FOR_MODULES() with EXPORT_SYMBOL_IF_KUNIT()
to mark the symbols as visible only if CONFIG_KUNIT is enabled.
Kunit test should import the namespace EXPORTED_FOR_KUNIT_TESTING to
use these marked symbols. This is the standard way for all KUnit
tests.
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
The comment in dax_folio_reset_order() claims that DAX maintains an
invariant where folio->share != 0 only when folio->mapping == NULL,
implying folio->share is zero whenever mapping is non-NULL. This is
misleading because folio->share and folio->index are a union -- for
non-shared folios with mapping != NULL, reading folio->share returns
the file page offset (folio->index), which is typically non-zero.
Reword the comment to accurately describe the union aliasing: the
assignment clears whichever interpretation of the union word is active
(index for non-shared folios, share for shared folios), which is correct
because the folio is being released in either case.
No functional change -- the code was already correct, only the
justification was wrong.
Fixes: 59eb73b98ae0b ("dax: Factor out dax_folio_reset_order() helper")
Reviewed-by: Jonathan Cameron <jic23@kernel.org>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Signed-off-by: John Groves <john@groves.net>
Link: https://patch.msgid.link/0100019ecc08b8cd-4ee80eeb-1341-4f67-8478-7298129440e9-000000@email.amazonses.com
Signed-off-by: Alison Schofield <alison.schofield@intel.com>
|
|
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>
|
|
The xfstests' test-case generic/564 fails for
the case of HFS+ file system. Test-case expects that
file system driver reports -EFBIG error code in the case
if there is the effort to write beyond 8TiB. However, HFS+
file system driver returns -ENOSPC instead.
The root cause is that hfsplus_fill_super() sets s_maxbytes
as MAX_LFS_FILESIZE. VFS therefore considers the write
position valid and calls into the filesystem. Because HFS+
does not support holes, cont_write_begin() zero-fills
the entire intermediate range from the current end-of-file
to the target offset. On a small test volume this exhausts
free space long before any block-number overflow is detected,
producing -ENOSPC instead of -EFBIG.
This patch fixes the issue by adding a bounds check at
the top of hfsplus_write_begin(). If the requested write
position is at or beyond the actual capacity of the volume
in bytes, return -EFBIG immediately before cont_write_begin()
is entered and before any zero-fill I/O is attempted.
sudo ./check generic/564
FSTYP -- hfsplus
PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.2.0-rc1-dirty #50 SMP PREEMPT_DYNAMIC Fri Jul 3 16:22:27 PDT 2026
MKFS_OPTIONS -- /dev/loop51
MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch
generic/564 13s ... 43s
Ran: generic/564
Passed all 1 tests
cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
cc: Yangtao Li <frank.li@vivo.com>
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
Link: https://lore.kernel.org/r/20260706221738.140271-2-slava@dubeyko.com
Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
|
|
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>
|