7.1.6-rc1 review
Subsystems (4)
Greg Kroah-Hartman
maintainerPATCH 640/744 ASoC: fsl_sai: Fix spurious BCLK on resume by clearing BYP
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chancel Liu <[email protected]>
commit d091132889c1378dd0944a72f86eae3e4da1e4fa upstream.
When the BCLK divider ratio is 1:1, fsl_sai_set_bclk() enables bypass mode by setting BYP, but never clears the bit. The BYP=1 value remains in the regcache, and is restored by regcache_sync() on the next runtime resume.
Since BYP=1 combined with BCD=1 immediately outputs the ungated MCLK as BCLK without waiting for BCE/TE/RE to be enabled, the clock is driven prematurely before the stream is fully configured, causing noise on some codecs.
Fix this by clearing BYP and BCI in fsl_sai_hw_free() taking into account sync mode and the opposite stream's state, so that the regcache holds BYP=0 before runtime suspend and regcache_sync() on resume will not restore bypass mode prematurely.
--- sound/soc/fsl/fsl_sai.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-)
sound/soc/fsl/fsl_sai.c +25 -4
@@ -804,6 +804,8 @@ static int fsl_sai_hw_free(struct snd_pcstruct fsl_sai *sai =snd_soc_dai_get_drvdata (cpu_dai);bool tx = substream->stream ==SNDRV_PCM_STREAM_PLAYBACK ;unsigned int ofs = sai->soc_data->reg_offset; +int adir = tx ?RX :TX ; +int dir = tx ?TX :RX ;/* Clear xMR to avoid channel swap with mclk_with_tere enabled case */ regmap_write (sai->regmap,FSL_SAI_xMR (tx),0 );
@@ -811,10 +813,29 @@ static int fsl_sai_hw_free(struct snd_pcregmap_update_bits (sai->regmap,FSL_SAI_xCR3 (tx, ofs),FSL_SAI_CR3_TRCE_MASK ,0 ); -if (!sai->is_consumer_mode[tx] && - sai->mclk_streams &BIT (substream->stream)) { -clk_disable_unprepare (sai->mclk_clk[sai->mclk_id[tx]]); - sai->mclk_streams &= ~BIT (substream->stream); +if (!sai->is_consumer_mode[tx]) { +bool adir_active = !!(sai->mclk_streams &BIT (!substream->stream)); +/* +* If opposite stream provides clocks for synchronous mode and +* it is inactive, Clear BYP and BCI +*/ +if (fsl_sai_dir_is_synced (sai, adir) && !adir_active) +regmap_update_bits (sai->regmap,FSL_SAI_xCR2 (!tx, ofs), +FSL_SAI_CR2_BCI |FSL_SAI_CR2_BYP ,0 ); +/* +* Clear BYP and BCI of current stream if either of: +* 1. current stream doesn't provide clocks for synchronous mode +* 2. current stream provides clocks for synchronous mode but no +* more stream is active. +*/ +if (!fsl_sai_dir_is_synced (sai, dir) || !adir_active) +regmap_update_bits (sai->regmap,FSL_SAI_xCR2 (tx, ofs), +FSL_SAI_CR2_BCI |FSL_SAI_CR2_BYP ,0 ); + +if (sai->mclk_streams &BIT (substream->stream)) { +clk_disable_unprepare (sai->mclk_clk[sai->mclk_id[tx]]); + sai->mclk_streams &= ~BIT (substream->stream); + } }return 0 ;
Greg Kroah-Hartman
maintainerPATCH 641/744 binfmt_elf_fdpic: only honour the first PT_INTERP
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit 3349ef6a366a61d631f6a263d12cea240957719d upstream.
The program header scan handles PT_INTERP from a switch nested in the scan loop, so its break leaves the switch and not the loop. A binary carrying more than one PT_INTERP runs the case again and overwrites both interpreter_name and interpreter. The previous name allocation leaks and so does the previous interpreter reference, along with the write denial open_exec() took on it. The denial is never released, so the file stays unwritable for as long as the system runs.
An unprivileged caller reaches this with a crafted binary and repeats it at will. binfmt_elf stops at the first PT_INTERP. Do the same here.
The flaw dates back to the driver's introduction in the pre-git history tree introduced in v2.6.11 by 91808d6ebe39 ("[PATCH] FRV: Add FDPIC ELF binary format driver").
--- fs/binfmt_elf_fdpic.c | 4 ++++ 1 file changed, 4 insertions(+)
fs/binfmt_elf_fdpic.c +4 -0
@@ -231,6 +231,10 @@ static int load_elf_fdpic_binary(structfor (i =0 ; i < exec_params.hdr.e_phnum; i++, phdr++) {switch (phdr->p_type) {case PT_INTERP : +/* elf ABI allows only one interpreter */ +if (interpreter_name) +continue ; + retval = -ENOMEM ;if (phdr->p_filesz >PATH_MAX ) goto error;
Greg Kroah-Hartman
maintainerPATCH 642/744 fs/super: fix emergency thaw double-unlock of s_umount
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chen Changcheng <[email protected]>
commit 503d67fbaec6fdeaba391cb497675071db9d16ea upstream.
do_thaw_all() iterates over all superblocks via __iterate_supers() with SUPER_ITER_EXCL, which acquires s_umount exclusively before calling the callback and releases it afterwards. However, the callback do_thaw_all_callback() calls thaw_super_locked() which unconditionally releases s_umount on every code path. This results in a second unlock attempt in __iterate_supers() that corrupts the rwsem state, triggering a DEBUG_RWSEMS warning:
[ 182.601148] sysrq: Emergency Thaw of all frozen filesystems [ 182.601865] ------------[ cut here ]------------ [ 182.602375] DEBUG_RWSEMS_WARN_ON((rwsem_owner(sem) != current) && !rwsem_test_oflags(sem, RWSEM_NONSPINNABLE)): count = 0x0, magic = 0xffff99b1011e5870, owner = 0x0, curr 0xffff99b101b06c80, list not empty [ 182.603817] WARNING: kernel/locking/rwsem.c:1412 at up_write+0xa3/0x170, CPU#2: kworker/2:1/53 [ 182.604578] Modules linked in: [ 182.604864] CPU: 2 UID: 0 PID: 53 Comm: kworker/2:1 Not tainted 7.2.0-rc4-00001-gbd3bd93ea98a-dirty #4 PREEMPT(lazy) [ 182.605711] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1kylin1 04/01/2014 [ 182.606417] Workqueue: events do_thaw_all [ 182.606750] RIP: 0010:up_write+0xaf/0x170 [ 182.607076] Code: 19 3a 92 48 0f 44 c2 48 8b 55 08 48 8b 55 00 4c 8b 45 08 48 8b 55 00 48 8d 3d ad 91 e0 01 48 8b 4d 20 50 48 c7 c6 f0 8c 26 92 <67> 48 0f b9 3a e8 d7 93 4e 00 58 eb 81 48 83 7f 18 00 48 c7 c2 8d [ 182.608563] RSP: 0018:ffffb670001d7e08 EFLAGS: 00010246 [ 182.609007] RAX: ffffffff92349e8d RBX: 0000000000000000 RCX: ffff99b1011e5870 [ 182.609595] RDX: 0000000000000000 RSI: ffffffff92268cf0 RDI: ffffffff92914d10 [ 182.610283] RBP: ffff99b1011e5870 R08: 0000000000000000 R09: ffff99b101b06c80 [ 182.610847] R10: ffff99b10139a808 R11: fefefefefefefeff R12: 0000000000000000 [ 182.611414] R13: ffffffff90cf74d0 R14: 0000000000000000 R15: ffff99b1011e5800 [ 182.612009] FS: 0000000000000000(0000) GS:ffff99b1eaaee000(0000) knlGS:0000000000000000 [ 182.612670] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 182.613146] CR2: 00000000005c631c CR3: 00000000013ee000 CR4: 00000000000006f0 [ 182.613722] Call Trace: [ 182.613946] <TASK> [ 182.614130] __iterate_supers+0x128/0x150 [ 182.614463] do_thaw_all+0x1b/0x30 [ 182.614759] process_scheduled_works+0xbb/0x3f0 [ 182.615150] ? __pfx_worker_thread+0x10/0x10 [ 182.615499] worker_thread+0x129/0x270 [ 182.615816] ? __pfx_worker_thread+0x10/0x10 [ 182.616201] kthread+0xe2/0x120 [ 182.616469] ? __pfx_kthread+0x10/0x10 [ 182.616792] ret_from_fork+0x15b/0x240 [ 182.617115] ? __pfx_kthread+0x10/0x10 [ 182.617426] ret_from_fork_asm+0x1a/0x30 [ 182.617761] </TASK> [ 182.617968] ---[ end trace 0000000000000000 ]--- [ 182.618412] Emergency Thaw complete
Fix this by switching to SUPER_ITER_UNLOCKED and acquiring s_umount in the callback via super_lock_excl() before calling thaw_super_locked(). This matches the locking pattern expected by thaw_super_locked() and eliminates the double unlock.
While at it, remove the dead 'return;' at the end of do_thaw_all_callback().
--- fs/super.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
fs/super.c +5 -2
@@ -1145,16 +1145,19 @@ void emergency_remount(void)static void do_thaw_all_callback (struct super_block *sb,void *unused) { +if (!super_lock_excl (sb)) +return ; +if (IS_ENABLED (CONFIG_BLOCK ))while (sb->s_bdev && !bdev_thaw (sb->s_bdev))pr_warn ("Emergency Thaw on %pg\n" , sb->s_bdev); +thaw_super_locked (sb,FREEZE_HOLDER_USERSPACE ,NULL ); -return ; }static void do_thaw_all (struct work_struct *work) { -__iterate_supers (do_thaw_all_callback,NULL ,SUPER_ITER_EXCL ); +__iterate_supers (do_thaw_all_callback,NULL ,SUPER_ITER_UNLOCKED );kfree (work);printk (KERN_WARNING "Emergency Thaw complete\n" ); }
Greg Kroah-Hartman
maintainerPATCH 643/744 fs: preserve ACL_DONT_CACHE state in forget_cached_acl()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
commit 4b9a5458d02e214ef2b384124ca626e3e381d778 upstream.
The ACL_DONT_CACHE state is meant to be a constant state for the inode for filesystems that want to opt out of posix acl caching.
Commit facd61053cff1 ("fuse: fixes after adapting to new posix acl api") used this facility to opt out of posix acl caching for fuse inodes with fuse server that does not negotiate FUSE_POSIX_ACL (fc->posix_acl).
The commit also takes care to gate the forget_all_cached_acls() call in fuse_set_acl() on fc->posix_acl because there is no need for it, but there are other placed in fuse code which call forget_all_cached_acls() unconditional to fc->posix_acl and those cause the loss of the ACL_DONT_CACHE state.
This is not only a functional bug. Properly timed, a get_acl() from this fuse filesystem can return a stale cached value, as was observed in tests, because set_acl() does not invalidate the unintentional acl cache.
We could fix this in fuse, but it actually makes no sense for the vfs helper forget_cached_acl() to invalidate the ACL_DONT_CACHE state, so let it not do that to fix fuse and future users of ACL_DONT_CACHE.
--- fs/posix_acl.c | 7 +++++++ 1 file changed, 7 insertions(+)
fs/posix_acl.c +7 -0
@@ -93,6 +93,13 @@ static void __forget_cached_acl(struct p {struct posix_acl *old; +/* +* ACL_DONT_CACHE is expected to be a "const" value and xchg it with +* ACL_NOT_CACHED would enable acl caching for the inode - +* clearly not what the caller has intended. +*/ +if (READ_ONCE (*p) ==ACL_DONT_CACHE ) +return ; old =xchg (p,ACL_NOT_CACHED );if (!is_uncached_acl (old))posix_acl_release (old);
Greg Kroah-Hartman
maintainerPATCH 644/744 fscrypt: Add missing superblock check in find_or_insert_direct_key()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit b5fa40226e71c17847b9ff2816c6ca4133d0d994 upstream.
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.
--- fs/crypto/keysetup_v1.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
fs/crypto/keysetup_v1.c +7 -1
@@ -147,13 +147,19 @@ find_or_insert_direct_key(struct fscryptif (memcmp (ci->ci_policy.v1.master_key_descriptor, dk->dk_descriptor,FSCRYPT_KEY_DESCRIPTOR_SIZE ) !=0 )continue ; +/* The sb is used at eviction time, so it must be the same. */ +if (ci->ci_inode->i_sb != dk->dk_sb) +continue ;if (ci->ci_mode != dk->dk_mode)continue ;if (!fscrypt_is_key_prepared (&dk->dk_key, ci))continue ;if (crypto_memneq (raw_key, dk->dk_raw, ci->ci_mode->keysize))continue ; -/* using existing tfm with same (descriptor, mode, raw_key) */ +/* +* Use an existing prepared key with the same (descriptor, sb, +* mode, inlinecrypt, raw_key) combination. +*/ refcount_inc (&dk->dk_refcount);spin_unlock (&fscrypt_direct_keys_lock);free_direct_key (to_insert);
Greg Kroah-Hartman
maintainerPATCH 645/744 fscrypt: Avoid dynamic allocation in fscrypt_get_devices()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Biggers <[email protected]>
commit 6fe4e4b8259e1330945b5f3c9476e08473b8e0e8 upstream.
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.)
--- fs/crypto/inline_crypt.c | 57 ++++++++++++++++------------------------------- fs/f2fs/super.c | 25 +++++++++++--------- include/linux/fscrypt.h | 20 +++++++++------- 3 files changed, 45 insertions(+), 57 deletions(-)
fs/crypto/inline_crypt.c +20 -37
@@ -22,22 +22,14 @@#include "fscrypt_private.h" -static struct block_device **fscrypt_get_devices (struct super_block *sb, -unsigned int *num_devs) +static unsigned int +fscrypt_get_devices (struct super_block *sb, +struct block_device *devs[FSCRYPT_MAX_DEVICES ]) { -struct block_device **devs; - -if (sb->s_cop->get_devices) { - devs = sb->s_cop->get_devices (sb, num_devs); -if (devs) -return devs; - } - devs =kmalloc_obj (*devs); -if (!devs) -return ERR_PTR (-ENOMEM ); +if (sb->s_cop->get_devices) +return sb->s_cop->get_devices (sb, devs); devs[0 ] = sb->s_bdev; - *num_devs =1 ; -return devs; +return 1 ; }static unsigned int fscrypt_get_dun_bytes (const struct fscrypt_inode_info *ci)
@@ -96,7 +88,7 @@ int fscrypt_select_encryption_impl(strucconst struct inode *inode = ci->ci_inode;struct super_block *sb = inode->i_sb;struct blk_crypto_config crypto_cfg; -struct block_device **devs; +struct block_device *devs[FSCRYPT_MAX_DEVICES ];unsigned int num_devs;unsigned int i;
@@ -135,20 +127,15 @@ int fscrypt_select_encryption_impl(struc crypto_cfg.key_type = is_hw_wrapped_key ?BLK_CRYPTO_KEY_TYPE_HW_WRAPPED :BLK_CRYPTO_KEY_TYPE_RAW ; - devs =fscrypt_get_devices (sb, &num_devs); -if (IS_ERR (devs)) -return PTR_ERR (devs); - + num_devs =fscrypt_get_devices (sb, devs);for (i =0 ; i < num_devs; i++) {if (!blk_crypto_config_supported (devs[i], &crypto_cfg)) - goto out_free_devs; +return 0 ; }fscrypt_log_blk_crypto_impl (ci->ci_mode, devs, num_devs, &crypto_cfg); ci->ci_inlinecrypt = true; -out_free_devs: -kfree (devs);return 0 ; }
@@ -164,7 +151,7 @@ int fscrypt_prepare_inline_crypt_key(strenum blk_crypto_key_type key_type = is_hw_wrapped ?BLK_CRYPTO_KEY_TYPE_HW_WRAPPED :BLK_CRYPTO_KEY_TYPE_RAW ;struct blk_crypto_key *blk_key; -struct block_device **devs; +struct block_device *devs[FSCRYPT_MAX_DEVICES ];unsigned int num_devs;unsigned int i;int err;
@@ -182,17 +169,12 @@ int fscrypt_prepare_inline_crypt_key(str }/* Start using blk-crypto on all the filesystem's block devices. */ - devs =fscrypt_get_devices (sb, &num_devs); -if (IS_ERR (devs)) { - err =PTR_ERR (devs); - goto fail; - } + num_devs =fscrypt_get_devices (sb, devs);for (i =0 ; i < num_devs; i++) { err =blk_crypto_start_using_key (devs[i], blk_key);if (err)break ; } -kfree (devs);if (err) {fscrypt_err (inode,"error %d starting to use blk-crypto" , err); goto fail;
@@ -210,20 +192,21 @@ void fscrypt_destroy_inline_crypt_key(st struct fscrypt_prepared_key *prep_key) {struct blk_crypto_key *blk_key = prep_key->blk_key; -struct block_device **devs; +struct block_device *devs[FSCRYPT_MAX_DEVICES ];unsigned int num_devs;unsigned int i;if (!blk_key)return ; -/* Evict the key from all the filesystem's block devices. */ - devs =fscrypt_get_devices (sb, &num_devs); -if (!IS_ERR (devs)) { -for (i =0 ; i < num_devs; i++) -blk_crypto_evict_key (devs[i], blk_key); -kfree (devs); - } +/* +* Evict the key from all the filesystem's block devices. +* This *must* be done before the key is freed. +*/ + num_devs =fscrypt_get_devices (sb, devs); +for (i =0 ; i < num_devs; i++) +blk_crypto_evict_key (devs[i], blk_key); +kfree_sensitive (blk_key); }
fs/f2fs/super.c +14 -11
@@ -3731,24 +3731,27 @@ static bool f2fs_has_stable_inodes(strucreturn true; } -static struct block_device **f2fs_get_devices (struct super_block *sb, -unsigned int *num_devs) +static unsigned int +f2fs_get_devices (struct super_block *sb, +struct block_device *devs[FSCRYPT_MAX_DEVICES ]) {struct f2fs_sb_info *sbi =F2FS_SB (sb); -struct block_device **devs; +int ndevs;int i; -if (!f2fs_is_multi_device (sbi)) -return NULL ; +static_assert (MAX_DEVICES <=FSCRYPT_MAX_DEVICES ); - devs =kmalloc_objs (*devs, sbi->s_ndevs); -if (!devs) -return ERR_PTR (-ENOMEM ); +if (!f2fs_is_multi_device (sbi)) { + devs[0 ] = sb->s_bdev; +return 1 ; + } + ndevs = sbi->s_ndevs; +if (WARN_ON_ONCE (ndevs >FSCRYPT_MAX_DEVICES )) + ndevs =FSCRYPT_MAX_DEVICES ; -for (i =0 ; i < sbi->s_ndevs; i++) +for (i =0 ; i < ndevs; i++) devs[i] =FDEV (i).bdev; - *num_devs = sbi->s_ndevs; -return devs; +return ndevs; }static const struct fscrypt_operations f2fs_cryptops = {
include/linux/fscrypt.h +11 -9
@@ -57,6 +57,9 @@ struct fscrypt_name {/* Maximum value for the third parameter of fscrypt_operations.set_context(). */ #define FSCRYPT_SET_CONTEXT_MAX_SIZE 40 +/* Maximum supported number of block devices per filesystem */ +#define FSCRYPT_MAX_DEVICES 8 +#ifdef CONFIG_FS_ENCRYPTION /* Crypto operations for filesystems */
@@ -181,21 +184,20 @@ struct fscrypt_operations {bool (*has_stable_inodes)(struct super_block *sb);/* -* Return an array of pointers to the block devices to which the -* filesystem may write encrypted file contents, NULL if the filesystem -* only has a single such block device, or an ERR_PTR() on error. -* -* On successful non-NULL return, *num_devs is set to the number of -* devices in the returned array. The caller must free the returned -* array using kfree(). +* Retrieve the list of block devices to which the filesystem may write +* encrypted file contents. +* +* This writes the block_device pointers to @devs and returns the count +* (between 1 and FSCRYPT_MAX_DEVICES inclusively). * * If the filesystem can use multiple block devices (other than block * devices that aren't used for encrypted file contents, such as * external journal devices), and wants to support inline encryption, * then it must implement this function. Otherwise it's not needed. */ -struct block_device **(*get_devices)(struct super_block *sb, -unsigned int *num_devs); +unsigned int (*get_devices)( +struct super_block *sb, +struct block_device *devs[FSCRYPT_MAX_DEVICES ]); }; int fscrypt_d_revalidate(struct inode *dir, const struct qstr *name,
Greg Kroah-Hartman
maintainerPATCH 646/744 ftrace: Add global mutex to serialize trace_parser access
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tengda Wu <[email protected]>
commit 7720b63bcef3f54c7fe288774b720a227d54a306 upstream.
In ftrace, the trace_parser structure is allocated and initialized when a trace file is opened, and is subsequently used across write and release handlers to parse user input.
The affected handler paths and their specific functions are:
- Open paths: ftrace_regex_open(), ftrace_graph_open()
- Write paths: ftrace_regex_write(), ftrace_graph_write()
- Release paths: ftrace_regex_release(), ftrace_graph_release()
If userspace opens a trace file descriptor and shares it across multiple threads, concurrent write calls will race on the parser's internal state, specifically the 'idx', 'cont', and 'buffer' fields, leading to corrupted input or undefined behavior.
Fix this by adding a global mutex, parser_lock, to serialize all access to trace_parser across write and release paths, preventing concurrent corruption of parser state.
--- kernel/trace/ftrace.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
kernel/trace/ftrace.c +13 -0
@@ -1098,6 +1098,12 @@ struct ftrace_ops global_ops = { };/* +* parser_lock - Protects trace_parser state against concurrent operations. +* Held across trace_get_user() and subsequent buffer parsing to prevent races. +*/ +static DEFINE_MUTEX (parser_lock); + +/* * Used by the stack unwinder to know about dynamic ftrace trampolines. */ struct ftrace_ops *ftrace_ops_trampoline (unsigned long addr)
@@ -5824,6 +5830,8 @@ ftrace_regex_write(struct file *file, co/* iter->hash is a local copy, so we don't need regex_lock */ parser = &iter->parser; + +guard (mutex)(&parser_lock); read =trace_get_user (parser, ubuf, cnt, ppos); if (read >= 0 && trace_parser_loaded(parser) &&
@@ -6961,12 +6969,14 @@ int ftrace_regex_release(struct inode *i iter = file->private_data; parser = &iter->parser; +mutex_lock (&parser_lock);if (trace_parser_loaded (parser)) {int enable = !(iter->flags &FTRACE_ITER_NOTRACE );ftrace_process_regex (iter, parser->buffer, parser->idx, enable); } +mutex_unlock (&parser_lock);trace_parser_put (parser);
@@ -7298,10 +7308,12 @@ ftrace_graph_release(struct inode *inode parser = &fgd->parser; +mutex_lock (&parser_lock);if (trace_parser_loaded ((parser))) { ret =ftrace_graph_set_hash (fgd->new_hash, parser->buffer); } +mutex_unlock (&parser_lock);trace_parser_put (parser);
@@ -7414,6 +7426,7 @@ ftrace_graph_write(struct file *file, co parser = &fgd->parser; +guard (mutex)(&parser_lock); read =trace_get_user (parser, ubuf, cnt, ppos); if (read >= 0 && trace_parser_loaded(parser) &&
Greg Kroah-Hartman
maintainerPATCH 647/744 io_uring/rw: fix missing ERESTARTSYS conversion in read paths
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yitang Yang <[email protected]>
commit ab05caca123c6d0b41850b7c05b246e4dca4a770 upstream.
Both read and write may receive internal restart error codes from the filesystem layer and should be converted to -EINTR. However, when multishot read support was added, the error code normalization was lost for both io_read() and io_read_mshot().
Extract the conversion into io_fixup_restart_res() and apply it in all three locations: io_rw_done(), io_read(), and io_read_mshot().
--- io_uring/rw.c | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-)
io_uring/rw.c +25 -17
@@ -615,6 +615,24 @@ static void io_complete_rw_iopoll(structsmp_store_release (&req->iopoll_completed,1 ); } +static inline ssize_t io_fixup_restart_res (ssize_t ret) +{ +switch (ret) { +case -ERESTARTSYS : +case -ERESTARTNOINTR : +case -ERESTARTNOHAND : +case -ERESTART_RESTARTBLOCK : +/* +* We can't just restart the syscall, since previously +* submitted sqes may already be in progress. Just fail +* this IO with EINTR. +*/ +return -EINTR ; +default : +return ret; + } +} +static inline void io_rw_done (struct io_kiocb *req,ssize_t ret) { struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
@@ -624,21 +642,8 @@ static inline void io_rw_done(struct io_return ;/* transform internal restart error codes */ -if (unlikely (ret <0 )) { -switch (ret) { -case -ERESTARTSYS : -case -ERESTARTNOINTR : -case -ERESTARTNOHAND : -case -ERESTART_RESTARTBLOCK : -/* -* We can't just restart the syscall, since previously -* submitted sqes may already be in progress. Just fail -* this IO with EINTR. -*/ - ret = -EINTR ; -break ; - } - } +if (unlikely (ret <0 )) + ret =io_fixup_restart_res (ret);if (req->flags &REQ_F_IOPOLL )io_complete_rw_iopoll (&rw->kiocb, ret);
@@ -1034,7 +1039,8 @@ int io_read(struct io_kiocb *req, unsignif (req->flags &REQ_F_BUFFERS_COMMIT )io_kbuf_recycle (req, sel.buf_list, issue_flags); -return ret; + +return io_fixup_restart_res (ret); }int io_read_mshot (struct io_kiocb *req,unsigned int issue_flags)
@@ -1068,8 +1074,10 @@ int io_read_mshot(struct io_kiocb *req,return IOU_RETRY ; }else if (ret <=0 ) {io_kbuf_recycle (req, sel.buf_list, issue_flags); -if (ret <0 ) +if (ret <0 ) { + ret =io_fixup_restart_res (ret);req_set_fail (req); + } }else if (!(req->flags &REQ_F_APOLL_MULTISHOT )) { cflags =io_put_kbuf (req, ret, sel.buf_list); }else {
Greg Kroah-Hartman
maintainerPATCH 648/744 iomap: fix out-of-bounds bitmap_set() with zero-length range
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhang Yi <[email protected]>
commit 9c7d8f7c8994c790fca501dc45ce66e7356cbe05 upstream.
ifs_set_range_dirty() and ifs_set_range_uptodate() compute last_blk as (off + len - 1) >> i_blkbits. When off is 0 and len is 0, the unsigned subtraction underflows to SIZE_MAX, producing a huge last_blk and nr_blks value that causes bitmap_set() to write far beyond the ifs->state allocation.
Regarding ifs_set_range_uptodate(), it is temporarily safe because len cannot be passed in as 0. However, for ifs_set_range_dirty() this is reachable from __iomap_write_end(): when copy_folio_from_iter_atomic() returns 0 (e.g. user buffer fault) and the folio is already uptodate, the guard at the top of __iomap_write_end() does not trigger because !folio_test_uptodate() is false, and iomap_set_range_dirty() is called with copied == 0.
Add a !len guard to both functions before the computation, so that a zero-length range is a no-op.
--- fs/iomap/buffered-io.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-)
fs/iomap/buffered-io.c +14 -8
@@ -67,11 +67,13 @@ static bool ifs_set_range_uptodate(struc struct iomap_folio_state *ifs, size_t off, size_t len) { struct inode *inode = folio->mapping->host; -unsigned int first_blk = off >> inode->i_blkbits; -unsigned int last_blk = (off + len -1 ) >> inode->i_blkbits; -unsigned int nr_blks = last_blk - first_blk +1 ; +unsigned int first_blk, last_blk; -bitmap_set (ifs->state, first_blk, nr_blks); +if (len) { + first_blk = off >> inode->i_blkbits; + last_blk = (off + len -1 ) >> inode->i_blkbits; +bitmap_set (ifs->state, first_blk, last_blk - first_blk +1 ); + }return ifs_is_fully_uptodate (folio, ifs); }
@@ -203,13 +205,17 @@ static void ifs_set_range_dirty(struct f {struct inode *inode = folio->mapping->host;unsigned int blks_per_folio =i_blocks_per_folio (inode, folio); -unsigned int first_blk = (off >> inode->i_blkbits); -unsigned int last_blk = (off + len -1 ) >> inode->i_blkbits; -unsigned int nr_blks = last_blk - first_blk +1 ; +unsigned int first_blk, last_blk;unsigned long flags; +if (!len) +return ; + + first_blk = off >> inode->i_blkbits; + last_blk = (off + len -1 ) >> inode->i_blkbits;spin_lock_irqsave (&ifs->state_lock, flags); -bitmap_set (ifs->state, first_blk + blks_per_folio, nr_blks); +bitmap_set (ifs->state, first_blk + blks_per_folio, + last_blk - first_blk +1 );spin_unlock_irqrestore (&ifs->state_lock, flags); }
Greg Kroah-Hartman
maintainerPATCH 649/744 iommu/vt-d: Disallow SVA if page walk is not coherent
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lu Baolu <[email protected]>
commit 780dfed688622ea01be3c9c2c55eec2207f05e04 upstream.
Hardware implementations report Scalable-Mode Page-walk Coherency Support via the SMPWCS field in the extended capability register. If the hardware does not support page-walk coherency, a clflush is required every time the page table entries (which are walked by the IOMMU hardware) are updated.
In the SVA case, page tables are managed by the CPU mm core, not by the IOMMU driver. Because the IOMMU driver has no way of knowing whether the CPU page table management code has ensured coherency via clflush, the driver must deny SVA if the hardware does not support coherent paging.
--- drivers/iommu/intel/svm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/intel/svm.c +1 -1
@@ -27,7 +27,7 @@void intel_svm_check (struct intel_iommu *iommu) { -if (!pasid_supported (iommu)) +if (!pasid_supported (iommu) || !ecap_smpwc (iommu->ecap))return ; if (cpu_feature_enabled(X86_FEATURE_GBPAGES) &&
Greg Kroah-Hartman
maintainerPATCH 650/744 mm/slub: fix lost local objects when bulk remote free batch fills
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shengming Hu <[email protected]>
commit af9ea231c0b4530edc389a3126a69e0699b7699d upstream.
In free_to_pcs_bulk(), when remote_objects[] fills to PCS_BATCH_MAX, the code jumps to flush_remote to free the batch. If all remote entries have already been compacted out of p[] via tail swaps while local objects remain, the flush_remote path returns early since i < size no longer holds. The leftover local objects are then neither cached in the sheaf nor returned to the slab freelist, causing a memory leak.
For illustration:
size = 64, local objects at p[0..31], remote objects at p[32..63] After scanning all remotes: i = 32, size = 32
p[0..31] local objects are dropped.
Harry pointed out that, although the logic contains a real leak, it does not appear to be triggerable with the current in-tree users. To hit this path, at least PCS_BATCH_MAX objects, currently hardcoded to 32, need to be collected in remote_objects[]. Looking at current kmem_cache_free_bulk() users:
* maple_node has sheaf_capacity = 32
* skbuff_head_cache has sheaf_capacity = 28
* panthor and msm drivers have sheaf_capacity = 4
The sheaf capacity is, at least for now, derived purely from the object size, with the user-requested capacity used as a minimum. Therefore, among the current users, only maple_node has a sheaf_capacity large enough to reach PCS_BATCH_MAX.
However, for the bug to trigger in maple_node, all objects in the sheaf would have to be from remote nodes. In that case, there would be no local objects left to leak. So this issue was found by code review rather than from a runtime report, and it does not seem to be triggerable by current users.
Still, the bug could become reachable with future users, a different sheaf capacity, or a change to PCS_BATCH_MAX. Fix the logic by freeing a full remote batch in place during the scan and then continuing to process the compacted array. This keeps all local objects on the normal fast path, while the tail path only handles any leftover partial remote batch. The redundant next_remote_batch jump label is removed as well.
--- mm/slub.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-)
mm/slub.c +5 -7
@@ -6066,7 +6066,6 @@ static void free_to_pcs_bulk(struct kmemvoid *remote_objects[PCS_BATCH_MAX ];unsigned int remote_nr =0 ; -next_remote_batch:while (i < size) {struct slab *slab =virt_to_slab (p[i]);
@@ -6081,8 +6080,11 @@ next_remote_batch:if (unlikely (!can_free_to_pcs (slab))) { remote_objects[remote_nr] = p[i]; p[i] = p[--size]; -if (++remote_nr >=PCS_BATCH_MAX ) - goto flush_remote; +if (++remote_nr >=PCS_BATCH_MAX ) { +__kmem_cache_free_bulk (s, remote_nr, &remote_objects[0 ]); +stat_add (s,FREE_SLOWPATH , remote_nr); + remote_nr =0 ; + }continue ; }
@@ -6166,10 +6168,6 @@ flush_remote:if (remote_nr) {__kmem_cache_free_bulk (s, remote_nr, &remote_objects[0 ]);stat_add (s,FREE_SLOWPATH , remote_nr); -if (i < size) { - remote_nr =0 ; - goto next_remote_batch; - } } }
Greg Kroah-Hartman
maintainerPATCH 651/744 mm/slab: fix a memory leak due to bootstrapping sheaves twice
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harry Yoo (Oracle) <[email protected]>
commit 1dba91a0493b7ffe9cbbcf7a8df1b361ddcac515 upstream.
When kmalloc caches are aliased, multiple cache pointers reference the same kmem_cache. As a result, iterating over kmalloc indices and bootstrapping sheaves can bootstrap the same cache more than once and leak memory.
Currently, this could happen when the architecture specifies minimum alignment for slab caches that is larger than ARCH_KMALLOC_MINALIGN.
Bootstrap sheaves only when the cache does not have them already. Add a warning when bootstrap_cache_sheaves() is called for a cache that already has sheaves enabled.
--- mm/slub.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
mm/slub.c +7 -2
@@ -8423,6 +8423,8 @@ static void __init bootstrap_cache_sheavbool failed = false;int node, cpu; +VM_WARN_ON_ONCE (cache_has_sheaves (s)); + capacity =calculate_sheaf_capacity (s, &empty_args);/* capacity can be 0 due to debugging or SLUB_TINY */
@@ -8473,8 +8475,11 @@ static void __init bootstrap_kmalloc_shefor (type =KMALLOC_NORMAL ; type <=KMALLOC_RANDOM_END ; type++) {for (int idx =0 ; idx <KMALLOC_SHIFT_HIGH +1 ; idx++) { -if (kmalloc_caches[type][idx]) -bootstrap_cache_sheaves (kmalloc_caches[type][idx]); +struct kmem_cache *s = kmalloc_caches[type][idx]; + +/* Do not bootstrap twice when caches are aliased */ +if (s && !cache_has_sheaves (s)) +bootstrap_cache_sheaves (s); } } }
Greg Kroah-Hartman
maintainerPATCH 652/744 net: stmmac: intel: skip SerDes reconfig when rate is unchanged
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Markus Breitenberger <[email protected]>
commit 0ab78ead2481adb52f9eb5b403865c529f6f2348 upstream.
intel_mac_finish() is registered as the phylink mac_finish() callback for the Elkhart Lake SGMII ports. phylink calls it at the end of every major link reconfiguration, including the initial one during probe.
The callback selects the PMC ModPHY LCPLL programming for the requested MAC-side interface and then power-cycles the SerDes. On Elkhart Lake that ModPHY is also used by the on-die AHCI SATA PHY. Reapplying the programming during the initial boot-time link-up disturbs the shared analog block while it is still driving SATA, so the SATA link fails to train:
ata1: SATA link down (SStatus 1 SControl 300)
The disk carrying the root filesystem is never detected and the system hangs at rootwait. Ethernet itself comes up normally, which makes the failure look unrelated to the network driver.
Before mac_finish() runs, the legacy SerDes power-up path has already programmed SERDES_GCR0 for the current interface. The 1G and 2.5G ModPHY tables selected by mac_finish() correspond to the SerDes lane rate, so read that rate back from SERDES_GCR0 and skip the PMC reprogramming and SerDes power-cycle when it already matches the selected interface.
This keeps the disruptive reprogramming out of the boot path when the SerDes is configured correctly, while preserving the previous behavior when a real SGMII/1000BASE-X to 2500BASE-X rate change is needed. If the register read fails, reconfigure as before.
--- drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c | 31 ++++++++++++++++++++++ 1 file changed, 31 insertions(+)
drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c +31 -0
@@ -524,6 +524,32 @@ static int intel_set_reg_access(const streturn ret; } +/* +* Return true if the SerDes lane rate must change to serve @interface. +* If the current rate cannot be determined, reconfigure as before. +*/ +static bool intel_serdes_needs_reconfig (struct stmmac_priv *priv, +struct intel_priv_data *intel_priv, +phy_interface_t interface) +{ +u32 cur_rate, want_rate; +int data; + +if (!intel_priv->mdio_adhoc_addr) +return true; + + data =mdiobus_read (priv->mii, intel_priv->mdio_adhoc_addr, +SERDES_GCR0 ); +if (data <0 ) +return true; + + cur_rate = (data &SERDES_RATE_MASK ) >>SERDES_RATE_PCIE_SHIFT ; + want_rate = interface ==PHY_INTERFACE_MODE_2500BASEX ? +SERDES_RATE_PCIE_GEN2 :SERDES_RATE_PCIE_GEN1 ; + +return cur_rate != want_rate; +} + static int intel_mac_finish(struct net_device *ndev, void *intel_data, unsigned int mode,
@@ -535,6 +561,11 @@ static int intel_mac_finish(struct net_dint max_regs =0 ;int ret =0 ; +if (!intel_serdes_needs_reconfig (priv, intel_priv, interface)) { + priv->plat->phy_interface = interface; +return 0 ; + } + ret =intel_tsn_lane_is_available (ndev, intel_priv);if (ret <0 ) {netdev_info (priv->dev,"No TSN lane available to set the registers.\n" );
Greg Kroah-Hartman
maintainerPATCH 653/744 phonet: pep: fix use-after-free in pep_get_sb()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
commit 0f71f852a96af9685858ce59fda34ecbf85c283d upstream.
pep_get_sb() doesn't consider that pskb_may_pull() might have relocated the skb data, and continue to access the older pointer, causing UAF.
Reproduced under KASAN:
BUG: KASAN: slab-use-after-free in pep_get_sb+0x234/0x3b0 Read of size 1 at addr ff11000105510f50 by task repro/157 pep_get_sb+0x234/0x3b0 pipe_handler_do_rcv+0x5f7/0xa10 pep_do_rcv+0x203/0x410 __sk_receive_skb+0x471/0x4a0 phonet_rcv+0x5b3/0x6c0 __netif_receive_skb+0xcc/0x1d0
Refetch the header with skb_header_pointer() after pskb_may_pull(), so the possibly stale pointer is no longer dereferenced. There are better ways to solve this, but, this is the less instrusive one.
--- net/phonet/pep.c | 2 ++ 1 file changed, 2 insertions(+)
net/phonet/pep.c +2 -0
@@ -55,6 +55,8 @@ static unsigned char *pep_get_sb(struct ph =skb_header_pointer (skb,0 ,2 , &h);if (ph ==NULL || ph->sb_len <2 || !pskb_may_pull (skb, ph->sb_len))return NULL ; +/* pskb_may_pull() may have reallocated the head; refetch ph. */ + ph =skb_header_pointer (skb,0 ,2 , &h); ph->sb_len -=2 ; *ptype = ph->sb_type; *plen = ph->sb_len;
Greg Kroah-Hartman
maintainerPATCH 654/744 vxlan: require CAP_NET_ADMIN in the device netns for changelink
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Doruk Tan Ozturk <[email protected]>
commit 3a61bd9637f3d929aa846e4eb3d98b48c26fcb0e upstream.
A tunnel changelink() operates on at most two netns, dev_net(dev) and the sticky underlay netns vxlan->net. They differ once the device is created in or moved to a netns other than the one the request runs in. The rtnl changelink path checks CAP_NET_ADMIN only against dev_net(dev), so a caller privileged there but not in vxlan->net can rewrite a vxlan device whose underlay lives in vxlan->net.
vxlan_changelink() validates and applies the new configuration against vxlan->net (vxlan_config_validate(vxlan->net, ...)) and can reopen the underlay socket in that netns, so the same reasoning as the tunnel changelink series applies here.
Gate vxlan_changelink() with rtnl_dev_link_net_capable(), at the top of the op before any attribute is parsed, matching ipgre_changelink() and the rest of the "require CAP_NET_ADMIN in the device netns for changelink" series.
Found by 0sec automated security-research tooling (https://0sec.ai).
--- drivers/net/vxlan/vxlan_core.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/vxlan/vxlan_core.c +3 -0
@@ -4422,6 +4422,9 @@ static int vxlan_changelink(struct net_dstruct vxlan_rdst *dst;int err; +if (!rtnl_dev_link_net_capable (dev, vxlan->net)) +return -EPERM ; + dst = &vxlan->default_dst; err =vxlan_nl2conf (tb, data, dev, &conf, true, extack);if (err)
Greg Kroah-Hartman
maintainerPATCH 655/744 net: slip: serialize receive against buffer reallocation
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sungmin Kang <[email protected]>
commit ee7f9bb9320add61f7b367d7e6cd55e3a3a4d65d upstream.
sl_realloc_bufs() replaces rbuff and updates buffsize while holding sl->lock. slip_receive_buf() reads those fields and writes through rbuff without holding the lock.
An MTU change can therefore race with receive processing. An MTU shrink can expose the new smaller rbuff with the old larger bound, causing an out-of-bounds write. A receive callback which already loaded the old rbuff can instead continue writing after that buffer has been freed.
Serialize receive processing with sl_realloc_bufs() by holding sl->lock while consuming each receive batch.
--- drivers/net/slip/slip.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/slip/slip.c +4 -0
@@ -693,6 +693,8 @@ static void slip_receive_buf(struct tty_if (!sl || sl->magic !=SLIP_MAGIC || !netif_running (sl->dev))return ; +spin_lock_bh (&sl->lock); +/* Read the characters out of the buffer */ while (count--) {if (fp && *fp++) {
@@ -708,6 +710,8 @@ static void slip_receive_buf(struct tty_#endif slip_unesc (sl, *cp++); } + +spin_unlock_bh (&sl->lock); }/************************************
Greg Kroah-Hartman
maintainerPATCH 656/744 geneve: require CAP_NET_ADMIN in the device netns for changelink
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Doruk Tan Ozturk <[email protected]>
commit 8efb8f8bbb353b8f2fdf4f37534c6d96c9f69e01 upstream.
A tunnel changelink() operates on at most two netns, dev_net(dev) and the sticky underlay netns geneve->net. They differ once the device is created in or moved to a netns other than the one the request runs in. The rtnl changelink path checks CAP_NET_ADMIN only against dev_net(dev), so a caller privileged there but not in geneve->net can rewrite a geneve device whose underlay lives in geneve->net.
geneve_changelink() applies the new configuration against geneve->net:geneve_link_config() and the geneve_quiesce()/geneve_unquiesce() pair reopen the underlay sockets in that netns (geneve_sock_add() uses geneve->net), so the same reasoning as the tunnel changelink series applies here.
Gate geneve_changelink() with rtnl_dev_link_net_capable(), at the top of the op before any attribute is parsed, matching ipgre_changelink() and the rest of the "require CAP_NET_ADMIN in the device netns for changelink" series.
Found by 0sec automated security-research tooling (https://0sec.ai).
--- drivers/net/geneve.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/geneve.c +3 -0
@@ -2251,6 +2251,9 @@ static int geneve_changelink(struct net_struct geneve_config cfg;int err; +if (!rtnl_dev_link_net_capable (dev, geneve->net)) +return -EPERM ; +/* If the geneve device is configured for metadata (or externally * controlled, for example, OVS), then nothing can be changed. */
Greg Kroah-Hartman
maintainerPATCH 657/744 net/af_iucv: fix NULL deref in afiucv_hs_callback_syn()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hidayath Khan <[email protected]>
commit 47a5116e56a6b6fe1e909f244e39cd0fc26ceee4 upstream.
afiucv_hs_callback_syn() allocates the child socket with GFP_ATOMIC. If the allocation fails, nsk is NULL.
The connection-refused path is entered when the listen state check fails, the accept backlog is full, or nsk is NULL. The code unconditionally calls iucv_sock_kill(nsk) in that path.
iucv_sock_kill() does not accept a NULL socket pointer and immediately dereferences sk via sock_flag(sk, SOCK_ZAPPED). When nsk is NULL, calling iucv_sock_kill(nsk) results in a NULL pointer dereference.
Only call iucv_sock_kill() when a child socket was successfully allocated.
--- net/iucv/af_iucv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/iucv/af_iucv.c +2 -1
@@ -1874,7 +1874,8 @@ static int afiucv_hs_callback_syn(structafiucv_swap_src_dest (skb); trans_hdr->flags =AF_IUCV_FLAG_SYN |AF_IUCV_FLAG_FIN ; err =dev_queue_xmit (skb); -iucv_sock_kill (nsk); +if (nsk) +iucv_sock_kill (nsk);bh_unlock_sock (sk); goto out; }
Greg Kroah-Hartman
maintainerPATCH 658/744 net/iucv: fix use-after-free of a severed iucv_path
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit be7cc4656eb1f54029610e82d1f0fdd3f9b5ec0a upstream.
af_iucv queues not-yet-received message notifications on iucv->message_q, each holding a raw pointer to the connection's iucv_path. When the peer severs the connection, iucv_sever_path() frees that path with iucv_path_free() but leaves the notifications queued. A later recvmsg() drains message_q via iucv_process_message_q() and hands the stale path to message_receive() -- a use-after-free of the freed iucv_path.
Drop the queued notifications when the path is severed; once the path is gone they can no longer be received. This also frees the notifications leaked when a socket is closed with messages still queued.
--- net/iucv/af_iucv.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
net/iucv/af_iucv.c +14 -0
@@ -336,6 +336,7 @@ static void iucv_sever_path(struct sockunsigned char user_data[16 ];struct iucv_sock *iucv =iucv_sk (sk);struct iucv_path *path = iucv->path; +struct sock_msg_q *p, *n;/* Whoever resets the path pointer, must sever and free it. */ if (xchg (&iucv->path,NULL )) {
@@ -347,6 +348,19 @@ static void iucv_sever_path(struct sock }else pr_iucv->path_sever (path,NULL );iucv_path_free (path); + +/* +* Message notifications queued on message_q still reference +* the now freed path; drop them, otherwise a later recvmsg() +* would pass the freed iucv_path to message_receive() via +* iucv_process_message_q(). +*/ +spin_lock_bh (&iucv->message_q.lock); +list_for_each_entry_safe (p, n, &iucv->message_q.list, list) { +list_del (&p->list); +kfree (p); + } +spin_unlock_bh (&iucv->message_q.lock); } }
Greg Kroah-Hartman
maintainerPATCH 659/744 net/mlx5e: Use sender devcom for MPV master-up
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manjunath Patil <[email protected]>
commit e32649b4bad90a6216d8e93cd7dd050af8ac9740 upstream.
After PCIe DPC recovery, mlx5 reloads the affected functions and replays multiport affiliation events. In the reported failure, the first relevant device error was:
pcieport 0000:10:01.1: DPC: containment event
pcieport 0000:10:01.1: PCIe Bus Error: severity=Uncorrected (Fatal)
pcieport 0000:10:01.1: [ 5] SDES (First)
mlx5 recovered the PCI functions and resumed 0000:11:00.1. During that resume, RDMA multiport binding replayed MLX5_DRIVER_EVENT_AFFILIATION_DONE and mlx5e sent MPV_DEVCOM_MASTER_UP. The host then panicked with:
BUG: kernel NULL pointer dereference, address: 0000000000000010 RIP: mlx5_devcom_comp_set_ready+0x5/0x40 [mlx5_core] RDI: 0000000000000000
Call trace included:
mlx5_devcom_comp_set_ready
mlx5e_devcom_event_mpv
mlx5_devcom_send_event
mlx5_ib_bind_slave_port
mlx5r_mp_probe
mlx5_pci_resume
MPV devcom registration publishes mlx5e private data to the component peer list before mlx5e_devcom_init_mpv() stores the returned component device in priv->devcom. A concurrent master-up event can therefore reach a peer whose private data is visible but whose priv->devcom backpointer is still NULL.
MPV_DEVCOM_MASTER_UP already carries the sender/master mlx5e private data as event_data. The ready bit is stored on the shared devcom component, not on an individual peer. Use the sender devcom when marking the MPV component ready.
This preserves the readiness transition while avoiding a NULL dereference of the peer devcom pointer during affiliation replay after PCI error recovery.
--- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en_main.c +2 -2
@@ -211,11 +211,11 @@ static void mlx5e_disable_async_events(sstatic int mlx5e_devcom_event_mpv (int event,void *my_data,void *event_data) { -struct mlx5e_priv *slave_priv = my_data; +struct mlx5e_priv *master_priv = event_data;switch (event) {case MPV_DEVCOM_MASTER_UP : -mlx5_devcom_comp_set_ready (slave_priv->devcom, true); +mlx5_devcom_comp_set_ready (master_priv->devcom, true);break ;case MPV_DEVCOM_MASTER_DOWN :/* no need for comp set ready false since we unregister after
Greg Kroah-Hartman
maintainerPATCH 660/744 net/sched: serialize qdisc_rtab_list against concurrent get/put
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aldo Ariel Panzardo <[email protected]>
commit f43ee0c0730d6191629b5ee1ceae27b1ebfdc047 upstream.
qdisc_get_rtab() and qdisc_put_rtab() mutate the process-global singly linked list qdisc_rtab_list and a plain non-atomic 'int refcnt' with no lock. This was only safe because every caller historically held the RTNL mutex, which serialized all rate-table lookups, inserts and frees.
That invariant no longer holds. cls_flower sets TCF_PROTO_OPS_DOIT_UNLOCKED, so tc_new_tfilter() keeps rtnl_held == false for it and sets TCA_ACT_FLAGS_NO_RTNL. That flag propagates through tcf_exts_validate_ex() -> tcf_action_init() -> tcf_action_init_1() -> tcf_police_init(), which calls qdisc_get_rtab()/qdisc_put_rtab() with the RTNL mutex NOT held. Two RTM_NEWTFILTER requests on different CPUs, each adding a flower filter with a police action carrying the same rate, then race on qdisc_rtab_list and on the non-atomic refcnt, leading to a use-after-free / double-free of the kmalloc-2k struct qdisc_rate_table. qdisc_rtab_list is a single global (not per-netns), so the corrupted object is shared system-wide.
BUG: KASAN: slab-use-after-free in qdisc_put_rtab+0x12f/0x160 qdisc_put_rtab+0x12f/0x160 tcf_police_init+0xda9/0x1590 tcf_action_init_1+0x460/0x6b0 tcf_action_init+0x439/0xa40 tcf_exts_validate_ex+0x42d/0x550 fl_change+0xddd/0x7da0 tc_new_tfilter+0xaa7/0x2420 rtnetlink_rcv_msg+0x95e/0xe90 which belongs to the cache kmalloc-2k of size 2048
Protect qdisc_rtab_list and the refcount with a dedicated spinlock. The (sleeping, GFP_KERNEL) allocation in qdisc_get_rtab() is performed before taking the lock; if a concurrent inserter added an identical table in the meantime the freshly allocated one is freed under the lock, so no duplicate is leaked. qdisc_put_rtab() now decrements the refcount and unlinks under the same lock.
--- net/sched/sch_api.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-)
net/sched/sch_api.c +19 -5
@@ -415,12 +415,13 @@ static __u8 __detect_linklayer(struct tc }static struct qdisc_rate_table *qdisc_rtab_list; +static DEFINE_SPINLOCK (qdisc_rtab_lock);struct qdisc_rate_table *qdisc_get_rtab (struct tc_ratespec *r,struct nlattr *tab,struct netlink_ext_ack *extack) { -struct qdisc_rate_table *rtab; +struct qdisc_rate_table *rtab, *new_rtab; if (tab == NULL || r->rate == 0 || r->cell_log == 0 || r->cell_log >= 32 ||
@@ -429,15 +430,20 @@ struct qdisc_rate_table *qdisc_get_rtab(return NULL ; } + new_rtab =kmalloc_obj (*new_rtab); + +spin_lock (&qdisc_rtab_lock);for (rtab = qdisc_rtab_list; rtab; rtab = rtab->next) {if (!memcmp (&rtab->rate, r,sizeof (struct tc_ratespec )) && !memcmp (&rtab->data,nla_data (tab),TC_RTAB_SIZE )) { rtab->refcnt++; +spin_unlock (&qdisc_rtab_lock); +kfree (new_rtab);return rtab; } } - rtab =kmalloc_obj (*rtab); + rtab = new_rtab;if (rtab) { rtab->rate = *r; rtab->refcnt =1 ;
@@ -449,6 +455,7 @@ struct qdisc_rate_table *qdisc_get_rtab( }else {NL_SET_ERR_MSG (extack,"Failed to allocate new qdisc rate table" ); } +spin_unlock (&qdisc_rtab_lock);return rtab; }EXPORT_SYMBOL (qdisc_get_rtab);
@@ -457,18 +464,25 @@ void qdisc_put_rtab(struct qdisc_rate_ta {struct qdisc_rate_table *rtab, **rtabp; -if (!tab || --tab->refcnt) +if (!tab) +return ; + +spin_lock (&qdisc_rtab_lock); +if (--tab->refcnt) { +spin_unlock (&qdisc_rtab_lock);return ; + }for (rtabp = &qdisc_rtab_list; (rtab = *rtabp) !=NULL ; rtabp = &rtab->next) {if (rtab == tab) { *rtabp = rtab->next; -kfree (rtab); -return ; +break ; } } +spin_unlock (&qdisc_rtab_lock); +kfree (tab); }EXPORT_SYMBOL (qdisc_put_rtab);
Greg Kroah-Hartman
maintainerPATCH 661/744 net/x25: fix use-after-free in x25_kill_by_neigh()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Lee <[email protected]>
commit 5499e0602d2faafd42c580d25f615903c3fbe11b upstream.
x25_kill_by_neigh() walks the global X.25 socket list looking for sockets attached to a terminating neighbour. x25_list_lock protects list membership while the lookup is in progress, but it does not pin a socket's lifetime after the lock is dropped.
The function currently drops x25_list_lock before calling lock_sock(s). A concurrent close can run x25_release(), remove the same socket from x25_list, and drop the last socket reference in that window. The neighbour teardown path can then lock or inspect a freed struct sock/struct x25_sock.
Take sock_hold(s) while x25_list_lock still proves that the list entry is live, then drop the temporary reference after the socket has been locked, rechecked, and released. Recheck x25_sk(s)->neighbour after lock_sock(), because another path may have disconnected the socket before this path acquired the socket lock. Restart the list walk after each disconnect because the list lock was dropped and the previous iterator state may no longer be valid.
A QEMU/KASAN run against origin/master reproduced a slab-use-after-free in x25_kill_by_neigh().
--- net/x25/af_x25.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
net/x25/af_x25.c +6 -2
@@ -1772,15 +1772,19 @@ void x25_kill_by_neigh(struct x25_neigh {struct sock *s; +again:write_lock_bh (&x25_list_lock);sk_for_each (s, &x25_list) {if (x25_sk (s)->neighbour == nb) { +sock_hold (s);write_unlock_bh (&x25_list_lock);lock_sock (s); -x25_disconnect (s,ENETUNREACH ,0 ,0 ); +if (x25_sk (s)->neighbour == nb) +x25_disconnect (s,ENETUNREACH ,0 ,0 );release_sock (s); -write_lock_bh (&x25_list_lock); +sock_put (s); + goto again; } }write_unlock_bh (&x25_list_lock);
Greg Kroah-Hartman
maintainerPATCH 662/744 net: gro: fix double aggregation of flush-marked skbs
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shiming Cheng <[email protected]>
commit e751256486d0ded20f5a9f9863467f1dce65142f upstream.
Commit 0ab03f353d36 ("net-gro: Fix GRO flush when receiving a GSO packet.") added a flush check to skb_gro_receive(), but skb_gro_receive_list() lacks the same validation.
As a result, packets marked with NAPI_GRO_CB(skb)->flush may still be re-aggregated.
This allows already-GRO'd packets with existing frag_list to be re-aggregated into a new GRO session, corrupting the frag_list chain structure. When skb_segment() attempts to unpack these malformed packets, it encounters invalid state and triggers a kernel panic.
Scenario (Tethering/Device forwarding):
1. Driver: Generated aggregated packet P1 via LRO with frag_list
2. Dev A: Receives aggregated fraglist packet and flush flag set
3. Dev A: Re-enters GRO, skb_gro_receive_list() is called
4. Missing flush check allows re-aggregation despite flush flag
5. Frag_list chain becomes corrupted (loops or dangling refs)
6. Dev B: TX path calls skb_segment(), crashes on corrupted frag_list
Root cause in skb_segment():
The check at line ~4891:
if (hsize <= 0 && i >= nfrags && skb_headlen(list_skb) &&
(skb_headlen(list_skb) == len || sg)) { When frag_list is corrupted by double aggregation, when list_skb is a NULL pointer from skb->next, skb_headlen(list_skb) dereference NULL/corrupted pointers occurs.
Call Trace: skb_headlen(NULL skb) skb_segment tcp_gso_segment tcp4_gso_segment inet_gso_segment skb_mac_gso_segment __skb_gso_segment skb_gso_segment validate_xmit_skb validate_xmit_skb_list sch_direct_xmit qdisc_restart __qdisc_run qdisc_run net_tx_action
Fix: Add NAPI_GRO_CB(skb)->flush validation to the early-return check in skb_gro_receive_list(), matching the defensive programming pattern of skb_gro_receive().
--- net/core/gro.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/core/gro.c +3 -1
@@ -229,7 +229,9 @@ done:int skb_gro_receive_list (struct sk_buff *p,struct sk_buff *skb) { -if (unlikely (p->len + skb->len >=65536 )) +/* make sure to check flush flag and to not merge */ +if (unlikely (p->len + skb->len >=65536 || +NAPI_GRO_CB (skb)->flush))return -E2BIG ;if (!pskb_may_pull (skb,skb_gro_offset (skb))) {
Greg Kroah-Hartman
maintainerPATCH 663/744 net: hip04: fix RX buffer leak on build_skb failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 14fa65d10f5696b063a7d8d26e8291ea84a2c6ed upstream.
When build_skb() fails in hip04_rx_poll(), the driver jumps to the refill path without releasing the current RX buffer and its DMA mapping. Installing a replacement buffer then overwrites the slot references and leaks both resources.
Keep the current slot intact and return budget so NAPI retries the same buffer. Also free a newly allocated RX fragment when dma_map_single() fails.
This issue was found by an in-house static analysis tool.
--- drivers/net/ethernet/hisilicon/hip04_eth.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/net/ethernet/hisilicon/hip04_eth.c +8 -3
@@ -594,7 +594,11 @@ static int hip04_rx_poll(struct napi_str skb =build_skb (buf, priv->rx_buf_size);if (unlikely (!skb)) {net_dbg_ratelimited ("build_skb failed\n" ); - goto refill; +/* Retain the slot; return budget so NAPI retries this +* buffer. Refill would overwrite rx_buf[]/rx_phys[] +* and leak them. +*/ +return budget; } dma_unmap_single(priv->dev, priv->rx_phys[priv->rx_head],
@@ -622,14 +626,15 @@ static int hip04_rx_poll(struct napi_str rx++; } -refill: buf =netdev_alloc_frag (priv->rx_buf_size);if (!buf) goto done; phys =dma_map_single (priv->dev, buf,RX_BUF_SIZE ,DMA_FROM_DEVICE ); -if (dma_mapping_error (priv->dev, phys)) +if (dma_mapping_error (priv->dev, phys)) { +skb_free_frag (buf); goto done; + } priv->rx_buf[priv->rx_head] = buf; priv->rx_phys[priv->rx_head] = phys;hip04_set_recv_desc (priv, phys);
Greg Kroah-Hartman
maintainerPATCH 664/744 net: pcs: xpcs: fix SGMII state reading
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Coia Prant <[email protected]>
commit def9a4745e105145133e442dd8a1c126caf0f553 upstream.
Commit 2a22b7ae2fa3 ("net: pcs: xpcs: adapt Wangxun NICs for SGMII mode") added a path in xpcs_get_state_c37_sgmii() that reads speed/duplex from BMCR after AN completes. However, BMCR does not reflect the negotiated result on the hardware where this has been tested:
- On RK3568 (MAC side SGMII), BMCR returns a fixed hardware reset value
- Wangxun engineer Jiawen Wu confirmed that on their side, "BMCR looks like it only wants to be return as 0" [0]
The correct information is available in CL37_ANSGM_STS, which contains the actual link status and negotiated speed/duplex.
This bug was previously masked by phylink core, which overrides the PCS link state with the PHY state when a PHY is present:
/* If we have a phy, the "up" state is the union of both the
* PHY and the MAC
*/
if (phy)
link_state.link &= pl->phy_state.link;Thus, when the link is down, the PHY's link_down state is applied on top of whatever the PCS reports, hiding the broken PCS state reading path.
Modify xpcs_get_state_c37_sgmii() to:
1. Read link state from CL37_ANSGM_STS
2. If link is up, report speed/duplex from CL37_ANSGM_STS
3. Remove the broken BMCR reading path entirely
Also properly set state->an_complete to reflect the AN completion status, and clear CL37_ANCMPLT_INTR when link is down to avoid stale state.
[0] https://lore.kernel.org/all/[email protected]/
--- drivers/net/pcs/pcs-xpcs.c | 32 +++++++------------------------- 1 file changed, 7 insertions(+), 25 deletions(-)
drivers/net/pcs/pcs-xpcs.c +7 -25
@@ -1058,6 +1058,7 @@ static int xpcs_get_state_c37_sgmii(stru/* Reset link_state */ state->link = false; + state->an_complete = false; state->speed =SPEED_UNKNOWN ; state->duplex =DUPLEX_UNKNOWN ; state->pause =0 ;
@@ -1069,6 +1070,8 @@ static int xpcs_get_state_c37_sgmii(struif (ret <0 )return ret; + state->an_complete = ret &DW_VR_MII_AN_STS_C37_ANCMPLT_INTR ; +if (ret &DW_VR_MII_C37_ANSGM_SP_LNKSTS ) {int speed_value;
@@ -1086,34 +1089,13 @@ static int xpcs_get_state_c37_sgmii(stru state->duplex =DUPLEX_FULL ; else state->duplex = DUPLEX_HALF; - }else if (ret ==DW_VR_MII_AN_STS_C37_ANCMPLT_INTR ) { -int speed, duplex; - - state->link = true; - - speed =xpcs_read (xpcs,MDIO_MMD_VEND2 ,MII_BMCR ); -if (speed <0 ) -return speed; - speed &=BMCR_SPEED100 |BMCR_SPEED1000 ; -if (speed ==BMCR_SPEED1000 ) - state->speed =SPEED_1000 ; -else if (speed ==BMCR_SPEED100 ) - state->speed =SPEED_100 ; -else if (speed ==0 ) - state->speed =SPEED_10 ; - - duplex =xpcs_read (xpcs,MDIO_MMD_VEND2 ,MII_ADVERTISE ); -if (duplex <0 ) -return duplex; - -if (duplex &ADVERTISE_1000XFULL ) - state->duplex =DUPLEX_FULL ; -else if (duplex &ADVERTISE_1000XHALF ) - state->duplex =DUPLEX_HALF ; +return 0 ; + } +/* Clear AN complete status or interrupt */ +if (state->an_complete)xpcs_write (xpcs,MDIO_MMD_VEND2 ,DW_VR_MII_AN_INTR_STS ,0 ); - }return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 665/744 net: qrtr: ns: Raise node count limit to 512
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Youssef Samir <[email protected]>
commit ff194cffd586cbd4cc49eccb002c65f2a902a277 upstream.
The current node limit of 64 breaks the functionality for a number of AI200 deployments that have up to 384 nodes. Raise the limit to 512.
--- net/qrtr/ns.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/qrtr/ns.c +2 -2
@@ -76,11 +76,11 @@ struct qrtr_node {* requirements. If the requirement changes in the future, these values can be * increased. */ -#define QRTR_NS_MAX_NODES 64 +#define QRTR_NS_MAX_NODES 512#define QRTR_NS_MAX_SERVERS 256#define QRTR_NS_MAX_LOOKUPS 64 -static u8 node_count; +static u16 node_count;static struct qrtr_node *node_get (unsigned int node_id) {
Greg Kroah-Hartman
maintainerPATCH 666/744 proc: Fix broken error paths for namespace links
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jann Horn <[email protected]>
commit 425224c2d700391729be7fe6929a88ef4e2d7a4e upstream.
Don't return the return value of down_read_killable() (0) when a ptrace access check fails, return -EACCES as intended.
--- fs/proc/namespaces.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/proc/namespaces.c +3 -1
@@ -46,7 +46,7 @@ static const char *proc_ns_get_link(struconst struct proc_ns_operations *ns_ops =PROC_I (inode)->ns_ops;struct task_struct *task;struct path ns_path; -int error = -EACCES ; +int error;if (!dentry)return ERR_PTR (-ECHILD );
@@ -59,6 +59,7 @@ static const char *proc_ns_get_link(struif (error) goto out_put_task; + error = -EACCES ;if (!ptrace_may_access (task,PTRACE_MODE_READ_FSCREDS )) goto out;
@@ -90,6 +91,7 @@ static int proc_ns_readlink(struct dentrif (res) goto out_put_task; + res = -EACCES ;if (ptrace_may_access (task,PTRACE_MODE_READ_FSCREDS )) { res =ns_get_name (name,sizeof (name), task, ns_ops);if (res >=0 )
Greg Kroah-Hartman
maintainerPATCH 667/744 ptp: ptp_s390: Add missing facility check
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Schnelle <[email protected]>
commit e78f1ac37afcb16cb6fef8a2c92591eab6558956 upstream.
Only register the physical clock when facility 28 is installed and PTFF QAF returns that PTFF QPT is available.
--- drivers/ptp/ptp_s390.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/ptp/ptp_s390.c +5 -1
@@ -107,6 +107,9 @@ static __init int ptp_s390_init(void)if (IS_ERR (ptp_stcke_clock))return PTR_ERR (ptp_stcke_clock); +if (!test_facility (28 ) || !ptff_query (PTFF_QPT )) +return 0 ; + ptp_qpt_clock =ptp_clock_register (&ptp_s390_qpt_info,NULL );if (IS_ERR (ptp_qpt_clock)) {ptp_clock_unregister (ptp_stcke_clock);
@@ -117,7 +120,8 @@ static __init int ptp_s390_init(void) static __exit void ptp_s390_exit(void) { -ptp_clock_unregister (ptp_qpt_clock); +if (ptp_qpt_clock) +ptp_clock_unregister (ptp_qpt_clock);ptp_clock_unregister (ptp_stcke_clock); }
Re: [PATCH 7.1 667/744] ptp: ptp_s390: Add missing facility check
Quoted 25 lines · Greg Kroah-Hartman
7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Schnelle <[email protected]>
commit
e78f1ac37afcb16cb6fef8a2c92591eab6558956upstream.Only register the physical clock when facility 28 is installed and PTFF QAF returns that PTFF QPT is available.
Fixes 2d7de7a3010d ("s390/time: Add PtP driver")Signed-off-by Sven Schnelle <[email protected]>Reviewed-by Heiko Carstens <[email protected]>Signed-off-by Jakub Kicinski <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>--- drivers/ptp/ptp_s390.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/ptp/ptp_s390.c static __init int ptp_s390_init(void) · line 110
Quoted 4 lines
drivers/ptp/ptp_s390.c +1
-0@@ -107,6 +107,9 @@ static __init int ptp_s390_init(void)if (IS_ERR (ptp_stcke_clock))return PTR_ERR (ptp_stcke_clock); +if (!test_facility (28 ) || !ptff_query (PTFF_QPT ))
ptff_query() here needs:9de445d8296a ("s390/ptff: Export ptff_function_mask[]")
thanks,
Signature · 2 lines
js suse labs
Greg Kroah-Hartman
maintainerRe: [PATCH 7.1 667/744] ptp: ptp_s390: Add missing facility check
Quoted 23 lines · Jiri Slaby
Quoted 22 lines · Greg Kroah-Hartman
7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Schnelle <[email protected]>
commit
e78f1ac37afcb16cb6fef8a2c92591eab6558956upstream.Only register the physical clock when facility 28 is installed and PTFF QAF returns that PTFF QPT is available.
Fixes 2d7de7a3010d ("s390/time: Add PtP driver")Signed-off-by Sven Schnelle <[email protected]>Reviewed-by Heiko Carstens <[email protected]>Signed-off-by Jakub Kicinski <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>--- drivers/ptp/ptp_s390.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
Quoted 9 lines
drivers/ptp/ptp_s390.c static __init int ptp_s390_init(void) · line 109
Quoted 6 lines
drivers/ptp/ptp_s390.c +1
-0@@ -107,6 +107,9 @@ static __init int ptp_s390_init(void)if (IS_ERR (ptp_stcke_clock))return PTR_ERR (ptp_stcke_clock); +if (!test_facility (28 ) || !ptff_query (PTFF_QPT ))
ptff_query()here needs:9de445d8296a("s390/ptff: Export ptff_function_mask[]")
Ah, good catch, now queued up. How did you find that thing?
greg k-h
Re: [PATCH 7.1 667/744] ptp: ptp_s390: Add missing facility check
Quoted 34 lines · Greg Kroah-Hartman
Quoted 23 lines · Jiri Slaby
Quoted 22 lines · Greg Kroah-Hartman
7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Schnelle <[email protected]>
commit
e78f1ac37afcb16cb6fef8a2c92591eab6558956upstream.Only register the physical clock when facility 28 is installed and PTFF QAF returns that PTFF QPT is available.
Fixes 2d7de7a3010d ("s390/time: Add PtP driver")Signed-off-by Sven Schnelle <[email protected]>Reviewed-by Heiko Carstens <[email protected]>Signed-off-by Jakub Kicinski <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>--- drivers/ptp/ptp_s390.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)Quoted 9 lines
drivers/ptp/ptp_s390.c static __init int ptp_s390_init(void) · line 109
Quoted 6 lines
drivers/ptp/ptp_s390.c +1
-0@@ -107,6 +107,9 @@ static __init int ptp_s390_init(void)if (IS_ERR (ptp_stcke_clock))return PTR_ERR (ptp_stcke_clock); +if (!test_facility (28 ) || !ptff_query (PTFF_QPT ))
ptff_query()here needs:9de445d8296a("s390/ptff: Export ptff_function_mask[]")
Quoted 1 line
Ah, good catch, now queued up. How did you find that thing?
It broke openSUSE kernel build. We have:
config/s390x/default:CONFIG_PTP_S390=m
thanks,
Signature · 2 lines
js suse labs
Re: [PATCH 7.1 667/744] ptp: ptp_s390: Add missing facility check
In reply to Greg Kroah-HartmanQuoted 34 lines · Greg Kroah-Hartman
Quoted 23 lines · Jiri Slaby
Quoted 22 lines · Greg Kroah-Hartman
7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Schnelle <[email protected]>
commit
e78f1ac37afcb16cb6fef8a2c92591eab6558956upstream.Only register the physical clock when facility 28 is installed and PTFF QAF returns that PTFF QPT is available.
Fixes 2d7de7a3010d ("s390/time: Add PtP driver")Signed-off-by Sven Schnelle <[email protected]>Reviewed-by Heiko Carstens <[email protected]>Signed-off-by Jakub Kicinski <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>--- drivers/ptp/ptp_s390.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)Quoted 9 lines
drivers/ptp/ptp_s390.c static __init int ptp_s390_init(void) · line 109
Quoted 6 lines
drivers/ptp/ptp_s390.c +1
-0@@ -107,6 +107,9 @@ static __init int ptp_s390_init(void)if (IS_ERR (ptp_stcke_clock))return PTR_ERR (ptp_stcke_clock); +if (!test_facility (28 ) || !ptff_query (PTFF_QPT ))
ptff_query()here needs:9de445d8296a("s390/ptff: Export ptff_function_mask[]")
Quoted 1 line
Ah, good catch, now queued up. How did you find that thing?
Maybe we should change the documentation. I was wondering whether I have to mark that as a dependency, looked up ./process/stable-kernel-rules.rst which says:
Note that for a patch series, you do not have to list as prerequisites the patches present in the series itself. For example, if you have the following patch series::
patch1
patch2
where patch2 depends on patch1, you do not have to list patch1 as prerequisite of patch2 if you have already marked patch1 for stable inclusion.
Which lead me to believe that I don't have to add stable@ to the the other patch, but looks like this was wrong?
Greg Kroah-Hartman
maintainerRe: [PATCH 7.1 667/744] ptp: ptp_s390: Add missing facility check
Quoted 49 lines · Sven Schnelle
Quoted 34 lines · Greg Kroah-Hartman
Quoted 23 lines · Jiri Slaby
Quoted 22 lines · Greg Kroah-Hartman
7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Schnelle <[email protected]>
commit
e78f1ac37afcb16cb6fef8a2c92591eab6558956upstream.Only register the physical clock when facility 28 is installed and PTFF QAF returns that PTFF QPT is available.
Fixes 2d7de7a3010d ("s390/time: Add PtP driver")Signed-off-by Sven Schnelle <[email protected]>Reviewed-by Heiko Carstens <[email protected]>Signed-off-by Jakub Kicinski <[email protected]>Signed-off-by Greg Kroah-Hartman <[email protected]>--- drivers/ptp/ptp_s390.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)Quoted 9 lines
drivers/ptp/ptp_s390.c static __init int ptp_s390_init(void) · line 109
Quoted 6 lines
drivers/ptp/ptp_s390.c +1
-0@@ -107,6 +107,9 @@ static __init int ptp_s390_init(void)if (IS_ERR (ptp_stcke_clock))return PTR_ERR (ptp_stcke_clock); +if (!test_facility (28 ) || !ptff_query (PTFF_QPT ))
ptff_query()here needs:9de445d8296a("s390/ptff: Export ptff_function_mask[]")Quoted 1 line
Ah, good catch, now queued up. How did you find that thing?
Maybe we should change the documentation. I was wondering whether I have to mark that as a dependency, looked up
./process/stable-kernel-rules.rstwhich says:Note that for a patch series, you do not have to list as prerequisites the patches present in the series itself. For example, if you have the following patch series::
patch1
patch2
Quoted 6 lines
where patch2 depends on patch1, you do not have to list patch1 as prerequisite of patch2 if you have already marked patch1 for stable inclusion.
Which lead me to believe that I don't have to add stable@ to the the other patch, but looks like this was wrong?
The issue is that was no link that I could find between 9de445d8296a ("s390/ptff: Export ptff_function_mask[]") and e78f1ac37afc ("ptp:ptp_s390: Add missing facility check")
i.e. no "Fixes:" tag, or dependancy info, so if I took the "add missing..." patch, I didn't know that the export patch was required.
Not a big deal, happens at times, just if you know a commit fixes an older patch, a "Fixes:" tag is helpful.
thanks,
greg k-h
Greg Kroah-Hartman
maintainerPATCH 668/744 ice: fix PTP Call Trace during PTP release
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Greenwalt <[email protected]>
commit f6a7e00b81e35ef1325234925f2fe1e53b466f92 upstream.
If a PF reset occurs when the PTP state is ICE_PTP_UNINIT, then ice_ptp_rebuild() will update the state to ICE_PTP_ERROR. This will result in the following PTP release call trace during driver unload:
kernel BUG at lib/list_debug.c:52!
ice_ptp_release+0x332/0x3c0 [ice]
ice_deinit_features.part.0+0x10e/0x120 [ice]
ice_remove+0x100/0x220 [ice]This was observed when passing PF1 through to a VM. ice_ptp_init() fails because ctrl_pf is NULL and sets the state to ICE_PTP_UNINIT.
Fix by detecting the ICE_PTP_UNINIT state in ice_ptp_rebuild() and returning without error, preventing the invalid state transition to ICE_PTP_ERROR. The only valid path to ICE_PTP_ERROR is from ICE_PTP_RESETTING after a failed rebuild.
--- drivers/net/ethernet/intel/ice/ice_ptp.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/net/ethernet/intel/ice/ice_ptp.c +5 -0
@@ -3035,6 +3035,11 @@ void ice_ptp_rebuild(struct ice_pf *pf,struct ice_ptp *ptp = &pf->ptp;int err; +if (ptp->state ==ICE_PTP_UNINIT ) { +dev_dbg (ice_pf_to_dev (pf),"PTP was not initialized, skipping rebuild\n" ); +return ; + } +if (ptp->state ==ICE_PTP_READY ) {ice_ptp_prepare_for_reset (pf, reset_type); }else if (ptp->state !=ICE_PTP_RESETTING ) {
Greg Kroah-Hartman
maintainerPATCH 669/744 selftests/ftrace: Reset triggers at top level before instance loop
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
commit 1a087033a6bad73b4140020b40e819b0933aafc3 upstream.
When running instance tests, 'ftracetest' creates a new ftrace instance and runs the tests inside it. Before starting each test, it executes 'initialize_system()' to reset the ftrace state to initial-state.
However, since 'initialize_system()' is executed in the context of the instance directory, it only cleans up triggers and filters of that instance.
Any triggers or dynamic events left behind in the top-level instance by previous failed top-level tests, are left completely untouched. These top-level leftovers can cause subsequent instance-based tests to fail or even crash the kernel.
Fix this by executing 'initialize_system()' in the top-level tracing directory once before entering the instance loop.
--- tools/testing/selftests/ftrace/ftracetest | 1 + 1 file changed, 1 insertion(+)
tools/testing/selftests/ftrace/ftracetest +1 -0
@@ -503,6 +503,7 @@ for t in $TEST_CASES; do done # Test on instance loop +(cd $TRACING_DIR; initialize_system) INSTANCE=" (instance) " for t in $TEST_CASES; do test_on_instance $t || continue
Greg Kroah-Hartman
maintainerPATCH 670/744 super: fix emergency thaw deadlock on frozen block devices
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
commit 749d7aa0377aae32af8c0a4ad43371e7bf830ab5 upstream.
do_thaw_all_callback() calls bdev_thaw() while holding sb->s_umount exclusively. If the block device was frozen via bdev_freeze() dropping the last block layer freeze reference calls fs_bdev_thaw() which reacquires s_umount:
do_thaw_all_callback(sb)
super_lock_excl(sb) # holds sb->s_umount
bdev_thaw(sb->s_bdev)
mutex_lock(&bdev->bd_fsfreeze_mutex)
# bd_fsfreeze_count drops 1 -> 0
bd_holder_ops->thaw == fs_bdev_thaw
get_bdev_super(bdev)
bdev_super_lock(bdev, true)
super_lock(sb, true)
down_write(&sb->s_umount) # same task: deadlockThe emergency thaw worker deadlocks against itself holding both s_umount and bd_fsfreeze_mutex. That fscks any subsequent unmount, freeze, or thaw of that filesystem and block device.
[ 81.878470] sysrq: Show Blocked State [ 81.880140] task:kworker/0:1 state:D stack:0 pid:11 tgid:11 ppid:2 task_flags:0x4208060 flags:0x00080000 [ 81.884876] Workqueue: events do_thaw_all [ 81.886656] Call Trace: [ 81.887759] <TASK> [ 81.888763] __schedule+0x579/0x1420 [ 81.890372] schedule+0x3a/0x100 [ 81.891794] schedule_preempt_disabled+0x15/0x30 [ 81.893848] rwsem_down_write_slowpath+0x1ea/0x900 [ 81.895191] ? __pfx_do_thaw_all_callback+0x10/0x10 [ 81.896528] down_write+0xbd/0xc0 [ 81.897505] super_lock+0x91/0x180 [ 81.898457] ? __mutex_lock+0xa99/0x1140 [ 81.900748] ? __mutex_unlock_slowpath+0x1f/0x400 [ 81.902069] bdev_super_lock+0x5b/0x150 [ 81.903132] get_bdev_super+0x10/0x60 [ 81.904042] fs_bdev_thaw+0x23/0xf0 [ 81.904755] bdev_thaw+0x82/0x100 [ 81.905484] do_thaw_all_callback+0x2c/0x50 [ 81.906298] __iterate_supers+0x5d/0x130 [ 81.907067] do_thaw_all+0x20/0x40 [ 81.907739] process_one_work+0x206/0x5e0 [ 81.908545] worker_thread+0x1e2/0x3c0 [ 81.909339] ? __pfx_worker_thread+0x10/0x10 [ 81.910171] kthread+0xf4/0x130 [ 81.910799] ? __pfx_kthread+0x10/0x10 [ 81.911528] ret_from_fork+0x2e2/0x3b0 [ 81.912259] ? __pfx_kthread+0x10/0x10 [ 81.913010] ret_from_fork_asm+0x1a/0x30 [ 81.913806] </TASK>
bdev_super_lock() even documents the violated requirement with lockdep_assert_not_held(&sb->s_umount).
Acquiring bd_fsfreeze_mutex under s_umount also inverts the bd_fsfreeze_mutex vs. s_umount ordering established by bdev_{freeze,thaw}() and can thus ABBA against a concurrent block-layer freeze even when the recursive path isn't hit.
Fix this by not holding s_umount around the bdev_thaw() loop at all. Pin the superblock with an active reference instead as filesystems_freeze_callback() does. The active reference keeps the superblock from being shut down and so ->s_bdev stays valid without holding s_umount. The block-layer-held freeze is dropped by fs_bdev_thaw() with FREEZE_MAY_NEST | FREEZE_HOLDER_USERSPACE exactly as a regular unfreeze would and thaw_super_locked() handles filesystem-level freezes as before.
The emergency thaw path has deadlocked like this in one form or another for a long long time but the current exclusively-held shape dates back to commit [1] where thaw_bdev() already ended in thaw_super() with s_umount held by do_thaw_all_callback().
--- fs/super.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-)
fs/super.c +16 -13
@@ -1143,16 +1143,30 @@ void emergency_remount(void) } } +static inline bool get_active_super (struct super_block *sb) +{ +bool active = false; + +if (super_lock_excl (sb)) { + active =atomic_inc_not_zero (&sb->s_active); +super_unlock_excl (sb); + } +return active; +} +static void do_thaw_all_callback (struct super_block *sb,void *unused) { -if (!super_lock_excl (sb)) +if (!get_active_super (sb))return ; +/* fs_bdev_thaw() acquires s_umount so it must not be held here */ if (IS_ENABLED (CONFIG_BLOCK ))while (sb->s_bdev && !bdev_thaw (sb->s_bdev))pr_warn ("Emergency Thaw on %pg\n" , sb->s_bdev); -thaw_super_locked (sb,FREEZE_HOLDER_USERSPACE ,NULL ); +if (super_lock_excl (sb)) +thaw_super_locked (sb,FREEZE_HOLDER_USERSPACE ,NULL ); +deactivate_super (sb); }static void do_thaw_all (struct work_struct *work)
@@ -1178,17 +1192,6 @@ void emergency_thaw_all(void) } } -static inline bool get_active_super (struct super_block *sb) -{ -bool active = false; - -if (super_lock_excl (sb)) { - active =atomic_inc_not_zero (&sb->s_active); -super_unlock_excl (sb); - } -return active; -} -static const char *filesystems_freeze_ptr ="filesystems_freeze" ;static void filesystems_freeze_callback (struct super_block *sb,void *freeze_all_ptr)
Greg Kroah-Hartman
maintainerPATCH 671/744 rbd: Reset positive result codes to zero in object map update path
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Raphael Zimmer <[email protected]>
commit a6c4250b81bd30beae94e1b7a4b26fa1193ad2e4 upstream.
In a reply message to an RBD request, a positive result code indicates a data payload, which is not allowed for writes. While rbd_osd_req_callback() already resets a positive result code for writes to zero, rbd_object_map_callback() does not. This allows a corrupted reply to an object map update to trigger the rbd_assert(*result < 0) in __rbd_obj_handle_request(). This happens, because rbd_object_map_callback() calls rbd_obj_handle_request() -> __rbd_obj_handle_request() and passes this positive result code. From __rbd_obj_handle_request(), rbd_obj_advance_write() is called, which leaves the positive result code unchanged and returns true. Therefore, the if(done && *result) branch is executed in __rbd_obj_handle_request() and the assertion triggers.
This patch fixes the issue by adjusting the logic in the rbd_object_map_callback() path. A positive result code for an object map update is now reset to zero (similar to rbd_osd_req_callback()), and the message is subsequently handled the same way as if the result code was zero from the beginning. Additionally, a WARN_ON_ONCE() is added for this case.
--- drivers/block/rbd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/block/rbd.c +6 -1
@@ -1957,10 +1957,15 @@ static int rbd_object_map_update_finish(bool has_current_state;void *p; -if (osd_req->r_result) +if (osd_req->r_result <0 )return osd_req->r_result;/* +* Writes aren't allowed to return a data payload. +*/ +WARN_ON_ONCE (osd_req->r_result >0 ); + +/* * Nothing to do for a snapshot object map. */ if (osd_req->r_num_ops ==1 )
Greg Kroah-Hartman
maintainerPATCH 672/744 smb: client: handle STATUS_STOPPED_ON_SYMLINK responses without a symlink target
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carl Johnson <[email protected]>
commit 2eb74eef4b7eda8df593d22fb48e94ef959ec8a5 upstream.
The macOS built-in SMB server returns STATUS_STOPPED_ON_SYMLINK for a CREATE on a path whose final component is a symlink, but it does not include a Symbolic Link Error Response in the error data: both ErrorContextCount and ByteCount are zero, so the symlink target is not present in the response at all. Per [MS-SMB2] section 2.2.2 such a response should carry a valid Symbolic Link Error Response, so this is a server bug, but the target can still be retrieved with FSCTL_GET_REPARSE_POINT.
Frame from a capture against macOS 26.5.2 (build 25F84):
SMB2 hdr : Status=0x8000002d STATUS_STOPPED_ON_SYMLINK, Cmd=Create Error Rsp: StructureSize=0x0009
Error Context Count: 0
Byte Count: 0
Error Data: 00
symlink_data() cannot find a struct smb2_symlink_err_rsp in such a response and returns -EINVAL, which parse_create_response() propagates, so smb2_query_path_info() bails out at
if (rc || !data->reparse_point) goto out;
before it can retry with SMB2_OP_GET_REPARSE. stat(), readlink() and ls of any server-side symlink then fail with -EINVAL:
$ ls -la Config l????????? ? ? ? ? ? Config.json $ stat Config/Config.json stat: cannot statx 'Config/Config.json': Invalid argument
A 5.10 client resolves these symlinks correctly against the same server and share, so this is a regression for Apple SMB servers.
Handle it in several places:
- symlink_data() detects the empty response (ErrorContextCount and ByteCount both zero) and returns a distinct -ENODATA, so that "server did not send the target" can be told apart from a genuinely malformed response and only this case is worked around.
- parse_create_response() treats -ENODATA like STATUS_IO_REPARSE_TAG_NOT_HANDLED, which does not carry the target
either: leave the reparse tag unset and clear rc, so the existing SMB2_OP_GET_REPARSE path retrieves the target.
- smb2_query_path_info() only fixes up the symlink target type when the target is already known. SMB2_OP_GET_REPARSE sets data->reparse.tag but does not parse the target out of the reparse buffer; that happens later, in reparse_info_to_fattr(). Without this check smb2_fix_symlink_target_type() is called with a NULL target and returns -EIO. This could not happen with servers that send the target inline and therefore skip SMB2_OP_GET_REPARSE.
- smb2_open_file() maps -ENODATA to -EIO, matching STATUS_IO_REPARSE_TAG_NOT_HANDLED, so its callers retrieve the target with SMB2_OP_GET_REPARSE as well.
Tested on Debian 13, kernel 6.18.38 (armv7), against macOS 26.5.2:
symlinks now resolve, including relative, parent-traversing and directory symlinks, and reads through symlinks succeed.
--- fs/smb/client/smb2file.c | 21 +++++++++++++++++++++ fs/smb/client/smb2inode.c | 23 ++++++++++++++++++++--- 2 files changed, 41 insertions(+), 3 deletions(-)
fs/smb/client/smb2file.c +21 -0
@@ -30,6 +30,19 @@ static struct smb2_symlink_err_rsp *symlu8 *end = (u8 *)err + iov->iov_len;u32 len; +/* +* Per [MS-SMB2] section 2.2.2, a STATUS_STOPPED_ON_SYMLINK response has to +* carry a Symbolic Link Error Response, so ByteCount cannot be zero. Some +* servers (e.g. the macOS built-in SMB server) violate this and return an +* empty error response, with both ErrorContextCount and ByteCount set to +* zero, i.e. without the symlink target. Detect this and return -ENODATA +* so that callers can tell "server did not send the target" apart from a +* malformed response, and retrieve the target with FSCTL_GET_REPARSE_POINT +* instead. +*/ +if (!err->ErrorContextCount && !le32_to_cpu (err->ByteCount)) +return ERR_PTR (-ENODATA ); +if (err->ErrorContextCount) {struct smb2_error_context_rsp *p;
@@ -201,6 +214,14 @@ int smb2_open_file(const unsigned int xi rc =smb2_parse_symlink_response (oparms->cifs_sb, &err_iov, oparms->path, &data->symlink_target); +/* +* If smb2_parse_symlink_response returned -ENODATA then the +* symlink_target was not sent. Treat this as if the SMB2_open() +* failed with STATUS_IO_REPARSE_TAG_NOT_HANDLED status, which is +* indicated by the -EIO errno. +*/ +if (rc == -ENODATA ) + rc = -EIO ;if (!rc) {memset (smb2_data,0 ,sizeof (*smb2_data)); oparms->create_options |=OPEN_REPARSE_POINT ;
fs/smb/client/smb2inode.c +20 -3
@@ -792,9 +792,19 @@ static int parse_create_response(struct rc =smb2_parse_symlink_response (cifs_sb, iov, full_path, &data->symlink_target); -if (rc) +if (rc !=0 && rc != -ENODATA )return rc; - tag =IO_REPARSE_TAG_SYMLINK ; +/* +* -ENODATA means that the response was parsed but did not contain +* the symlink target at all (see symlink_data()). Treat it like +* STATUS_IO_REPARSE_TAG_NOT_HANDLED, which does not contain it +* either: leave the tag unset and clear rc, so that the caller +* retrieves the target with SMB2_OP_GET_REPARSE. +*/ +if (rc == -ENODATA ) + rc =0 ; +else + tag =IO_REPARSE_TAG_SYMLINK ; reparse_point = true;break ;case STATUS_SUCCESS :
@@ -987,7 +997,14 @@ int smb2_query_path_info(const unsigned rc = -EOPNOTSUPP ; } -if (data->reparse.tag ==IO_REPARSE_TAG_SYMLINK && !rc) { +/* +* If the symlink was already parsed in create response then it is needed to fix +* its type now (after the second call with OPEN_REPARSE_POINT which filled the +* data->fi.Attributes). If the symlink was not parsed in create response then +* the data->symlink_target was not filled yet and then the type will be fixed +* later after data->symlink_target is filled. +*/ +if (data->reparse.tag ==IO_REPARSE_TAG_SYMLINK && !rc && data->symlink_target) {bool directory =le32_to_cpu (data->fi.Attributes) &ATTR_DIRECTORY ; rc =smb2_fix_symlink_target_type (&data->symlink_target, directory, cifs_sb); }
Greg Kroah-Hartman
maintainerPATCH 673/744 ksmbd: defer destroy_previous_session() until after NTLM authentication
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Montgomery <[email protected]>
commit c74801ee524f477c174a1899782b6c3b6918d407 upstream.
In ntlm_authenticate(), destroy_previous_session() is called using a user pointer resolved from the client-supplied NTLM blob username field before the NTLMv2 response is validated. An authenticated attacker can set the NTLM blob username to match a victim account and set PreviousSessionId to the victim's session ID; destroy_previous_session() destroys the victim's session while ksmbd_decode_ntlmssp_auth_blob() subsequently rejects the request with -EPERM.
Move destroy_previous_session() and the prev_id assignment to after ksmbd_decode_ntlmssp_auth_blob() returns success and use sess->user rather than the pre-authentication lookup result. This matches the ordering already used by krb5_authenticate(), where destroy_previous_session() is called only after ksmbd_krb5_authenticate() returns success.
--- fs/smb/server/smb2pdu.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
fs/smb/server/smb2pdu.c +4 -5
@@ -1535,11 +1535,6 @@ static int ntlm_authenticate(struct ksmbreturn -EPERM ; } -/* Check for previous session */ - prev_id =le64_to_cpu (req->PreviousSessionId); -if (prev_id && prev_id != sess->id) -destroy_previous_session (conn, user, prev_id); -if (sess->state ==SMB2_SESSION_VALID ) {/* * Reuse session if anonymous try to connect
@@ -1579,6 +1574,10 @@ static int ntlm_authenticate(struct ksmb } } + prev_id =le64_to_cpu (req->PreviousSessionId); +if (prev_id && prev_id != sess->id) +destroy_previous_session (conn, sess->user, prev_id); +/* * If session state is SMB2_SESSION_VALID, We can assume * that it is reauthentication. And the user/password
Greg Kroah-Hartman
maintainerPATCH 674/744 ksmbd: validate minimum PDU size for transform requests
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
commit cfc0b8e5080aec87700774e8568765eaa4b7b92b upstream.
The receive path applies the minimum SMB2 PDU size check only when ProtocolId is SMB2_PROTO_NUMBER. A packet carrying SMB2_TRANSFORM_PROTO_NUM bypasses the check even when the negotiated dialect does not provide transform handling.
On an SMB 2.1 connection, a short transform packet therefore reaches init_smb2_rsp_hdr(), which interprets the request as a full SMB2 header and reads beyond the request allocation. The copied fields can then be returned to the unauthenticated client.
Compression transforms are converted to ordinary SMB2 messages before protocol validation. After that conversion, validate ordinary SMB2 requests against SMB2_MIN_SUPPORTED_PDU_SIZE and require encryption transform requests to contain both a transform header and an SMB2 header. This rejects truncated requests before work allocation.
--- fs/smb/server/connection.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
fs/smb/server/connection.c +11 -5
@@ -440,6 +440,8 @@ bool ksmbd_conn_alive(struct ksmbd_conn/* "+2" for BCC field (ByteCount, 2 bytes) */ #define SMB1_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb_hdr) + 2)#define SMB2_MIN_SUPPORTED_PDU_SIZE (sizeof(struct smb2_pdu)) +#define SMB2_TRANSFORM_MIN_SUPPORTED_PDU_SIZE \ + (sizeof(struct smb2_transform_hdr) + sizeof(struct smb2_hdr))/** * ksmbd_conn_handler_loop() - session thread to listen on new smb requests
@@ -454,6 +456,7 @@ int ksmbd_conn_handler_loop(void *p)struct ksmbd_conn *conn = (struct ksmbd_conn *)p;struct ksmbd_transport *t = conn->transport;unsigned int pdu_size, max_allowed_pdu_size, max_req; +__le32 proto;char hdr_buf[4 ] = {0 ,};int size;
@@ -534,11 +537,14 @@ recheck:if (!ksmbd_smb_request (conn))break ; -if (((struct smb2_hdr *)smb_get_msg (conn->request_buf))->ProtocolId == -SMB2_PROTO_NUMBER ) { -if (pdu_size <SMB2_MIN_SUPPORTED_PDU_SIZE ) -break ; - } + proto = *(__le32 *)smb_get_msg (conn->request_buf); +if (proto ==SMB2_PROTO_NUMBER && + pdu_size <SMB2_MIN_SUPPORTED_PDU_SIZE ) +break ; + +if (proto ==SMB2_TRANSFORM_PROTO_NUM && + pdu_size <SMB2_TRANSFORM_MIN_SUPPORTED_PDU_SIZE ) +break ;if (!default_conn_ops.process_fn) {pr_err ("No connection request callback\n" );
Greg Kroah-Hartman
maintainerPATCH 675/744 gve: fix Rx queue stall on alloc failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eddie Phillips <[email protected]>
commit b65352a1bac64442ad95e64f385b40ccb9f1b0db upstream.
When the system is under extreme memory pressure, page allocations can fail during the Rx buffer refill loop. If the number of buffers posted to hardware falls below a critical low threshold and the refill loop exits due to allocation failures, the queue can stall:
1. The device drops incoming packets because there are no descriptors.
2. Since no packets are processed, no Rx completions are generated.
3. Because no completions occur, NAPI is never scheduled, preventing the refill loop from running again even after memory is freed.
This results in a permanent queue stall.
Resolve this by introducing a starvation recovery timer for each Rx queue. If the number of buffers posted to hardware falls below a critical low threshold, start a timer to periodically reschedule NAPI. Once NAPI runs and successfully refills the queue above the threshold, the timer is not rescheduled.
The threshold is set to 32 because a single maximum-sized Receive Segment Coalescing (RSC) packet can consume up to 19 descriptors in the Rx path. Lower thresholds (such as 8 or 16) would be insufficient to process a complete maximum-sized RSC packet, risking packet drops or unexpected hardware behavior under memory pressure. Setting the threshold to 32 guarantees a safe margin to handle at least one full RSC packet.
--- drivers/net/ethernet/google/gve/gve.h | 3 ++ drivers/net/ethernet/google/gve/gve_rx_dqo.c | 34 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+)
drivers/net/ethernet/google/gve/gve.h +3 -0
@@ -13,6 +13,7 @@#include <linux/netdevice.h> #include <linux/net_tstamp.h> #include <linux/pci.h> +#include <linux/timer.h> #include <linux/ptp_clock_kernel.h> #include <linux/u64_stats_sync.h> #include <net/page_pool/helpers.h>
@@ -41,6 +42,7 @@/* Interval to schedule a stats report update, 20000ms. */ #define GVE_STATS_REPORT_TIMER_PERIOD 20000 +#define GVE_RX_NAPI_RESCHED_MS 20/* msecs */ /* Numbers of NIC tx/rx stats in stats report. */ #define NIC_TX_STATS_REPORT_NUM 0
@@ -341,6 +343,7 @@ struct gve_rx_ring {struct xdp_rxq_info xdp_rxq;struct xsk_buff_pool *xsk_pool;struct page_frag_cache page_cache;/* Page cache to allocate XDP frames */ +struct timer_list starvation_timer;/* for queue starvation recovery */ };/* A TX desc ring entry */
drivers/net/ethernet/google/gve/gve_rx_dqo.c +34 -0
@@ -18,6 +18,16 @@#include <net/tcp.h> #include <net/xdp_sock_drv.h> +static void gve_rx_starvation_timer (struct timer_list *t) +{ +struct gve_rx_ring *rx =timer_container_of (rx, t, starvation_timer); +struct gve_priv *priv = rx->gve; +struct gve_notify_block *block; + + block = &priv->ntfy_blocks[rx->ntfy_id]; +napi_schedule (&block->napi); +} +static void gve_rx_free_hdr_bufs (struct gve_priv *priv,struct gve_rx_ring *rx) {struct device *hdev = &priv->pdev->dev;
@@ -120,6 +130,7 @@ void gve_rx_stop_ring_dqo(struct gve_priif (rx->dqo.page_pool)page_pool_disable_direct_recycling (rx->dqo.page_pool); +timer_shutdown_sync (&rx->starvation_timer);gve_remove_napi (priv, ntfy_idx);gve_rx_remove_from_block (priv, idx);gve_rx_reset_ring_dqo (priv, idx);
@@ -208,8 +219,10 @@ static int gve_rx_alloc_hdr_bufs(structvoid gve_rx_start_ring_dqo (struct gve_priv *priv,int idx) {int ntfy_idx =gve_rx_idx_to_ntfy (priv, idx); +struct gve_rx_ring *rx = &priv->rx[idx];gve_rx_add_to_block (priv, idx); +timer_setup (&rx->starvation_timer, gve_rx_starvation_timer,0 );gve_add_napi (priv, ntfy_idx, gve_napi_poll_dqo); }
@@ -365,6 +378,7 @@ void gve_rx_post_buffers_dqo(struct gve_struct gve_rx_compl_queue_dqo *complq = &rx->dqo.complq;struct gve_rx_buf_queue_dqo *bufq = &rx->dqo.bufq;struct gve_priv *priv = rx->gve; +u32 num_bufs_avail_to_hw;u32 num_avail_slots;u32 num_full_slots;u32 num_posted =0 ;
@@ -400,6 +414,26 @@ void gve_rx_post_buffers_dqo(struct gve_ } rx->fill_cnt += num_posted; + +/* If the queue has fewer than GVE_RX_BUF_THRESH_DQO descriptors +* visible to the hardware, the hardware is in danger of starving +* and cannot trigger interrupts. +* +* We use a threshold of 32 because a single maximum-sized RSC +* packet can consume up to 19 descriptors in the Rx path. Lower +* thresholds (e.g., 8 or 16) would be unsafe as they could cause +* the device to drop/stall on a maximum-sized RSC packet. +* +* Start the timer to periodically reschedule NAPI and recover. +*/ + num_bufs_avail_to_hw = + ((bufq->tail & ~(GVE_RX_BUF_THRESH_DQO -1 )) - + bufq->head) & bufq->mask; + +if (num_bufs_avail_to_hw <GVE_RX_BUF_THRESH_DQO ) { +mod_timer (&rx->starvation_timer, + jiffies +msecs_to_jiffies (GVE_RX_NAPI_RESCHED_MS )); + } } static void gve_rx_skb_csum(struct sk_buff *skb,
Greg Kroah-Hartman
maintainerPATCH 676/744 ice: reject out-of-range ptype in ice_parser_profile_init
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksandr Loktionov <[email protected]>
commit 59abb87159c53605c063f6e2ceb215b5eba43ee6 upstream.
set_bit(rslt->ptype, prof->ptypes) operates on a DECLARE_BITMAP of ICE_FLOW_PTYPE_MAX (1024) bits. Nothing prevents a malicious VF from providing ptype >= 1024 through VIRTCHNL, resulting in a write past the end of the bitmap and a kernel page fault.
Reproduced with a custom kernel module injecting a crafted VIRTCHNL_OP_ADD_RSS_CFG on E810-C QSFP (8086:1592), FW 4.91 0x800214af 1.3909.0, ICE COMMS DDP 1.3.53.0, kernel 7.1.0-rc1.
crash_parser: ice_parser_profile_init @ ffffffffc0d61b60crash_parser: setting ptype=0xffff (max valid=1023)crash_parser: calling ice_parser_profile_init -- expect OOB crash!
BUG: kernel NULL pointer dereference, address: 0000000000000000 Oops: Oops: 0002 [#1] SMP NOPTI CPU: 56 UID: 0 PID: 165011 Comm: insmod Kdump: loaded Tainted: G S U OE 7.1.0-rc1 #1 Hardware name: Intel Corporation S2600BPB/S2600BPB RIP: 0010:ice_parser_profile_init+0x2d/0x1d0 [ice] Call Trace: <TASK> ? __pfx_ice_parser_profile_init+0x10/0x10 [ice] crash_init+0x127/0xff0 [crash_parser] do_one_initcall+0x45/0x310 do_init_module+0x64/0x270 init_module_from_file+0xcc/0xf0 idempotent_init_module+0x17b/0x280 __x64_sys_finit_module+0x6e/0xe0
Bail out early with -EINVAL when ptype is out of range.
--- drivers/net/ethernet/intel/ice/ice_parser.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/ethernet/intel/ice/ice_parser.c +3 -0
@@ -2368,6 +2368,9 @@ int ice_parser_profile_init(struct ice_pu16 proto_off =0 ;u16 off; +if (rslt->ptype >=ICE_FLOW_PTYPE_MAX ) +return -EINVAL ; +memset (prof,0 ,sizeof (*prof));set_bit (rslt->ptype, prof->ptypes);if (blk ==ICE_BLK_SW ) {
Hi
kernel build / boot test on x86_64 (Intel).
No regressions here.
Thanks
Greg Kroah-Hartman
maintainerPATCH 677/744 ice: use READ_ONCE() to access cached PHC time
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sergey Temerkhanov <[email protected]>
commit 2915681b89f817677ab9f1166d95b595bc144f5f upstream.
ptp.cached_phc_time is a 64-bit value updated by a periodic work item on one CPU and read locklessly on another. On 32-bit or non-atomic architectures this can result in a torn read. Use READ_ONCE() to enforce a single atomic load.
--- drivers/net/ethernet/intel/ice/ice_ptp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/intel/ice/ice_ptp.c +1 -1
@@ -350,7 +350,7 @@ static u64 ice_ptp_extend_40b_ts(structreturn 0 ; } -return ice_ptp_extend_32b_ts (pf->ptp.cached_phc_time, +return ice_ptp_extend_32b_ts (READ_ONCE (pf->ptp.cached_phc_time), (in_tstamp >>8 ) & mask); }
Greg Kroah-Hartman
maintainerPATCH 678/744 ila: reload IPv6 header after pskb_may_pull in checksum adjust
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 92d3817649df2b0b6a008a686c8275c88d7ef594 upstream.
ila_csum_adjust_transport() caches ip6h = ipv6_hdr(skb) before calling pskb_may_pull(). On a non-linear skb whose transport header sits in a page fragment, pskb_may_pull() can call __pskb_pull_tail() / pskb_expand_head() and free the old skb head, leaving ip6h dangling; the following get_csum_diff(ip6h, p) then reads freed memory. ila_update_ipv6_locator() uses ip6h (and the iaddr derived from it) again after the csum-adjust call and additionally writes the new locator through that pointer.
Impact: a remote IPv6 packet routed through a configured ILA csum-adjust-transport route or receive-side mapping triggers a slab-use-after-free in ila_update_ipv6_locator() (KASAN). The route or mapping requires CAP_NET_ADMIN to configure, but trigger packets are unauthenticated once it exists.
Reload ip6h after each pskb_may_pull() in ila_csum_adjust_transport() before the csum-diff read. In ila_update_ipv6_locator() only the ILA_CSUM_ADJUST_TRANSPORT case pulls the skb, so reload ip6h and iaddr in that case alone before the destination-address write; the neutral-map modes never pull and keep their cached pointers.
--- net/ipv6/ila/ila_common.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
net/ipv6/ila/ila_common.c +12 -0
@@ -85,6 +85,7 @@ static void ila_csum_adjust_transport(ststruct tcphdr *th = (struct tcphdr *) (skb_network_header (skb) + nhoff); + ip6h =ipv6_hdr (skb); diff =get_csum_diff (ip6h, p);inet_proto_csum_replace_by_diff (&th->check, skb, diff, true, true);
@@ -96,6 +97,7 @@ static void ila_csum_adjust_transport(st (skb_network_header (skb) + nhoff);if (uh->check || skb->ip_summed ==CHECKSUM_PARTIAL ) { + ip6h =ipv6_hdr (skb); diff =get_csum_diff (ip6h, p);inet_proto_csum_replace_by_diff (&uh->check, skb, diff, true, true);
@@ -110,6 +112,7 @@ static void ila_csum_adjust_transport(ststruct icmp6hdr *ih = (struct icmp6hdr *) (skb_network_header (skb) + nhoff); + ip6h =ipv6_hdr (skb); diff =get_csum_diff (ip6h, p);inet_proto_csum_replace_by_diff (&ih->icmp6_cksum, skb, diff, true, true);
@@ -127,6 +130,15 @@ void ila_update_ipv6_locator(struct sk_bswitch (p->csum_mode) {case ILA_CSUM_ADJUST_TRANSPORT :ila_csum_adjust_transport (skb, p); +/* +* ila_csum_adjust_transport() calls pskb_may_pull(), which can +* reallocate the skb head and leave ip6h (and the iaddr derived +* from it) dangling; reload both before the write below. The +* other csum modes do not pull, so their cached pointers stay +* valid. +*/ + ip6h =ipv6_hdr (skb); + iaddr =ila_a2i (&ip6h->daddr);break ;case ILA_CSUM_NEUTRAL_MAP :if (sir2ila) {
Greg Kroah-Hartman
maintainerPATCH 679/744 mac802154: hold an interface reference across the scan worker
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ibrahim Hashimov <[email protected]>
commit 234e5e898b713bc0b3a631b6f002897f43d046c8 upstream.
mac802154_scan_worker() captures the scanning sub-interface under RCU and then keeps dereferencing sdata->dev after rcu_read_unlock() and outside the rtnl -- in the failure traces, in mac802154_transmit_beacon_req() (skb->dev = sdata->dev), and in the end_scan cleanup. Nothing keeps that netdev alive across the worker iteration.
A concurrent DEL_INTERFACE or PHY removal can unregister the interface once the worker drops the rtnl between its two drv_set_channel() sections. unregister_netdevice() frees the netdev asynchronously from netdev_run_todo() with the rtnl already dropped, so neither holding the rtnl nor the per-PHY IEEE802154_IS_SCANNING flag prevents a stale worker iteration from dereferencing the freed netdev -- a KASAN slab-use-after-free, reachable by racing TRIGGER_SCAN against DEL_INTERFACE (both CAP_NET_ADMIN).
Pin the netdev with netdev_hold() while the RCU read lock is still held, and release it at every worker exit.
--- net/mac802154/scan.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
net/mac802154/scan.c +11 -0
@@ -179,6 +179,7 @@ void mac802154_scan_worker(struct work_senum nl802154_scan_types scan_req_type;struct ieee802154_sub_if_data *sdata;unsigned int scan_duration =0 ; +netdevice_tracker dev_tracker;struct wpan_phy *wpan_phy;u8 scan_req_duration;u8 page, channel;
@@ -209,6 +210,14 @@ void mac802154_scan_worker(struct work_sreturn ; } +/* +* sdata->dev is dereferenced below after rcu_read_unlock() and outside +* the rtnl, and a concurrent DEL_INTERFACE / PHY teardown can free it +* asynchronously from netdev_run_todo(). Pin it with a reference taken +* while the RCU read lock is still held, and drop it at every exit. +*/ +netdev_hold (sdata->dev, &dev_tracker,GFP_ATOMIC ); + wpan_phy = scan_req->wpan_phy; scan_req_type = scan_req->type; scan_req_duration = scan_req->duration;
@@ -262,12 +271,14 @@ void mac802154_scan_worker(struct work_s"Scan page %u channel %u for %ums\n" , page, channel, jiffies_to_msecs(scan_duration));queue_delayed_work (local->mac_wq, &local->scan_work, scan_duration); +netdev_put (sdata->dev, &dev_tracker);return ; end_scan:rtnl_lock ();mac802154_scan_cleanup_locked (local, sdata, false);rtnl_unlock (); +netdev_put (sdata->dev, &dev_tracker); } int mac802154_trigger_scan_locked(struct ieee802154_sub_if_data *sdata,
Greg Kroah-Hartman
maintainerPATCH 680/744 mac802154: llsec: reject frames shorter than the authentication tag
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Doruk Tan Ozturk <[email protected]>
commit fd3a3f28ed60c6af4b2a39933b151d6b27842c3b upstream.
llsec_do_decrypt_auth() computes the associated-data length for the AEAD request as
assoclen += datalen - authlen;
where datalen is the number of bytes after the MAC header and authlen (4, 8 or 16) is the length of the authentication tag. Nothing verifies that the frame actually carries at least authlen payload bytes. A secured frame whose payload is shorter than the tag makes datalen - authlen negative; assoclen is then passed to aead_request_set_ad() as an unsigned value close to 4 GiB, so crypto_aead_decrypt() walks far off the end of the scatterlist that only spans the real frame.
The frame is fully attacker-controlled and reaches this path from any IEEE 802.15.4 peer in radio range. Reject frames whose payload is shorter than the authentication tag before the subtraction.
Dynamically reproduced on a KASAN kernel as a general-protection-fault in the AEAD scatterwalk, and the fix confirmed.
--- net/mac802154/llsec.c | 5 +++++ 1 file changed, 5 insertions(+)
net/mac802154/llsec.c +5 -0
@@ -891,6 +891,11 @@ llsec_do_decrypt_auth(struct sk_buff *sk data =skb_mac_header (skb) + skb->mac_len; datalen =skb_tail_pointer (skb) - data; +if (datalen < authlen) { +kfree_sensitive (req); +return -EBADMSG ; + } +sg_init_one (&sg,skb_mac_header (skb), assoclen + datalen);if (!(hdr->sec.level &IEEE802154_SCF_SECLEVEL_ENC )) {
Greg Kroah-Hartman
maintainerPATCH 681/744 mctp: serial: handle zero-length frames to prevent rx buffer overflow
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Doruk Tan Ozturk <[email protected]>
commit 793b9b729f1e8de57be8c8daf1a9838be96cabed upstream.
The MCTP serial receive state machine reads a frame length byte in mctp_serial_push_header() case 2 and validates it upper-bound-only:
if (c > MCTP_SERIAL_FRAME_MTU) {
dev->rxstate = STATE_ERR;
} else {
dev->rxlen = c;
dev->rxpos = 0;
dev->rxstate = STATE_DATA;
...
}A length of zero passes this check, so rxlen is set to 0 and the state machine advances to STATE_DATA. In mctp_serial_push() STATE_DATA, the incoming byte is stored and rxpos incremented before the terminator is tested:
dev->rxbuf[dev->rxpos] = c;
dev->rxpos++;
dev->rxstate = STATE_DATA;
if (dev->rxpos == dev->rxlen) {
dev->rxpos = 0;
dev->rxstate = STATE_TRAILER;
}With rxlen == 0 the "rxpos == rxlen" terminator can never fire (rxpos is already 1 on the first data byte), so subsequent bytes are written past the end of the fixed 74-byte rxbuf, which is the last member of the netdev private area. Every following data byte is an attacker-controlled 1-byte out-of-bounds heap write, and the overflow continues until a frame (0x7e) or escape byte resets the parser -- effectively unbounded.
Reaching this requires CAP_NET_ADMIN to attach the N_MCTP line discipline and bring the resulting mctpserialN netdev up, after which the bytes arrive via the tty receive path.
Route a zero-length frame straight to STATE_TRAILER instead of STATE_DATA. The trailer/framing bytes are still consumed, and the frame resolves to a zero-length skb that the MCTP core rejects; the parser never enters STATE_DATA with rxlen == 0, so the out-of-bounds write can no longer occur.
KASAN, on a frame of 0x7e 0x01 0x00 followed by data bytes (before this change):
UBSAN: array-index-out-of-bounds in drivers/net/mctp/mctp-serial.c:370 index 74 is out of range for type 'u8 [74]' BUG: KASAN: slab-out-of-bounds in mctp_serial_tty_receive_buf Write of size 1 at addr ... by task kworker/u16:0 mctp_serial_tty_receive_buf tty_ldisc_receive_buf flush_to_ldisc Allocated by task 152: alloc_netdev_mqs mctp_serial_open
v2: route zero-length frames to STATE_TRAILER instead of STATE_ERR so
the trailer/framing bytes are still consumed (Jeremy Kerr).
Found by 0sec automated security-research tooling (https://0sec.ai).
--- drivers/net/mctp/mctp-serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/mctp/mctp-serial.c +1 -1
@@ -318,7 +318,7 @@ static void mctp_serial_push_header(stru }else { dev->rxlen = c; dev->rxpos =0 ; - dev->rxstate =STATE_DATA ; + dev->rxstate = c >0 ?STATE_DATA :STATE_TRAILER ; dev->rxfcs =crc_ccitt_byte (dev->rxfcs, c); }break ;
Greg Kroah-Hartman
maintainerPATCH 682/744 openvswitch: fix GSO userspace truncation underflow
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kyle Zeng <[email protected]>
commit 4032f8ed10fcb84d41c508dfb04be96589f78dfe upstream.
OVS_ACTION_ATTR_TRUNC currently stores a delta from the original skb length in OVS_CB(skb)->cutlen. When a later userspace action segments a GSO skb, queue_gso_packets() reuses that delta for each smaller segment. A segment can then reach queue_userspace_packet() with cutlen greater than skb->len, underflowing the length passed to skb_zerocopy().
Store the maximum preserved length instead and bound each consumer against the current skb length. Use U32_MAX as the no-truncation sentinel so the value remains valid if skb geometry changes before a consumer handles it.
--- net/openvswitch/actions.c | 19 +++++++------------ net/openvswitch/datapath.c | 25 ++++++++++++++----------- net/openvswitch/datapath.h | 2 +- net/openvswitch/vport.c | 2 +- 4 files changed, 23 insertions(+), 25 deletions(-)
net/openvswitch/actions.c +7 -12
@@ -837,12 +837,8 @@ static void do_output(struct datapath *du16 mru =OVS_CB (skb)->mru;u32 cutlen =OVS_CB (skb)->cutlen; -if (unlikely (cutlen >0 )) { -if (skb->len - cutlen >ovs_mac_header_len (key)) -pskb_trim (skb, skb->len - cutlen); -else -pskb_trim (skb,ovs_mac_header_len (key)); - } +if (unlikely (cutlen < skb->len)) +pskb_trim (skb,max (cutlen,ovs_mac_header_len (key)));if (likely (!mru || (skb->len <= mru + vport->dev->hard_header_len))) {
@@ -1234,7 +1230,7 @@ static void execute_psample(struct datap psample_group.net =ovs_dp_get_net (dp); md.in_ifindex =OVS_CB (skb)->input_vport->dev->ifindex; - md.trunc_size = skb->len -OVS_CB (skb)->cutlen; + md.trunc_size =min (skb->len,OVS_CB (skb)->cutlen); md.rate_as_probability =1 ; rate =OVS_CB (skb)->probability ?OVS_CB (skb)->probability :U32_MAX ;
@@ -1284,22 +1280,21 @@ static int do_execute_actions(struct dat clone =skb_clone (skb,GFP_ATOMIC );if (clone)do_output (dp, clone, port, key); -OVS_CB (skb)->cutlen =0 ; +OVS_CB (skb)->cutlen =U32_MAX ;break ; }case OVS_ACTION_ATTR_TRUNC : {struct ovs_action_trunc *trunc =nla_data (a); -if (skb->len > trunc->max_len) -OVS_CB (skb)->cutlen = skb->len - trunc->max_len; +OVS_CB (skb)->cutlen = trunc->max_len;break ; }case OVS_ACTION_ATTR_USERSPACE :output_userspace (dp, skb, key, a, attr, len,OVS_CB (skb)->cutlen); -OVS_CB (skb)->cutlen =0 ; +OVS_CB (skb)->cutlen =U32_MAX ;if (nla_is_last (a, rem)) {consume_skb (skb);return 0 ;
@@ -1453,7 +1448,7 @@ static int do_execute_actions(struct datcase OVS_ACTION_ATTR_PSAMPLE :execute_psample (dp, skb, a); -OVS_CB (skb)->cutlen =0 ; +OVS_CB (skb)->cutlen =U32_MAX ;if (nla_is_last (a, rem)) {consume_skb (skb);return 0 ;
net/openvswitch/datapath.c +14 -11
@@ -276,7 +276,7 @@ void ovs_dp_process_packet(struct sk_buf upcall.portid =ovs_vport_find_upcall_portid (p, skb); upcall.mru =OVS_CB (skb)->mru; - error =ovs_dp_upcall (dp, skb, key, &upcall,0 ); + error =ovs_dp_upcall (dp, skb, key, &upcall,U32_MAX );switch (error) {case 0 :case -EAGAIN :
@@ -457,7 +457,8 @@ static int queue_userspace_packet(structstruct sk_buff *nskb =NULL ;struct sk_buff *user_skb =NULL ;/* to be queued to userspace */ struct nlattr *nla; -size_t len; +size_t msg_size; +size_t skb_len;unsigned int hlen;int err, dp_ifindex;u64 hash;
@@ -478,7 +479,8 @@ static int queue_userspace_packet(struct skb = nskb; } -if (nla_attr_size (skb->len) >USHRT_MAX ) { + skb_len =min (skb->len, cutlen); +if (nla_attr_size (skb_len) >USHRT_MAX ) { err = -EFBIG ; goto out; }
@@ -493,13 +495,13 @@ static int queue_userspace_packet(struct* padding logic. Only perform zerocopy if padding is not required. */ if (dp->user_features &OVS_DP_F_UNALIGNED ) - hlen =skb_zerocopy_headlen (skb); + hlen =min (skb_zerocopy_headlen (skb), cutlen);else - hlen = skb->len; + hlen = skb_len; - len =upcall_msg_size (upcall_info, hlen - cutlen, -OVS_CB (skb)->acts_origlen); - user_skb =genlmsg_new (len,GFP_ATOMIC ); + msg_size =upcall_msg_size (upcall_info, hlen, +OVS_CB (skb)->acts_origlen); + user_skb =genlmsg_new (msg_size,GFP_ATOMIC );if (!user_skb) { err = -ENOMEM ; goto out;
@@ -560,7 +562,7 @@ static int queue_userspace_packet(struct }/* Add OVS_PACKET_ATTR_LEN when packet is truncated */ -if (cutlen >0 && +if (skb_len < skb->len &&nla_put_u32 (user_skb,OVS_PACKET_ATTR_LEN , skb->len)) { err = -ENOBUFS ; goto out;
@@ -585,9 +587,9 @@ static int queue_userspace_packet(struct err = -ENOBUFS ; goto out; } - nla->nla_len =nla_attr_size (skb->len - cutlen); + nla->nla_len =nla_attr_size (skb_len); - err =skb_zerocopy (user_skb, skb, skb->len - cutlen, hlen); + err =skb_zerocopy (user_skb, skb, skb_len, hlen);if (err) goto out;
@@ -644,6 +646,7 @@ static int ovs_packet_cmd_execute(struct packet->ignore_df =1 ; }OVS_CB (packet)->mru = mru; +OVS_CB (packet)->cutlen =U32_MAX ;if (a[OVS_PACKET_ATTR_HASH ]) { hash =nla_get_u64 (a[OVS_PACKET_ATTR_HASH ]);
net/openvswitch/datapath.h +1 -1
@@ -118,7 +118,7 @@ struct datapath {* @mru: The maximum received fragement size; 0 if the packet is not * fragmented. * @acts_origlen: The netlink size of the flow actions applied to this skb. -* @cutlen: The number of bytes from the packet end to be removed. +* @cutlen: The number of bytes in the packet to preserve on output. * @probability: The sampling probability that was applied to this skb; 0 means * no sampling has occurred; U32_MAX means 100% probability. * @upcall_pid: Netlink socket PID to use for sending this packet to userspace;
net/openvswitch/vport.c +1 -1
@@ -502,7 +502,7 @@ int ovs_vport_receive(struct vport *vporOVS_CB (skb)->input_vport = vport;OVS_CB (skb)->mru =0 ; -OVS_CB (skb)->cutlen =0 ; +OVS_CB (skb)->cutlen =U32_MAX ;OVS_CB (skb)->probability =0 ;OVS_CB (skb)->upcall_pid =0 ;if (unlikely (dev_net (skb->dev) !=ovs_dp_get_net (vport->dp))) {
Greg Kroah-Hartman
maintainerPATCH 683/744 ovpn: fix peer refcount leak in TCP error paths
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavitra Jha <[email protected]>
commit 63bbe18fc03062f483c627838a566a707b62da79 upstream.
When either the TCP RX or TX error path calls ovpn_peer_hold() followed by schedule_work(&peer->tcp.defer_del_work), and the work item is already pending from the other path, schedule_work() returns false and the work runs only once. Since ovpn_tcp_peer_del_work() calls ovpn_peer_put() exactly once, the extra reference taken by the losing path is never dropped, leaking the peer object.
The race window:
CPU0 (strparser/RX error): CPU1 (tcp_tx_work/TX error):
ovpn_peer_hold() <- refcnt+1 ovpn_peer_hold() <- refcnt+2
schedule_work() <- queued schedule_work() <- NO-OP
(work already pending)
ovpn_tcp_peer_del_work runs:
ovpn_peer_del()
ovpn_peer_put() <- refcnt+1
<- peer never freedFix by checking the return value of schedule_work() in both paths and calling ovpn_peer_put() to drop the extra reference if the work was already pending. ovpn_peer_hold() is kept unconditional in the TX path as it cannot fail at that point.
--- drivers/net/ovpn/tcp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/ovpn/tcp.c +4 -2
@@ -151,7 +151,8 @@ err:/* take reference for deferred peer deletion. should never fail */ if (WARN_ON (!ovpn_peer_hold (peer))) goto err_nopeer; -schedule_work (&peer->tcp.defer_del_work); +if (!schedule_work (&peer->tcp.defer_del_work)) +ovpn_peer_put (peer);ovpn_dev_dstats_rx_dropped (peer->ovpn->dev); err_nopeer:kfree_skb (skb);
@@ -283,7 +284,8 @@ static void ovpn_tcp_send_sock(struct ov* stream therefore we abort the connection */ ovpn_peer_hold (peer); -schedule_work (&peer->tcp.defer_del_work); +if (!schedule_work (&peer->tcp.defer_del_work)) +ovpn_peer_put (peer);/* we bail out immediately and keep tx_in_progress set * to true. This way we prevent more TX attempts
Greg Kroah-Hartman
maintainerPATCH 684/744 ovpn: hold peer before scheduling keepalive work
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuvam Pandey <[email protected]>
commit a4710ae2e7e322fdaefb4be8604228279cfaf48c upstream.
ovpn_peer_keepalive_send() passes its peer reference to ovpn_xmit_special(), which ultimately drops it. The keepalive scheduler currently queues the work first and takes the reference only after schedule_work() reports that the work was queued.
Once schedule_work() queues the item, another CPU may run the worker before the caller gets to ovpn_peer_hold(). In that case the worker can consume a reference that was not acquired for it, corrupting the peer lifetime accounting.
Take the peer reference before queueing the work and drop it again when the work was already pending.
--- drivers/net/ovpn/peer.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/ovpn/peer.c +4 -2
@@ -1285,8 +1285,10 @@ static time64_t ovpn_peer_keepalive_worknetdev_dbg (peer->ovpn->dev,"sending keepalive to peer %u\n" , peer->id); -if (schedule_work (&peer->keepalive_work)) -ovpn_peer_hold (peer); +if (WARN_ON (!ovpn_peer_hold (peer))) +return 0 ; +if (!schedule_work (&peer->keepalive_work)) +ovpn_peer_put (peer); }if (next_run1 < next_run2)
Greg Kroah-Hartman
maintainerPATCH 685/744 pppoe: reload header pointer after dev_hard_header()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asim Viladi Oglu Manizada <[email protected]>
commit e9c238f6fe42fb1b4dba3a578277de32cb487937 upstream.
pppoe_sendmsg() saves a pointer to the PPPoE header before calling dev_hard_header(). Device header callbacks are allowed to reallocate the skb head, invalidating pointers into it.
This can happen when a send is blocked in copy_from_user() while the first non-Ethernet port is added to an empty team device. The team's delegated GRE header callback then expands the skb head. PPPoE subsequently writes six bytes through the stale pointer into the freed head.
Reload the PPPoE header through the skb's network-header offset after device header creation. pskb_expand_head() updates that offset when it relocates the head.
--- drivers/net/ppp/pppoe.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ppp/pppoe.c +1 -0
@@ -824,6 +824,7 @@ static int pppoe_sendmsg(struct socket *dev_hard_header (skb, dev,ETH_P_PPP_SES , po->pppoe_pa.remote,NULL , total_len); + ph =pppoe_hdr (skb);memcpy (ph, &hdr,sizeof (struct pppoe_hdr )); ph->length =htons (total_len);
Greg Kroah-Hartman
maintainerPATCH 686/744 rtase: Workaround for TX hang caused by hardware packet parsing
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Justin Lai <[email protected]>
commit 1c50efa1faf3a1a96e100b07ec7a2f3164d90bee upstream.
The hardware performs packet parsing before packet transmission. Parsing incomplete IPv4, IPv6, TCP, or UDP headers may trigger a TX hang because the hardware parser expects additional protocol header data that is not present in the packet.
The hardware performs additional PTP parsing on UDP packets identified by destination ports 319/320 at the expected UDP destination port offset.
If such a packet has transport data smaller than RTASE_MIN_PAD_LEN, the hardware parser expects additional packet data and may trigger a TX hang.
To avoid these hardware issues, the driver applies the following workarounds.
Drop malformed packets that may trigger this hardware issue before transmission.
For IPv4 non-initial fragments, the hardware does not check the fragment offset before parsing the expected transport header location. As a result, these packets are still subject to transport header parsing even though they do not contain a transport header. If the transport data is shorter than the minimum transport header required by the hardware parser, pad the transport data to the minimum transport header length required by the hardware parser. Packets that also match the hardware PTP parsing conditions continue to follow the corresponding workaround.
For IPv6 fragmented packets, neither of the above hardware issues occurs because the hardware only continues packet parsing when the IPv6 Base Header Next Header field directly indicates UDP. Packets carrying a Fragment Header do not continue through the subsequent packet parsing stages.
For packets identified for hardware PTP parsing, pad the transport data so it reaches RTASE_MIN_PAD_LEN before transmission.
--- drivers/net/ethernet/realtek/rtase/rtase.h | 8 drivers/net/ethernet/realtek/rtase/rtase_main.c | 197 ++++++++++++++++++++++++ 2 files changed, 205 insertions(+)
drivers/net/ethernet/realtek/rtase/rtase.h +8 -0
@@ -188,6 +188,12 @@ enum rtase_sw_flag_content { RTASE_SWF_MSIX_ENABLED = BIT(2), }; +enum rtase_parse_result { +RTASE_PARSE_OK , +RTASE_PARSE_SKIP , +RTASE_PARSE_DROP , +}; +#define RSVD_MASK 0x3FFFC000struct rtase_tx_desc {
@@ -359,4 +365,6 @@ struct rtase_private {#define RTASE_MSS_MASK GENMASK(28, 18) +#define RTASE_MIN_PAD_LEN 47 +#endif /* RTASE_H */
drivers/net/ethernet/realtek/rtase/rtase_main.c +197 -0
215 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 687/744 tcp: initialize standalone TCP-AO response padding
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yizhou Zhao <[email protected]>
commit e1a9d3cc11829c5414a75eb39c704f461936eb24 upstream.
tcp_v4_send_ack() and tcp_v6_send_response() construct standalone TCP responses with TCP-AO options. The option length carries the actual MAC length, but the TCP header length includes the option rounded up to a four-byte boundary.
tcp_ao_hash_hdr() writes the MAC only. Thus, when the MAC length is not four-byte aligned, the one to three bytes after the MAC are left uninitialized and may be transmitted. For the normal TCP-AO hashing mode, those bytes also have to be initialized before computing the MAC.
Initialize only the alignment padding in the TCP-AO branches, before hashing the header. Use TCPOPT_NOP, as in the normal TCP-AO output path. This avoids adding work to non-AO TCP responses while preserving a valid authenticated header.
--- net/ipv4/tcp_ipv4.c | 3 +++ net/ipv6/tcp_ipv6.c | 2 ++ 2 files changed, 5 insertions(+)
net/ipv4/tcp_ipv4.c +3 -0
@@ -971,6 +971,9 @@ static void tcp_v4_send_ack(const struct key->rcv_next); arg.iov[0 ].iov_len +=tcp_ao_len_aligned (key->ao_key); rep.th.doff = arg.iov[0 ].iov_len /4 ; +memset ((u8 *)&rep.opt[offset] +tcp_ao_maclen (key->ao_key), +TCPOPT_NOP ,tcp_ao_len_aligned (key->ao_key) - +tcp_ao_len (key->ao_key)); tcp_ao_hash_hdr(AF_INET, (char *)&rep.opt[offset], key->ao_key, key->traffic_key,
net/ipv6/tcp_ipv6.c +2 -0
@@ -915,6 +915,8 @@ static void tcp_v6_send_response(const s (tcp_ao_len (key->ao_key) <<16 ) | (key->ao_key->sndid <<8 ) | (key->rcv_next)); +memset ((u8 *)topt +tcp_ao_maclen (key->ao_key),TCPOPT_NOP , +tcp_ao_len_aligned (key->ao_key) -tcp_ao_len (key->ao_key)); tcp_ao_hash_hdr(AF_INET6, (char *)topt, key->ao_key, key->traffic_key,
Greg Kroah-Hartman
maintainerPATCH 688/744 tcp: challenge ACK for non-exact RST in SYN-RECEIVED
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuxiang Yang <[email protected]>
commit a28c4fcbf774e23b4779cae468e3497a5ad1f4a1 upstream.
The SYN-RECEIVED request-socket path in tcp_check_req() accepts an in-window RST without requiring SEG.SEQ to exactly match RCV.NXT. A non-exact RST therefore removes the request instead of eliciting a challenge ACK.
RFC 9293 section 3.10.7.4 applies the RFC 5961 reset check in
SYN-RECEIVED: an exact RST resets the connection, while a non-exact in-window RST must trigger a challenge ACK and be dropped.
Apply that check before the ACK-field validation, following the RFC sequence-number, RST, then ACK processing order. Factor the per-netns challenge ACK quota out of tcp_send_challenge_ack() so request sockets can share it. Use the request socket's send_ack() callback and its own out-of-window ACK timestamp to send and rate-limit the response.
--- include/net/tcp.h | 2 + net/ipv4/tcp_input.c | 56 ++++++++++++++++++++++++++++++++++++----------- net/ipv4/tcp_minisocks.c | 12 +++++++++- 3 files changed, 56 insertions(+), 14 deletions(-)
include/net/tcp.h +2 -0
@@ -1965,6 +1965,8 @@ static inline void tcp_fast_path_check(sbool tcp_oow_rate_limited (struct net *net,const struct sk_buff *skb,int mib_idx,u32 *last_oow_ack_time); +void tcp_reqsk_send_challenge_ack (struct sock *sk,struct sk_buff *skb, +struct request_sock *req);static inline void tcp_mib_init (struct net *net) {
net/ipv4/tcp_input.c +43 -13
79 lines not on this page · raw message
net/ipv4/tcp_minisocks.c +11 -1
@@ -835,7 +835,7 @@ struct sock *tcp_check_req(struct sock ** elsewhere and is checked directly against the child socket rather * than req because user data may have been sent out. */ -if ((flg &TCP_FLAG_ACK ) && !fastopen && +if ((flg &TCP_FLAG_ACK ) && !(flg &TCP_FLAG_RST ) && !fastopen && (TCP_SKB_CB (skb)->ack_seq !=tcp_rsk (req)->snt_isn +1 ))return sk;
@@ -874,6 +874,16 @@ struct sock *tcp_check_req(struct sock * flg &= ~TCP_FLAG_SYN ; } +/* RFC 5961 section 3.2, as clarified by RFC 9293 section +* 3.10.7.4, requires a challenge ACK for a non-exact +* in-window RST in SYN-RECEIVED. +*/ +if ((flg &TCP_FLAG_RST ) && +TCP_SKB_CB (skb)->seq !=tcp_rsk (req)->rcv_nxt) { +tcp_reqsk_send_challenge_ack (sk, skb, req); +return NULL ; + } +/* RFC793: "second check the RST bit" and * "fourth, check the SYN bit" */
Greg Kroah-Hartman
maintainerPATCH 689/744 tipc: clear sock->sk on the failed-insert path in tipc_sk_create()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daehyeon Ko <[email protected]>
commit ba0533fc163f905fe817cfabdf8ed4058da44800 upstream.
When tipc_sk_create() fails to insert the new socket (tipc_sk_insert() returns non-zero), its error path frees the sk with sk_free() but leaves sock->sk pointing at the freed object:
if (tipc_sk_insert(tsk)) {
sk_free(sk);
pr_warn("Socket create failed; port number exhausted\n");
return -EINVAL;
}This is harmless for plain socket(): the syscall layer clears sock->ops before releasing, so tipc_release() is never called. It is not harmless on the accept() path. tipc_accept() creates the pre-allocated child socket with tipc_sk_create(net, new_sock, 0, kern); on failure it leaves new_sock->sk dangling and new_sock->ops non-NULL, and do_accept() then fput()s the new file, so __sock_release() -> tipc_release() runs lock_sock(new_sock->sk) on the freed sk -- a use-after-free write of the sk_lock spinlock.
tipc_release() already guards this exact "failed accept() releases a pre-allocated child" case with "if (sk == NULL) return 0;", but the guard is bypassed because tipc_sk_create() left sock->sk non-NULL (dangling) rather than NULL.
Clear sock->sk on the failed-insert path so the existing tipc_release() NULL check fires and the use-after-free is avoided.
The tipc_sk_insert() failure is reached when the per-netns socket rhashtable hits its max_size (tsk_rht_params.max_size = 1048576, ~2M elements) -- i.e. once a netns holds ~2M TIPC sockets every insert returns -E2BIG.
BUG: KASAN: slab-use-after-free in lock_sock_nested (net/core/sock.c:3839) Write of size 8 at addr ffff8880047cdc38 by task init/1 lock_sock_nested (net/core/sock.c:3839) tipc_release (net/tipc/socket.c:638) __sock_release (net/socket.c:710) sock_close (net/socket.c:1501) __fput (fs/file_table.c:512) Allocated by task 1: sk_alloc (net/core/sock.c:2308) tipc_sk_create (net/tipc/socket.c:487) tipc_accept (net/tipc/socket.c:2744) do_accept (net/socket.c:2034) Freed by task 1: __sk_destruct (net/core/sock.c:2391) tipc_sk_create (net/tipc/socket.c:504) tipc_accept (net/tipc/socket.c:2744) do_accept (net/socket.c:2034)
--- net/tipc/socket.c | 1 + 1 file changed, 1 insertion(+)
net/tipc/socket.c +1 -0
@@ -501,6 +501,7 @@ static int tipc_sk_create(struct net *netipc_set_sk_state (sk,TIPC_OPEN );if (tipc_sk_insert (tsk)) {sk_free (sk); + sock->sk =NULL ;pr_warn ("Socket create failed; port number exhausted\n" );return -EINVAL ; }
Greg Kroah-Hartman
maintainerPATCH 690/744 vsock/virtio: collapse receive queue under memory pressure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stefano Garzarella <[email protected]>
commit 2a12c05aef213ff304ecc9e2f351de20731946b8 upstream.
When many small packets accumulate in the receive queue, the skb overhead can exceed buf_alloc even while the payload is within bounds. This causes virtio_transport_inc_rx_pkt() to reject packets, leading to connection resets during large transfers under backpressure.
The issue was reported by Brien, who has a reproducer, but it is also easily reproducible with iperf-vsock [1] using a small packet size:
iperf3 --vsock -c $CID -l 129
which fails immediately without this patch but with commit 059b7dbd20a6 ("vsock/virtio: fix potential unbounded skb queue").
Inspired by TCP's tcp_collapse() which solves a similar problem, add virtio_transport_collapse_rx_queue() that walks the receive queue and re-copies data into compact linear skbs to reduce the overhead.
The collapse is triggered proactively from when the number of skb queued is close to exceeding the overhead budget.
A pre-scan counts the eligible bytes to size each allocation precisely, avoiding waste for isolated small packets. Partially consumed skbs are kept as-is to preserve buf_used/fwd_cnt accounting, EOM-marked skbs to maintain SEQPACKET message boundaries, and skbs already larger than the collapse target because they already have a good data-to-overhead ratio.
Walking a large queue may take a significant amount of time and cache misses, causing traffic burstiness. To limit this, the collapse stops once enough room is freed for this packet and the next one, but may opportunistically free more to fill each collapsed skb to capacity.
[1] https://github.com/stefano-garzarella/iperf-vsock
--- net/vmw_vsock/virtio_transport_common.c | 165 +++++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 1 deletion(-)
net/vmw_vsock/virtio_transport_common.c +164 -1
@@ -26,6 +26,13 @@/* Threshold for detecting small packets to copy */ #define GOOD_COPY_LEN 128 +/* Max payload that can be collapsed into a single linear skb, using the same +* allocation threshold as virtio_vsock_alloc_skb() to avoid adding pressure +* on the page allocator. +*/ +#define MAX_COLLAPSE_LEN \ + SKB_MAX_ORDER(VIRTIO_VSOCK_SKB_HEADROOM, PAGE_ALLOC_COSTLY_ORDER) +static void virtio_transport_cancel_close_work (struct vsock_sock *vsk,bool cancel_timeout);static s64 virtio_transport_has_space (struct virtio_vsock_sock *vvs);
@@ -420,6 +427,145 @@ static int virtio_transport_send_pkt_infreturn ret; } +static bool virtio_transport_can_collapse (struct sk_buff *skb) +{ +/* skbs that are partially consumed, mark a SEQPACKET message boundary, +* or are already large enough should not be collapsed: they either +* need special accounting, carry protocol state, or already have a +* good data-to-overhead ratio. +*/ +if (VIRTIO_VSOCK_SKB_CB (skb)->offset) +return false; +if (le32_to_cpu (virtio_vsock_hdr (skb)->flags) &VIRTIO_VSOCK_SEQ_EOM ) +return false; +if (skb->len >=MAX_COLLAPSE_LEN ) +return false; +return true; +} + +/* Iterate through the packets in the queue starting from the current skb to +* count the number of bytes we can collapse. +*/ +static unsigned int +virtio_transport_collapse_size (struct sk_buff *skb,struct sk_buff_head *queue) +{ +unsigned int target = skb->len -VIRTIO_VSOCK_SKB_CB (skb)->offset; + +while ((skb =skb_peek_next (skb, queue)) && +virtio_transport_can_collapse (skb)) { +unsigned int len = skb->len -VIRTIO_VSOCK_SKB_CB (skb)->offset; + +if (len >MAX_COLLAPSE_LEN - target) +return target; + + target += len; + } + +return target; +} + +/* Called under lock_sock to compact the receive queue by merging small skbs. +* @min_to_free: minimum number of skbs to eliminate from the queue. May free +* more to fill each collapsed skb to capacity. +*/ +static void +virtio_transport_collapse_rx_queue (struct virtio_vsock_sock *vvs, +u32 min_to_free) +{ +struct sk_buff *skb, *next_skb, *new_skb =NULL ; +struct sk_buff_head new_queue; +u32 saved =0 ; + +__skb_queue_head_init (&new_queue); + + skb_queue_walk_safe(&vvs->rx_queue, skb, next_skb) { +struct virtio_vsock_hdr *hdr =virtio_vsock_hdr (skb); +u32 src_off =VIRTIO_VSOCK_SKB_CB (skb)->offset; +u32 src_len = skb->len - src_off; +bool keep; + + keep = !virtio_transport_can_collapse (skb); +if (keep) { +/* Finalize pending collapsed skb to preserve packet +* ordering. +*/ +if (new_skb) { +__skb_queue_tail (&new_queue, new_skb); + new_skb =NULL ; + saved--; + } + goto next; + } + +/* Finalize if this packet won't fit in the remaining tailroom, +* so we can allocate a right-sized new_skb. +*/ +if (new_skb && src_len >skb_tailroom (new_skb)) { +__skb_queue_tail (&new_queue, new_skb); + new_skb =NULL ; + saved--; + } + +if (!new_skb) { +unsigned int alloc_size; + +/* Check after finalizing to opportunistically fill +* each collapsed skb to capacity, merging more skbs +* than strictly required. +*/ +if (saved >= min_to_free) +break ; + + alloc_size =virtio_transport_collapse_size (skb, &vvs->rx_queue); + +/* Only this skb's data is eligible, nothing to merge +* with. Keep as-is. +*/ +if (alloc_size <= src_len) { + keep = true; + goto next; + } + + new_skb =virtio_vsock_alloc_linear_skb (alloc_size + +VIRTIO_VSOCK_SKB_HEADROOM ,GFP_KERNEL ); +if (!new_skb) +break ; + +memcpy (virtio_vsock_hdr (new_skb), hdr, +sizeof (struct virtio_vsock_hdr )); +virtio_vsock_hdr (new_skb)->len =0 ; + } + +/* Cannot fail since src_off/src_len are within bounds, but if +* it does, discard new_skb to avoid queuing corrupted data. +*/ +if (WARN_ON_ONCE (skb_copy_bits (skb, src_off, +skb_put (new_skb, src_len), + src_len))) { +kfree_skb (new_skb); + new_skb =NULL ; +break ; + } + +le32_add_cpu (&virtio_vsock_hdr (new_skb)->len, src_len); +virtio_vsock_hdr (new_skb)->flags |= hdr->flags; + +next: +__skb_unlink (skb, &vvs->rx_queue); +if (keep) { +__skb_queue_tail (&new_queue, skb); + }else { +consume_skb (skb); + saved++; + } + } + +if (new_skb) +__skb_queue_tail (&new_queue, new_skb); + +skb_queue_splice (&new_queue, &vvs->rx_queue); +} +static bool virtio_transport_inc_rx_pkt (struct virtio_vsock_sock *vvs,u32 len) {
@@ -1354,12 +1500,29 @@ virtio_transport_recv_enqueue(struct vso {struct virtio_vsock_sock *vvs = vsk->trans;bool can_enqueue, free_pkt = false; +u32 len, queue_max, queue_len;struct virtio_vsock_hdr *hdr; -u32 len; hdr =virtio_vsock_hdr (skb); len =le32_to_cpu (hdr->len); +/* virtio_transport_inc_rx_pkt() rejects packets when the per-skb +* overhead (skb_queue_len * SKB_TRUESIZE(0)) exceeds buf_alloc. +* Proactively collapse the queue before that happens. +* No rx_lock needed: lock_sock is held by caller, preventing +* concurrent enqueue or dequeue. +*/ + queue_max = vvs->buf_alloc /SKB_TRUESIZE (0 ); + queue_len =skb_queue_len (&vvs->rx_queue); +if (queue_len >= queue_max) { +/* Walking a large queue may take a significant amount of time +* and cache misses, causing traffic burstiness. Limit the +* collapse to freeing room for this packet and the next one. +* It may free more to fill each collapsed skb to capacity. +*/ +virtio_transport_collapse_rx_queue (vvs, queue_len +2 - queue_max); + } +spin_lock_bh (&vvs->rx_lock); can_enqueue =virtio_transport_inc_rx_pkt (vvs, len);
Greg Kroah-Hartman
maintainerPATCH 691/744 vxlan: mdb: Fix source list corruption on a failed replace
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Raphael Tiovalen <[email protected]>
commit dcd9b465965422b9654f6026e8a2fa8984f74c3c upstream.
When replacing the source list of an MDB remote entry, all existing sources are first marked for deletion and vxlan_mdb_remote_srcs_add() is then called to add the new source list. Sources present in the new list have their deletion mark cleared, and any sources left marked afterwards are removed.
If vxlan_mdb_remote_srcs_add() fails partway through, its error path deletes all entries on the remote's source list. That rollback is only correct for its other caller, vxlan_mdb_remote_add(), where the remote was just allocated and the list contains solely entries added during the call. On the replace path the list also holds pre-existing sources, so a failed replace tears them down together with their (S, G) forwarding entries instead of leaving the entry unchanged.
This is reachable from an existing (*, G) remote. An EXCLUDE filter that loses sources starts forwarding traffic that should be blocked, while an INCLUDE filter that loses sources drops traffic that should be forwarded.
Mark entries created during the current pass with a new VXLAN_SGRP_F_NEW flag. On failure, delete only those entries and clear the deletion mark on the pre-existing ones, so a failed replace leaves the source list untouched. Retain the flag until the whole operation succeeds and then clear it. Also stop vxlan_mdb_remote_src_add() from deleting a pre-existing entry it only looked up when adding that entry's forwarding entry fails.
--- drivers/net/vxlan/vxlan_mdb.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-)
drivers/net/vxlan/vxlan_mdb.c +18 -12
@@ -42,6 +42,7 @@ struct vxlan_mdb_remote { };#define VXLAN_SGRP_F_DELETE BIT(0) +#define VXLAN_SGRP_F_NEW BIT(1)struct vxlan_mdb_src_entry {struct hlist_node node;
@@ -844,6 +845,7 @@ vxlan_mdb_remote_src_add(const struct vx ent =vxlan_mdb_remote_src_entry_add (remote, &src->addr);if (!ent)return -ENOMEM ; + ent->flags |=VXLAN_SGRP_F_NEW ; }else if (!(cfg->nlflags &NLM_F_REPLACE )) {NL_SET_ERR_MSG_MOD (extack,"Source entry already exists" );return -EEXIST ;
@@ -853,15 +855,16 @@ vxlan_mdb_remote_src_add(const struct vxif (err) goto err_src_del; -/* Clear flags in case source entry was marked for deletion as part of -* replace flow. +/* Clear the deletion mark so the entry survives the replace sweep. +* The new mark is retained until the whole operation succeeds. */ - ent->flags =0 ; + ent->flags &= ~VXLAN_SGRP_F_DELETE ;return 0 ; err_src_del: -vxlan_mdb_remote_src_entry_del (ent); +if (ent->flags &VXLAN_SGRP_F_NEW ) +vxlan_mdb_remote_src_entry_del (ent);return err; }
@@ -889,11 +892,19 @@ static int vxlan_mdb_remote_srcs_add(con goto err_src_del; } +hlist_for_each_entry (ent, &remote->src_list, node) + ent->flags &= ~VXLAN_SGRP_F_NEW ; +return 0 ; err_src_del: -hlist_for_each_entry_safe (ent, tmp, &remote->src_list, node) -vxlan_mdb_remote_src_del (cfg->vxlan, &cfg->group, remote, ent); +hlist_for_each_entry_safe (ent, tmp, &remote->src_list, node) { +if (ent->flags &VXLAN_SGRP_F_NEW ) +vxlan_mdb_remote_src_del (cfg->vxlan, &cfg->group, remote, + ent); +else + ent->flags &= ~VXLAN_SGRP_F_DELETE ; + }return err; }
@@ -1069,7 +1080,7 @@ vxlan_mdb_remote_srcs_replace(const stru err =vxlan_mdb_remote_srcs_add (cfg, remote, extack);if (err) - goto err_clear_delete; +return err;hlist_for_each_entry_safe (ent, tmp, &remote->src_list, node) {if (ent->flags &VXLAN_SGRP_F_DELETE )
@@ -1078,11 +1089,6 @@ vxlan_mdb_remote_srcs_replace(const stru }return 0 ; - -err_clear_delete: -hlist_for_each_entry (ent, &remote->src_list, node) - ent->flags &= ~VXLAN_SGRP_F_DELETE ; -return err; } static int vxlan_mdb_remote_replace(const struct vxlan_mdb_config *cfg,
Greg Kroah-Hartman
maintainerPATCH 692/744 watchdog: s32g_wdt: remove incorrect options in watchdog_info struct
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ethan Nelson-Moore <[email protected]>
commit 2b37415618bfc6a83d4aceb00fd8d6491096f2ed upstream.
The s32g_wdt driver uses two incorrect constants in the options field of its watchdog_info struct. This bit mask should contain WDIOF_* constants, but the driver uses two WDIOC_* ioctl constants (in addition to correct WDIOF_* constants). This causes many incorrect bits to be set in the bit mask. The functionality indicated by these ioctl constants is supported by all drivers using the watchdog framework, so this patch simply removes them.
--- drivers/watchdog/s32g_wdt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/watchdog/s32g_wdt.c +1 -2
@@ -56,8 +56,7 @@ MODULE_PARM_DESC(early_enable,static const struct watchdog_info s32g_wdt_info = { .identity ="s32g watchdog" , - .options =WDIOF_KEEPALIVEPING |WDIOF_SETTIMEOUT |WDIOF_MAGICCLOSE | -WDIOC_GETTIMEOUT |WDIOC_GETTIMELEFT , + .options =WDIOF_KEEPALIVEPING |WDIOF_SETTIMEOUT |WDIOF_MAGICCLOSE , };static struct s32g_wdt_device *wdd_to_s32g_wdt (struct watchdog_device *wdd)
Greg Kroah-Hartman
maintainerPATCH 693/744 drm/amd/pm: fix amdgpu_pm_info power display units
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Wang <[email protected]>
commit 238baca26a6279e688d1a156bd031390b82eb578 upstream.
amdgpu_pm_info displayed power sensor readings with the wrong fractional unit. It treated the low byte of the raw sensor value as the decimal part of watts, while that field represents milliwatts in the decoded value. As a result, debugfs could report misleading SoC power when the remainder was not already a two-digit centiwatt value.
Example with query = 0x00000354:
raw field value
---------------------
query >> 8 3 W query & 0xff 84 mW decoded power 3084 mW
output value
---------------------
before 3.84 W
after 3.08 W
--- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-)
drivers/gpu/drm/amd/pm/amdgpu_pm.c +12 -9
@@ -41,6 +41,8 @@#define DEVICE_ATTR_IS (_name) (attr_id == device_attr_id__##_name) +#define power_2_mwatt (power) (((power) >> 8) * 1000 + ((power) & 0xff)) +struct od_attribute {struct kobj_attribute attribute;struct list_head entry;
@@ -3333,7 +3335,6 @@ static int amdgpu_hwmon_get_power(struct enum amd_pp_sensors sensor) {struct amdgpu_device *adev =dev_get_drvdata (dev); -unsigned int uw;u32 query =0 ;int r;
@@ -3342,9 +3343,7 @@ static int amdgpu_hwmon_get_power(structreturn r;/* convert to microwatts */ - uw = (query >>8 ) *1000000 + (query &0xff ) *1000 ; - -return uw; +return power_2_mwatt (query) *1000 ; } static ssize_t amdgpu_hwmon_show_power_avg(struct device *dev,
@@ -4882,7 +4881,7 @@ static int amdgpu_debugfs_pm_info_pp(str {uint32_t mp1_ver =amdgpu_ip_version (adev,MP1_HWIP ,0 );uint32_t gc_ver =amdgpu_ip_version (adev,GC_HWIP ,0 ); -uint32_t value; +uint32_t value, mwatt, centiwatt;uint64_t value64 =0 ;uint32_t query =0 ;int size;
@@ -4907,17 +4906,21 @@ static int amdgpu_debugfs_pm_info_pp(strseq_printf (m,"\t%u mV (VDDNB)\n" , value); size =sizeof (uint32_t );if (!amdgpu_dpm_read_sensor (adev,AMDGPU_PP_SENSOR_GPU_AVG_POWER , (void *)&query, &size)) { + mwatt =power_2_mwatt (query); + centiwatt =DIV_ROUND_CLOSEST (mwatt,10 );if (adev->flags &AMD_IS_APU ) -seq_printf (m,"\t%u.%02u W (average SoC including CPU)\n" , query >>8 , query &0xff ); +seq_printf (m,"\t%u.%02u W (average SoC including CPU)\n" , centiwatt /100 , centiwatt %100 );else -seq_printf (m,"\t%u.%02u W (average SoC)\n" , query >>8 , query &0xff ); +seq_printf (m,"\t%u.%02u W (average SoC)\n" , centiwatt /100 , centiwatt %100 ); } size =sizeof (uint32_t );if (!amdgpu_dpm_read_sensor (adev,AMDGPU_PP_SENSOR_GPU_INPUT_POWER , (void *)&query, &size)) { + mwatt =power_2_mwatt (query); + centiwatt =DIV_ROUND_CLOSEST (mwatt,10 );if (adev->flags &AMD_IS_APU ) -seq_printf (m,"\t%u.%02u W (current SoC including CPU)\n" , query >>8 , query &0xff ); +seq_printf (m,"\t%u.%02u W (current SoC including CPU)\n" , centiwatt /100 , centiwatt %100 );else -seq_printf (m,"\t%u.%02u W (current SoC)\n" , query >>8 , query &0xff ); +seq_printf (m,"\t%u.%02u W (current SoC)\n" , centiwatt /100 , centiwatt %100 ); } size =sizeof (value);seq_printf (m,"\n" );
Greg Kroah-Hartman
maintainerPATCH 694/744 drm/amd/pm: make pp_features read-only when scpm is enabled
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Wang <[email protected]>
commit 53c78ab388bfc1a4d72e756815d0db0a842c812e upstream.
SCPM owns power feature control when enabled.
Make pp_features read-only during sysfs setup by clearing its write bits and store callback.
--- drivers/gpu/drm/amd/pm/amdgpu_pm.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/gpu/drm/amd/pm/amdgpu_pm.c +5 -0
@@ -2682,6 +2682,11 @@ static int default_attr_update(struct am gc_ver != IP_VERSION(9, 4, 3)) || gc_ver < IP_VERSION(9, 0, 0)) *states =ATTR_STATE_UNSUPPORTED ; + +if (adev->scpm_enabled) { + dev_attr->attr.mode &= ~S_IWUGO ; + dev_attr->store =NULL ; + } }else if (DEVICE_ATTR_IS (gpu_metrics)) {if (gc_ver <IP_VERSION (9 ,1 ,0 )) *states =ATTR_STATE_UNSUPPORTED ;
Greg Kroah-Hartman
maintainerPATCH 695/744 drm/amdgpu/gfx10: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit d06c4173a7c38c7a39e98859f839ce714c7af2c9 upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +5 -8
@@ -4022,7 +4022,7 @@ static void gfx_v10_0_wait_reg_mem(struc WAIT_REG_MEM_ENGINE(eng_sel)));if (mem_space) -BUG_ON (addr0 &0x3 );/* Dword align */ +WARN_ON (addr0 &0x3 );/* Dword align */ amdgpu_ring_write (ring, addr0);amdgpu_ring_write (ring, addr1);amdgpu_ring_write (ring, ref);
@@ -8664,7 +8664,7 @@ static void gfx_v10_0_ring_emit_ib_gfx(s }amdgpu_ring_write (ring, header); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -8699,7 +8699,7 @@ static void gfx_v10_0_ring_emit_ib_compu }amdgpu_ring_write (ring,PACKET3 (PACKET3_INDIRECT_BUFFER ,2 )); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -8732,9 +8732,9 @@ static void gfx_v10_0_ring_emit_fence(st* aligned if only send 32bit data low (discard data high) */ if (write64bit) -BUG_ON (addr &0x7 ); +WARN_ON (addr &0x7 );else -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
@@ -8782,9 +8782,6 @@ static void gfx_v10_0_ring_emit_fence_ki {struct amdgpu_device *adev = ring->adev; -/* we only allocate 32bit for each seq wb address */ -BUG_ON (flags &AMDGPU_FENCE_FLAG_64BIT ); -/* write fence seq to the "addr" */ amdgpu_ring_write (ring,PACKET3 (PACKET3_WRITE_DATA ,3 )); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
Greg Kroah-Hartman
maintainerPATCH 696/744 drm/amdgpu/gfx12.1: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit 6560e6bd76127844e39f09fa591c2791dc7932e8 upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c +4 -7
@@ -248,7 +248,7 @@ static void gfx_v12_1_wait_reg_mem(struc WAIT_REG_MEM_FUNCTION(3))); /* equal */if (mem_space) -BUG_ON (addr0 &0x3 );/* Dword align */ +WARN_ON (addr0 &0x3 );/* Dword align */ amdgpu_ring_write (ring, addr0);amdgpu_ring_write (ring, addr1);amdgpu_ring_write (ring, ref);
@@ -3373,7 +3373,7 @@ static void gfx_v12_1_ring_emit_ib_compu }amdgpu_ring_write (ring,PACKET3 (PACKET3_INDIRECT_BUFFER ,2 )); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -3406,9 +3406,9 @@ static void gfx_v12_1_ring_emit_fence(st* aligned if only send 32bit data low (discard data high) */ if (write64bit) -BUG_ON (addr &0x7 ); +WARN_ON (addr &0x7 );else -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
@@ -3455,9 +3455,6 @@ static void gfx_v12_1_ring_emit_fence_ki {struct amdgpu_device *adev = ring->adev; -/* we only allocate 32bit for each seq wb address */ -BUG_ON (flags &AMDGPU_FENCE_FLAG_64BIT ); -/* write fence seq to the "addr" */ amdgpu_ring_write (ring,PACKET3 (PACKET3_WRITE_DATA ,3 ));amdgpu_ring_write (ring, (WRITE_DATA_DST_SEL (5 ) |WR_CONFIRM ));
Greg Kroah-Hartman
maintainerPATCH 697/744 drm/amdgpu/gfx11: fix EOP interrupt routing for KQ and userq
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jesse Zhang <[email protected]>
commit 0a3d35460320baf8744c7dcc3e287e07fbaf6d36 upstream.
Try KQ by ring_id first (KCQ and UQ never share a HW slot); fall back to amdgpu_userq_process_fence_irq() on miss, since KQ EOPs were misrouted into the userq fence path when enable_mes is true.
Require a strict (me,pipe,queue) match in the gfx case, then userq gfx EOPs fall through to amdgpu_userq_process_fence_irq().
--- drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c | 43 ++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 14 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +29 -14
@@ -6513,25 +6513,33 @@ static int gfx_v11_0_eop_irq(struct amdg struct amdgpu_iv_entry *entry) {u32 doorbell_offset = entry->src_data[0 ]; -u8 me_id, pipe_id, queue_id; -struct amdgpu_ring *ring; -int i;DRM_DEBUG ("IH: CP EOP\n" ); -if (adev->enable_mes && doorbell_offset) { -amdgpu_userq_process_fence_irq (adev, doorbell_offset); - }else { - me_id = (entry->ring_id &0x0c ) >>2 ; - pipe_id = (entry->ring_id &0x03 ) >>0 ; - queue_id = (entry->ring_id &0x70 ) >>4 ; +if (!adev->gfx.disable_kq) { +u8 me_id = (entry->ring_id &0x0c ) >>2 ; +u8 pipe_id = (entry->ring_id &0x03 ) >>0 ; +u8 queue_id = (entry->ring_id &0x70 ) >>4 ; +struct amdgpu_ring *ring; +int i;switch (me_id) {case 0 : -if (pipe_id ==0 ) -amdgpu_fence_process (&adev->gfx.gfx_ring[0 ]); -else -amdgpu_fence_process (&adev->gfx.gfx_ring[1 ]); +/* +* MES splits gfx HQDs per (me,pipe): KGQ owns queue=0, +* userq gfx owns queue>=1 (see amdgpu_mes_get_hqd_mask). +* Require a strict (me,pipe,queue) match so userq gfx +* EOPs fall through to amdgpu_userq_process_fence_irq(). +*/ +for (i =0 ; i < adev->gfx.num_gfx_rings; i++) { + ring = &adev->gfx.gfx_ring[i]; +if ((ring->me == me_id) && + (ring->pipe == pipe_id) && + (ring->queue == queue_id)) { +amdgpu_fence_process (ring); +return 0 ; + } + }break ;case 1 :case 2 :
@@ -6543,13 +6551,20 @@ static int gfx_v11_0_eop_irq(struct amdg*/ if ((ring->me == me_id) && (ring->pipe == pipe_id) && - (ring->queue == queue_id)) + (ring->queue == queue_id)) {amdgpu_fence_process (ring); +return 0 ; + } }break ; +default : +break ; } } +if (adev->enable_mes && doorbell_offset) +amdgpu_userq_process_fence_irq (adev, doorbell_offset); +return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 698/744 drm/amdgpu/gfx12: fix EOP interrupt routing for KQ and userq
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jesse Zhang <[email protected]>
commit 128abbbfa913e7e099b75ae652cc90cfd66c6d6b upstream.
Try KQ by ring_id first (KCQ and UQ never share a HW slot); fall back to amdgpu_userq_process_fence_irq() on miss, since KCQ EOPs were misrouted into the userq fence path when enable_mes is true.
Require a strict (me,pipe,queue) match in the gfx case, then userq gfx EOPs fall through to amdgpu_userq_process_fence_irq().
--- drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 43 ++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 14 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +29 -14
@@ -4854,25 +4854,33 @@ static int gfx_v12_0_eop_irq(struct amdg struct amdgpu_iv_entry *entry) {u32 doorbell_offset = entry->src_data[0 ]; -u8 me_id, pipe_id, queue_id; -struct amdgpu_ring *ring; -int i;DRM_DEBUG ("IH: CP EOP\n" ); -if (adev->enable_mes && doorbell_offset) { -amdgpu_userq_process_fence_irq (adev, doorbell_offset); - }else { - me_id = (entry->ring_id &0x0c ) >>2 ; - pipe_id = (entry->ring_id &0x03 ) >>0 ; - queue_id = (entry->ring_id &0x70 ) >>4 ; +if (!adev->gfx.disable_kq) { +u8 me_id = (entry->ring_id &0x0c ) >>2 ; +u8 pipe_id = (entry->ring_id &0x03 ) >>0 ; +u8 queue_id = (entry->ring_id &0x70 ) >>4 ; +struct amdgpu_ring *ring; +int i;switch (me_id) {case 0 : -if (pipe_id ==0 ) -amdgpu_fence_process (&adev->gfx.gfx_ring[0 ]); -else -amdgpu_fence_process (&adev->gfx.gfx_ring[1 ]); +/* +* MES splits gfx HQDs per (me,pipe): KGQ owns queue=0, +* userq gfx owns queue>=1 (see amdgpu_mes_get_hqd_mask). +* Require a strict (me,pipe,queue) match so userq gfx +* EOPs fall through to amdgpu_userq_process_fence_irq(). +*/ +for (i =0 ; i < adev->gfx.num_gfx_rings; i++) { + ring = &adev->gfx.gfx_ring[i]; +if ((ring->me == me_id) && + (ring->pipe == pipe_id) && + (ring->queue == queue_id)) { +amdgpu_fence_process (ring); +return 0 ; + } + }break ;case 1 :case 2 :
@@ -4884,13 +4892,20 @@ static int gfx_v12_0_eop_irq(struct amdg*/ if ((ring->me == me_id) && (ring->pipe == pipe_id) && - (ring->queue == queue_id)) + (ring->queue == queue_id)) {amdgpu_fence_process (ring); +return 0 ; + } }break ; +default : +break ; } } +if (adev->enable_mes && doorbell_offset) +amdgpu_userq_process_fence_irq (adev, doorbell_offset); +return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 699/744 drm/amdgpu/gfx12: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit cd3b3efa1ced05528d9128755338baa62a6b562d upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +5 -8
@@ -440,7 +440,7 @@ static void gfx_v12_0_wait_reg_mem(struc WAIT_REG_MEM_ENGINE(eng_sel)));if (mem_space) -BUG_ON (addr0 &0x3 );/* Dword align */ +WARN_ON (addr0 &0x3 );/* Dword align */ amdgpu_ring_write (ring, addr0);amdgpu_ring_write (ring, addr1);amdgpu_ring_write (ring, ref);
@@ -4459,7 +4459,7 @@ static void gfx_v12_0_ring_emit_ib_gfx(s control |= ib->length_dw | (vmid <<24 );amdgpu_ring_write (ring, header); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -4478,7 +4478,7 @@ static void gfx_v12_0_ring_emit_ib_compuu32 control =INDIRECT_BUFFER_VALID | ib->length_dw | (vmid <<24 );amdgpu_ring_write (ring,PACKET3 (PACKET3_INDIRECT_BUFFER ,2 )); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -4509,9 +4509,9 @@ static void gfx_v12_0_ring_emit_fence(st* aligned if only send 32bit data low (discard data high) */ if (write64bit) -BUG_ON (addr &0x7 ); +WARN_ON (addr &0x7 );else -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
@@ -4559,9 +4559,6 @@ static void gfx_v12_0_ring_emit_fence_ki {struct amdgpu_device *adev = ring->adev; -/* we only allocate 32bit for each seq wb address */ -BUG_ON (flags &AMDGPU_FENCE_FLAG_64BIT ); -/* write fence seq to the "addr" */ amdgpu_ring_write (ring,PACKET3 (PACKET3_WRITE_DATA ,3 )); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
Greg Kroah-Hartman
maintainerPATCH 700/744 drm/amdgpu/gfx8: drop unecessary BUG_ON()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit 84a1a8a952ab4b8c23c5dd1f2eea4049cb4914f5 upstream.
There's no need to crash the kernel for this case.
--- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 3 --- 1 file changed, 3 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +0 -3
@@ -6252,9 +6252,6 @@ static void gfx_v8_0_ring_emit_fence_comstatic void gfx_v8_0_ring_emit_fence_kiq (struct amdgpu_ring *ring,u64 addr,u64 seq,unsigned int flags) { -/* we only allocate 32bit for each seq wb address */ -BUG_ON (flags &AMDGPU_FENCE_FLAG_64BIT ); -/* write fence seq to the "addr" */ amdgpu_ring_write (ring,PACKET3 (PACKET3_WRITE_DATA ,3 )); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
Greg Kroah-Hartman
maintainerPATCH 701/744 drm/amdgpu/gfx9.4.3: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit 00f4050f7c367d7bdce347ca279ce467c434cf15 upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +4 -7
@@ -405,7 +405,7 @@ static void gfx_v9_4_3_wait_reg_mem(stru WAIT_REG_MEM_ENGINE(eng_sel)));if (mem_space) -BUG_ON (addr0 &0x3 );/* Dword align */ +WARN_ON (addr0 &0x3 );/* Dword align */ amdgpu_ring_write (ring, addr0);amdgpu_ring_write (ring, addr1);amdgpu_ring_write (ring, ref);
@@ -2857,7 +2857,7 @@ static void gfx_v9_4_3_ring_emit_ib_comp }amdgpu_ring_write (ring,PACKET3 (PACKET3_INDIRECT_BUFFER ,2 )); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -2891,9 +2891,9 @@ static void gfx_v9_4_3_ring_emit_fence(s* aligned if only send 32bit data low (discard data high) */ if (write64bit) -BUG_ON (addr &0x7 ); +WARN_ON (addr &0x7 );else -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
@@ -2953,9 +2953,6 @@ static void gfx_v9_4_3_ring_emit_fence_k {struct amdgpu_device *adev = ring->adev; -/* we only allocate 32bit for each seq wb address */ -BUG_ON (flags &AMDGPU_FENCE_FLAG_64BIT ); -/* write fence seq to the "addr" */ amdgpu_ring_write (ring,PACKET3 (PACKET3_WRITE_DATA ,3 )); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
Greg Kroah-Hartman
maintainerPATCH 702/744 drm/amdgpu/gfx9: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit 6302be10b521f5106ce01eb5a724b9e7945a5061 upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +5 -5
@@ -1183,7 +1183,7 @@ static void gfx_v9_0_wait_reg_mem(struct WAIT_REG_MEM_ENGINE(eng_sel)));if (mem_space) -BUG_ON (addr0 &0x3 );/* Dword align */ +WARN_ON (addr0 &0x3 );/* Dword align */ amdgpu_ring_write (ring, addr0);amdgpu_ring_write (ring, addr1);amdgpu_ring_write (ring, ref);
@@ -5466,7 +5466,7 @@ static void gfx_v9_0_ring_emit_ib_gfx(st }amdgpu_ring_write (ring, header); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -5562,7 +5562,7 @@ static void gfx_v9_0_ring_emit_ib_comput }amdgpu_ring_write (ring,PACKET3 (PACKET3_INDIRECT_BUFFER ,2 )); -BUG_ON (ib->gpu_addr &0x3 );/* Dword align */ +WARN_ON (ib->gpu_addr &0x3 );/* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) |
@@ -5603,9 +5603,9 @@ static void gfx_v9_0_ring_emit_fence(str* aligned if only send 32bit data low (discard data high) */ if (write64bit) -BUG_ON (addr &0x7 ); +WARN_ON (addr &0x7 );else -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
Greg Kroah-Hartman
maintainerPATCH 703/744 drm/amdgpu/jpeg: fix jpeg_v4_0_3_is_idle detection
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boyuan Zhang <[email protected]>
commit c44af3810fc8b3adf6910a332038aa566560c8fa upstream.
jpeg_v4_0_3_is_idle() initializes ret to false and then accumulates ring idle status using &=. Since false & condition always remains false, the function can never report the JPEG block as idle.
Initialize ret to true so the function returns true only when all JPEG rings report RB_JOB_DONE.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +1 -1
@@ -1010,7 +1010,7 @@ void jpeg_v4_0_3_dec_ring_nop(struct amdstatic bool jpeg_v4_0_3_is_idle (struct amdgpu_ip_block *ip_block) {struct amdgpu_device *adev = ip_block->adev; -bool ret = false; +bool ret = true;int i, j;for (i =0 ; i < adev->jpeg.num_jpeg_inst; ++i) {
Greg Kroah-Hartman
maintainerPATCH 704/744 drm/amdgpu/jpeg: fix jpeg_v5_0_1_is_idle detection
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boyuan Zhang <[email protected]>
commit efcedeececcf995fcf717b21e39aa7c446fa3bf7 upstream.
jpeg_v5_0_1_is_idle() initializes ret to false and then accumulates ring idle status using &=. Since false & condition always remains false, the function can never report the JPEG block as idle.
Initialize ret to true so the function returns true only when all JPEG rings report RB_JOB_DONE.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c +1 -1
@@ -657,7 +657,7 @@ static void jpeg_v5_0_1_dec_ring_set_wptstatic bool jpeg_v5_0_1_is_idle (struct amdgpu_ip_block *ip_block) {struct amdgpu_device *adev = ip_block->adev; -bool ret = false; +bool ret = true;int i, j;for (i =0 ; i < adev->jpeg.num_jpeg_inst; ++i) {
Greg Kroah-Hartman
maintainerPATCH 705/744 drm/amdgpu/mes11: set doorbell offset for suspending userq
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Prike Liang <[email protected]>
commit 96f222efc9e798165079def83d7f94f22ca9c384 upstream.
Updating the union MESAPI__SUSPEND and union MESAPI__RESUME to add the doorbell offset for suspending userq.
--- drivers/gpu/drm/amd/amdgpu/mes_v11_0.c | 2 ++ drivers/gpu/drm/amd/include/mes_v11_api_def.h | 2 ++ 2 files changed, 4 insertions(+)
drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +2 -0
@@ -557,6 +557,7 @@ static int mes_v11_0_suspend_gang(struct mes_suspend_gang_pkt.gang_context_addr = input->gang_context_addr; mes_suspend_gang_pkt.suspend_fence_addr = input->suspend_fence_addr; mes_suspend_gang_pkt.suspend_fence_value = input->suspend_fence_value; + mes_suspend_gang_pkt.doorbell_offset = input->doorbell_offset; return mes_v11_0_submit_pkt_and_poll_completion(mes, &mes_suspend_gang_pkt, sizeof(mes_suspend_gang_pkt),
@@ -576,6 +577,7 @@ static int mes_v11_0_resume_gang(struct mes_resume_gang_pkt.resume_all_gangs = input->resume_all_gangs; mes_resume_gang_pkt.gang_context_addr = input->gang_context_addr; + mes_resume_gang_pkt.doorbell_offset = input->doorbell_offset; return mes_v11_0_submit_pkt_and_poll_completion(mes, &mes_resume_gang_pkt, sizeof(mes_resume_gang_pkt),
drivers/gpu/drm/amd/include/mes_v11_api_def.h +2 -0
@@ -427,6 +427,7 @@ union MESAPI__SUSPEND {uint32_t suspend_fence_value;struct MES_API_STATUS api_status; +uint32_t doorbell_offset; };uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS ];
@@ -444,6 +445,7 @@ union MESAPI__RESUME {uint64_t gang_context_addr;struct MES_API_STATUS api_status; +uint32_t doorbell_offset; };uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS ];
Greg Kroah-Hartman
maintainerPATCH 706/744 drm/amdgpu/sdma4.4.2: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit 40cdbe9fa424cc6264a7aed93a04bd7d69109d9e upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c +2 -2
@@ -457,7 +457,7 @@ static void sdma_v4_4_2_ring_emit_fence(/* write the fence */ amdgpu_ring_write (ring,SDMA_PKT_HEADER_OP (SDMA_OP_FENCE ));/* zero in first two bits */ -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
@@ -467,7 +467,7 @@ static void sdma_v4_4_2_ring_emit_fence( addr +=4 ;amdgpu_ring_write (ring,SDMA_PKT_HEADER_OP (SDMA_OP_FENCE ));/* zero in first two bits */ -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (seq));
Greg Kroah-Hartman
maintainerPATCH 707/744 drm/amdgpu/sdma7.1: replace BUG_ON() with WARN_ON()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alex Deucher <[email protected]>
commit 767648c18d7872bbf54481ba846e055f7e1c0213 upstream.
There's no need to crash the kernel for these cases.
--- drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c +2 -2
@@ -331,7 +331,7 @@ static void sdma_v7_1_ring_emit_fence(stamdgpu_ring_write (ring,SDMA_PKT_COPY_LINEAR_HEADER_OP (SDMA_OP_FENCE ) |SDMA_PKT_FENCE_HEADER_MTYPE (0x3 ));/* Ucached(UC) */ /* zero in first two bits */ -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,lower_32_bits (seq));
@@ -342,7 +342,7 @@ static void sdma_v7_1_ring_emit_fence(stamdgpu_ring_write (ring,SDMA_PKT_COPY_LINEAR_HEADER_OP (SDMA_OP_FENCE ) |SDMA_PKT_FENCE_HEADER_MTYPE (0x3 ));/* zero in first two bits */ -BUG_ON (addr &0x3 ); +WARN_ON (addr &0x3 );amdgpu_ring_write (ring,lower_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (addr));amdgpu_ring_write (ring,upper_32_bits (seq));
Greg Kroah-Hartman
maintainerPATCH 708/744 drm/amdgpu/vce: fix integer overflow in image size
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boyuan Zhang <[email protected]>
commit 186bfdc4e26d019b2e7570cb121964a1d89b2e5b upstream.
Fix a security vulnerability where malicious VCE command streams with oversized dimensions (e.g. 65536×65536) cause 32-bit integer overflow, wrapping the calculated buffer size to 0. This bypasses validation and allows GPU firmware to perform out-of-bound memory access.
The fix uses 64-bit arithmetic to detect overflow and rejects invalid dimensions before they reach the hardware.
V2: remove redundant check
V3: modify max height value
V4: remove size64
--- drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +14 -3
@@ -877,9 +877,20 @@ int amdgpu_vce_ring_parse_cs(struct amdg goto out; } - *size =amdgpu_ib_get_value (ib, idx +8 ) * -amdgpu_ib_get_value (ib, idx +10 ) * -8 *3 /2 ; +uint32_t width, height; + width =amdgpu_ib_get_value (ib, idx +8 ); + height =amdgpu_ib_get_value (ib, idx +10 ); + +if (width ==0 || height ==0 || + width >4096 || height >2304 ) { +DRM_ERROR ("invalid VCE image size: %ux%u\n" , + width, height); + r = -EINVAL ; + goto out; + } + + *size = width * height *8 *3 /2 ; +break ;case 0x04000001 :/* config extension */
Greg Kroah-Hartman
maintainerPATCH 709/744 drm/amdgpu/vcn4: avoid rereading IB param length
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boyuan Zhang <[email protected]>
commit 3b4082fabc67c9780b06eb959e59dd92fa79c0f0 upstream.
Reuse the parameter length returned by vcn_v4_0_enc_find_ib_param() instead of rereading it from the IB.
This avoids a potential TOCTOU issue if the IB contents change between reads.
--- drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +9 -6
@@ -1927,14 +1927,17 @@ out:#define RENCODE_IB_PARAM_SESSION_INIT 0x00000003/* return the offset in ib if id is found, -1 otherwise */ -static int vcn_v4_0_enc_find_ib_param (struct amdgpu_ib *ib,uint32_t id,int start) +static int vcn_v4_0_enc_find_ib_param (struct amdgpu_ib *ib,uint32_t id,int start,uint32_t *length) {int i;uint32_t len;for (i = start; (len =amdgpu_ib_get_value (ib, i)) >=8 ; i += len /4 ) { -if (amdgpu_ib_get_value (ib, i +1 ) == id) +if (amdgpu_ib_get_value (ib, i +1 ) == id) { +if (length) + *length = len;return i; + } }return -1 ; }
@@ -1944,14 +1947,14 @@ static int vcn_v4_0_ring_patch_cs_in_pla struct amdgpu_ib *ib) {struct amdgpu_ring *ring =amdgpu_job_ring (job); -uint32_t val; +uint32_t val, len;int idx =0 , sidx;/* The first instance can decode anything */ if (!ring->me)return 0 ; -while ((idx =vcn_v4_0_enc_find_ib_param (ib,RADEON_VCN_ENGINE_INFO , idx)) >=0 ) { +while ((idx =vcn_v4_0_enc_find_ib_param (ib,RADEON_VCN_ENGINE_INFO , idx, &len)) >=0 ) { val =amdgpu_ib_get_value (ib, idx +2 );/* RADEON_VCN_ENGINE_TYPE */ if (val ==RADEON_VCN_ENGINE_TYPE_DECODE ) {uint32_t valid_buf_flag =amdgpu_ib_get_value (ib, idx +6 );
@@ -1964,12 +1967,12 @@ static int vcn_v4_0_ring_patch_cs_in_plaamdgpu_ib_get_value (ib, idx +8 );return vcn_v4_0_dec_msg (p, job, msg_buffer_addr); }else if (val ==RADEON_VCN_ENGINE_TYPE_ENCODE ) { - sidx =vcn_v4_0_enc_find_ib_param (ib,RENCODE_IB_PARAM_SESSION_INIT , idx); + sidx =vcn_v4_0_enc_find_ib_param (ib,RENCODE_IB_PARAM_SESSION_INIT , idx,NULL );if (sidx >=0 &&amdgpu_ib_get_value (ib, sidx +2 ) ==RENCODE_ENCODE_STANDARD_AV1 )return vcn_v4_0_limit_sched (p, job); } - idx +=amdgpu_ib_get_value (ib, idx) /4 ; + idx += len /4 ; }return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 710/744 drm/dp_mst: Handle torn-down topology gracefully in drm_dp_mst_topology_queue_probe()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luca Coelho <[email protected]>
commit 613059875958e7b217b250ed14c3b189f9488421 upstream.
A hotplug or link-loss event can tear down the MST topology (setting mgr->mst_state = false and mgr->mst_primary = NULL) concurrently with a caller invoking drm_dp_mst_topology_queue_probe(). Since the check is already performed under mgr->lock, the condition is not a programming error but a valid race -- the topology was valid when the caller decided to call this function, but was torn down before the lock was acquired.
Replace the drm_WARN_ON() with a graceful early return. This eliminates spurious kernel warnings and the resulting compositor crashes observed when connecting/disconnecting DP MST monitors, while keeping the correct behavior of doing nothing when MST is not active. A drm_dbg_mst() trace is added so the skipped probe remains observable under MST debug logging.
The existing WARN_ON(mgr->mst_primary) in drm_dp_mst_topology_mgr_set_mst() already catches the case where the topology is initialized twice, so no diagnostic coverage is lost.
--- drivers/gpu/drm/display/drm_dp_mst_topology.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/display/drm_dp_mst_topology.c +3 -1
@@ -3740,8 +3740,10 @@ void drm_dp_mst_topology_queue_probe(str {mutex_lock (&mgr->lock); -if (drm_WARN_ON (mgr->dev, !mgr->mst_state || !mgr->mst_primary)) +if (!mgr->mst_state || !mgr->mst_primary) { +drm_dbg_kms (mgr->dev,"queue_probe skipped: topology torn down\n" ); goto out_unlock; + }drm_dp_mst_topology_mgr_invalidate_mstb (mgr->mst_primary);drm_dp_mst_queue_probe_work (mgr);
Greg Kroah-Hartman
maintainerPATCH 711/744 drm/amdgpu: fix division by zero with invalid uvd dimensions
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Boyuan Zhang <[email protected]>
commit 0c01c811be47e6b146552dd59bfedbea8f09b8f4 upstream.
When width or height is less than 16, width_in_mb or height_in_mb becomes 0, leading to fs_in_mb being 0. This causes a division by zero when calculating num_dpb_buffer in H264 and H264 Perf decode paths.
Add validation to reject frames with width < 16 or height < 16 before performing any calculations that depend on these values.
V2: Format change - move up all vaiable definitions.
V3: Use warn_once to avoid spam.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +8 -0
@@ -655,6 +655,14 @@ static int amdgpu_uvd_cs_msg_decode(struunsigned int image_size, tmp, min_dpb_size, num_dpb_buffer;unsigned int min_ctx_size = ~0 ; +/* Reject invalid dimensions to prevent division by zero */ +if (width <16 || height <16 ) { +dev_WARN_ONCE (adev->dev,1 , +"Invalid UVD decoding dimensions (%dx%d)!\n" , + width, height); +return -EINVAL ; + } + image_size = width * height; image_size += image_size /2 ; image_size =ALIGN (image_size,1024 );
Greg Kroah-Hartman
maintainerPATCH 712/744 drm/amdgpu: Fix kernel panic during driver load failure
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harish Kasiviswanathan <[email protected]>
commit a279bd143b3c184358b658e43a057e31ee8c4de5 upstream.
Avoid kernel panic if MES init fails during driver load. The KIQ ring is falsely marked as ready as ASICs that use MES, KIQ is owned by MES.
BUG: kernel NULL pointer dereference, address: 0000000000000000 RIP: 0010:gfx_v12_1_wait_reg_mem+0x5a/0x1f0 [amdgpu] Call Trace: gfx_v12_1_ring_emit_reg_write_reg_wait+0x1f/0x30 [amdgpu] amdgpu_gmc_fw_reg_write_reg_wait+0xb2/0x190 [amdgpu] amdgpu_gmc_flush_gpu_tlb+0x1cc/0x230 [amdgpu] amdgpu_gart_invalidate_tlb+0x81/0xa0 [amdgpu] amdgpu_gart_unbind+0x72/0x90 [amdgpu] amdgpu_ttm_backend_unbind+0xa4/0xb0 [amdgpu] amdgpu_ttm_tt_unpopulate+0x13/0xd0 [amdgpu] amdttm_tt_unpopulate+0x29/0x70 [amdttm] ttm_bo_put+0x1eb/0x360 [amdttm] amdgpu_bo_free_kernel+0xf9/0x1f0 [amdgpu] amdgpu_ih_ring_fini+0x5a/0x90 [amdgpu] amdgpu_irq_fini_hw+0x58/0x80 [amdgpu] amdgpu_device_fini_hw+0x4e0/0x5b0 [amdgpu] amdgpu_driver_load_kms+0x60/0xa0 [amdgpu] amdgpu_pci_probe+0x28e/0x6d0 [amdgpu] pci_device_probe+0x19f/0x220 really_probe+0x1ed/0x340 driver_probe_device+0x1e/0x80 __driver_attach+0xd3/0x1a0 bus_for_each_dev+0x68/0xa0 bus_add_driver+0x19f/0x270 driver_register+0x5d/0xf0 do_one_initcall+0xac/0x200 do_init_module+0x1ec/0x280 __se_sys_finit_module+0x2de/0x310 do_syscall_64+0x6a/0x250 entry_SYSCALL_64_after_hwframe+0x4b/0x53
--- drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c | 13 +++++++++++-- drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c | 13 +++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +11 -2
@@ -3514,10 +3514,19 @@ static int gfx_v12_0_cp_resume(struct amgfx_v12_0_cp_gfx_enable (adev, true); } -if (adev->enable_mes_kiq && adev->mes.kiq_hw_init) +if (adev->enable_mes_kiq && adev->mes.kiq_hw_init) { r =amdgpu_mes_kiq_hw_init (adev,0 ); -else +/* +* With MES, GFX KIQ ring is owned by the MES and is never +* initialized/used directly by the driver, so it must +* not be left flagged as ready. mes_v12_0_hw_init() clears +* but clear here if MES init fails +*/ +if (r) + adev->gfx.kiq[0 ].ring.sched.ready = false; + }else { r =gfx_v12_0_kiq_resume (adev); + }if (r)return r;
drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c +11 -2
@@ -2502,10 +2502,19 @@ static int gfx_v12_1_xcc_cp_resume(strucgfx_v12_1_xcc_cp_compute_enable (adev, true, xcc_id); -if (adev->enable_mes_kiq && adev->mes.kiq_hw_init) +if (adev->enable_mes_kiq && adev->mes.kiq_hw_init) { r =amdgpu_mes_kiq_hw_init (adev, xcc_id); -else +/* +* With MES, GFX KIQ ring is owned by the MES and is never +* initialized/used directly by the driver, so it must +* not be left flagged as ready. mes_v12_0_hw_init() clears +* but clear here if MES init fails +*/ +if (r) + adev->gfx.kiq[xcc_id].ring.sched.ready = false; + }else { r =gfx_v12_1_xcc_kiq_resume (adev, xcc_id); + }if (r)return r;
Greg Kroah-Hartman
maintainerPATCH 713/744 drm/amdgpu: fix resource leak on ACP reset timeout
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ce Sun <[email protected]>
commit 020da7c5aac5b86bad8a1571f6eda6b8cff9331d upstream.
When ACP soft reset poll times out, original code returns early without cleanup, leaking MFD child devices, genpd links and all ACP heap allocations.
Replace direct early return with goto out to force run all cleanup logic regardless of reset success, preserve timeout error code for caller.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +7 -4
@@ -509,6 +509,7 @@ static int acp_hw_fini(struct amdgpu_ip_u32 val =0 ;u32 count =0 ;struct amdgpu_device *adev = ip_block->adev; +int ret =0 ;/* return early if no ACP */ if (!adev->acp.acp_genpd) {
@@ -530,7 +531,8 @@ static int acp_hw_fini(struct amdgpu_ip_break ;if (--count ==0 ) {dev_err (&adev->pdev->dev,"Failed to reset ACP\n" ); -return -ETIMEDOUT ; + ret = -ETIMEDOUT ; + goto out; }udelay (100 ); }
@@ -547,11 +549,12 @@ static int acp_hw_fini(struct amdgpu_ip_break ;if (--count ==0 ) {dev_err (&adev->pdev->dev,"Failed to reset ACP\n" ); -return -ETIMEDOUT ; + ret = -ETIMEDOUT ; + goto out; }udelay (100 ); } - +out:device_for_each_child (adev->acp.parent,NULL , acp_genpd_remove_device);
@@ -560,7 +563,7 @@ static int acp_hw_fini(struct amdgpu_ip_kfree (adev->acp.acp_genpd);kfree (adev->acp.acp_cell); -return 0 ; +return ret; }static int acp_suspend (struct amdgpu_ip_block *ip_block)
Greg Kroah-Hartman
maintainerPATCH 714/744 drm/amdgpu: invoke pm_genpd_remove() before freeing genpd
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ce Sun <[email protected]>
commit 28c9b3c5dc35cc790d11e26ca3fc6e068be63998 upstream.
Call pm_genpd_remove() to unregister from global list prior to releasing acp_genpd memory, and clear the pointer after free.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +2 -0
@@ -560,7 +560,9 @@ out:mfd_remove_devices (adev->acp.parent);kfree (adev->acp.acp_res); +pm_genpd_remove (&adev->acp.acp_genpd->gpd);kfree (adev->acp.acp_genpd); + adev->acp.acp_genpd =NULL ;kfree (adev->acp.acp_cell);return ret;
Greg Kroah-Hartman
maintainerPATCH 715/744 drm/amdgpu: reject mapping a reserved doorbell to a new queue
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhu Lingshan <[email protected]>
commit a609b6278bf3cde17eeee6620091465521e4b02c upstream.
When creating an user-queue, the user space provides a doorbell BO handle and an offset within the bo to obtain a doorbell.
However current implementation using xa_store_irq() to store a doorbell, which allows a later queue created with the same BO and offset parameters to overwrite an existing queue and doorbell mapping.
This can cause problems like misrouting fence IRQ processing to a wrong queue, and mislead the cleanup process of one queue erasing the mapping of another queue.
This commit fixes this issue by replacing xa_store_irq with xa_insert_irq, which rejects mapping a reserved doorbell to a newly created queue
--- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +2 -2
@@ -689,8 +689,8 @@ amdgpu_userq_create(struct drm_file *fil/* Update VM owner at userq submit-time for page-fault attribution. */ amdgpu_vm_set_task_info (&fpriv->vm); - r =xa_err (xa_store_irq (&adev->userq_doorbell_xa, index, queue, -GFP_KERNEL )); + r =xa_insert_irq (&adev->userq_doorbell_xa, index, queue, +GFP_KERNEL );if (r) goto clean_mqd;
Greg Kroah-Hartman
maintainerPATCH 716/744 drm/amdgpu: fix aperture mapping leak
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asad Kamal <[email protected]>
commit ea772a440d56b285f4d491affac50ecd41f6b402 upstream.
amdgpu_pci_remove() calls drm_dev_unplug() before invoking the driver fini routines. This causes drm_dev_enter() in amdgpu_ttm_fini() to always return false, so iounmap(aper_base_kaddr) never runs on normal driver unload, leaving an orphaned entry in the x86 PAT interval tree.
On connected_to_cpu hardware, the aperture is mapped write-back (WB) via ioremap_cache(). On reload, IP discovery calls memremap(..., MEMREMAP_WC) over the same range. The WC vs WB conflict causes:
ioremap error for 0x..., requested 0x1, got 0x0
amdgpu: discovery failed: -2
Fix by switching to devres-managed mappings so cleanup is guaranteed regardless of drm_dev_enter() state:
- connected_to_cpu path: devm_memremap(MEMREMAP_WB). For IORESOURCE_SYSTEM_RAM ranges this takes the try_ram_remap() shortcut, returning __va(offset) from the existing kernel direct map. No new ioremap VA or PAT entry is created, so there is nothing to orphan.
- dGPU path: devm_ioremap_wc() registers iounmap() as a devres action, guaranteeing cleanup at device_del() time.
Also remove iounmap(aper_base_kaddr) from amdgpu_device_unmap_mmio() since the mapping is now devres-owned.
v2: Remove redundant x86_64 guard (Lijo)
--- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 - drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 36 ++++++++++++----------------- 2 files changed, 16 insertions(+), 22 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +0 -2
@@ -4169,8 +4169,6 @@ static void amdgpu_device_unmap_mmio(striounmap (adev->rmmio); adev->rmmio =NULL ; -if (adev->mman.aper_base_kaddr) -iounmap (adev->mman.aper_base_kaddr); adev->mman.aper_base_kaddr =NULL ;/* Memory manager related */
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +16 -20
@@ -2121,18 +2121,23 @@ int amdgpu_ttm_init(struct amdgpu_device/* Change the size here instead of the init above so only lpfn is affected */ amdgpu_ttm_set_buffer_funcs_status (adev, false);#ifdef CONFIG_64BIT -#ifdef CONFIG_X86 -if (adev->gmc.xgmi.connected_to_cpu) - adev->mman.aper_base_kaddr =ioremap_cache (adev->gmc.aper_base, - adev->gmc.visible_vram_size); - -else if (adev->gmc.is_app_apu) +if (adev->gmc.xgmi.connected_to_cpu) { +void *kaddr =devm_memremap (adev->dev, adev->gmc.aper_base, + adev->gmc.visible_vram_size, +MEMREMAP_WB ); +if (IS_ERR (kaddr)) +return PTR_ERR (kaddr); + adev->mman.aper_base_kaddr = (__force void __iomem *)kaddr; + }else if (adev->gmc.is_app_apu) {DRM_DEBUG_DRIVER ("No need to ioremap when real vram size is 0\n" ); - else -#endif - adev->mman.aper_base_kaddr =ioremap_wc (adev->gmc.aper_base, - adev->gmc.visible_vram_size); + }else { + adev->mman.aper_base_kaddr =devm_ioremap_wc (adev->dev, + adev->gmc.aper_base, + adev->gmc.visible_vram_size); +if (!adev->mman.aper_base_kaddr) +return -ENOMEM ; + }#endif amdgpu_ttm_init_vram_resv_regions (adev);
@@ -2249,8 +2254,6 @@ int amdgpu_ttm_init(struct amdgpu_device*/ void amdgpu_ttm_fini (struct amdgpu_device *adev) { -int idx; -if (!adev->mman.initialized)return ;
@@ -2273,14 +2276,7 @@ void amdgpu_ttm_fini(struct amdgpu_devicamdgpu_ttm_unmark_vram_reserved (adev,AMDGPU_RESV_FW_VRAM_USAGE );amdgpu_ttm_unmark_vram_reserved (adev,AMDGPU_RESV_DRV_VRAM_USAGE ); -if (drm_dev_enter (adev_to_drm (adev), &idx)) { - -if (adev->mman.aper_base_kaddr) -iounmap (adev->mman.aper_base_kaddr); - adev->mman.aper_base_kaddr =NULL ; - -drm_dev_exit (idx); - } + adev->mman.aper_base_kaddr =NULL ;if (!adev->gmc.is_app_apu)amdgpu_vram_mgr_fini (adev);
Greg Kroah-Hartman
maintainerPATCH 717/744 drm/amd/pm: fix smu13 power limit range calculation
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yang Wang <[email protected]>
commit 220f22e1d66c1cfb63387eb1c4210f92a357c2d9 upstream.
SMU13 reports SocketPowerLimitAc/Dc as the default power limit, but MsgLimits.Power may carry a different firmware bound for the same PPT throttler. Using only the socket limit for both min and max can therefore expose an incorrect power range.
Keep the socket limit as the default, but derive the range from both values:
use the lower value for the min base and the higher value for the max base before applying OD percentages. Keep the current limit query independent from the cap calculation.
--- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c | 11 +++++++---- drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c | 15 ++++++++------- 2 files changed, 15 insertions(+), 11 deletions(-)
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +7 -4
@@ -2403,11 +2403,14 @@ static int smu_v13_0_0_get_power_limit(suint32_t pp_limit = smu->adev->pm.ac_power ? skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0 ] : skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0 ]; -uint32_t power_limit =0 , od_percent_upper =0 , od_percent_lower =0 ; +uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0 ][POWER_SOURCE_AC ]; +uint32_t min_limit =min_t (uint32_t, pp_limit, msg_limit); +uint32_t max_limit =max_t (uint32_t, pp_limit, msg_limit); +uint32_t od_percent_upper =0 , od_percent_lower =0 ;int ret;if (current_power_limit) { - ret =smu_v13_0_get_current_power_limit (smu, &power_limit); + ret =smu_v13_0_get_current_power_limit (smu, current_power_limit);if (ret) *current_power_limit = pp_limit; }
@@ -2430,12 +2433,12 @@ static int smu_v13_0_0_get_power_limit(s od_percent_upper, od_percent_lower, pp_limit);if (max_power_limit) { - *max_power_limit = pp_limit * (100 + od_percent_upper); + *max_power_limit = max_limit * (100 + od_percent_upper); *max_power_limit /=100 ; }if (min_power_limit) { - *min_power_limit = pp_limit * (100 - od_percent_lower); + *min_power_limit = min_limit * (100 - od_percent_lower); *min_power_limit /=100 ; }
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +8 -7
@@ -2385,15 +2385,16 @@ static int smu_v13_0_7_get_power_limit(suint32_t pp_limit = smu->adev->pm.ac_power ? skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0 ] : skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0 ]; -uint32_t power_limit =0 , od_percent_upper =0 , od_percent_lower =0 ; +uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0 ][POWER_SOURCE_AC ]; +uint32_t min_limit =min_t (uint32_t, pp_limit, msg_limit); +uint32_t max_limit =max_t (uint32_t, pp_limit, msg_limit); +uint32_t od_percent_upper =0 , od_percent_lower =0 ;int ret;if (current_power_limit) { - ret =smu_v13_0_get_current_power_limit (smu, &power_limit); + ret =smu_v13_0_get_current_power_limit (smu, current_power_limit);if (ret) - power_limit = pp_limit; - - *current_power_limit = power_limit; + *current_power_limit = pp_limit; }if (default_power_limit)
@@ -2414,12 +2415,12 @@ static int smu_v13_0_7_get_power_limit(s od_percent_upper, od_percent_lower, pp_limit);if (max_power_limit) { - *max_power_limit = pp_limit * (100 + od_percent_upper); + *max_power_limit = max_limit * (100 + od_percent_upper); *max_power_limit /=100 ; }if (min_power_limit) { - *min_power_limit = pp_limit * (100 - od_percent_lower); + *min_power_limit = min_limit * (100 - od_percent_lower); *min_power_limit /=100 ; }
Greg Kroah-Hartman
maintainerPATCH 718/744 drm/amdgpu: fix check in amdgpu_hmm_invalidate_gfx
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian König <[email protected]>
commit 52f650963d8825e97a0ccdd2b616f8a01d9d3d38 upstream.
For a short moment during alloc/free the userptr BO is not part of his VM, so bo->vm_bo can be NULL.
Keep a reference to the VM root PD as parent of the userptr BO so that we can always use that to wait for all submissions of the VM instead of only the one involving the userptr BO.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +1 -0
@@ -535,6 +535,7 @@ int amdgpu_gem_userptr_ioctl(struct drm_ bo =gem_to_amdgpu_bo (gobj); bo->preferred_domains =AMDGPU_GEM_DOMAIN_GTT ; bo->allowed_domains =AMDGPU_GEM_DOMAIN_GTT ; + bo->parent =amdgpu_bo_ref (fpriv->vm.root.bo); r =amdgpu_ttm_tt_set_userptr (&bo->tbo, args->addr, args->flags);if (r) goto release_object;
drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c +1 -2
@@ -67,7 +67,6 @@ static bool amdgpu_hmm_invalidate_gfx(st { struct amdgpu_bo *bo = container_of(mni, struct amdgpu_bo, notifier);struct amdgpu_device *adev =amdgpu_ttm_adev (bo->tbo.bdev); -struct amdgpu_bo *vm_root = bo->vm_bo->vm->root.bo;long r;if (!mmu_notifier_range_blockable (range))
@@ -78,7 +77,7 @@ static bool amdgpu_hmm_invalidate_gfx(stmmu_interval_set_seq (mni, cur_seq);amdgpu_vm_bo_invalidate (bo, false); - r =dma_resv_wait_timeout (vm_root->tbo.base.resv, + r =dma_resv_wait_timeout (bo->parent->tbo.base.resv,DMA_RESV_USAGE_BOOKKEEP , false,MAX_SCHEDULE_TIMEOUT );mutex_unlock (&adev->notifier_lock);
Greg Kroah-Hartman
maintainerPATCH 719/744 selftests: drv-net: add missing kconfig for psp.py
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthieu Baerts (NGI0) <[email protected]>
[ Upstream commit c25dd7439f84cf607e13d6de8cc1c79cd51f56ff ]
This psp.py selftest was failing on my side when only using the drivers/net config file on top of the default one -- the recommended way to execute selftest targets.
It looks like some kernel config are needed to execute the new tc commands.
Note that this was not visible on NIPA, because these tests are executed with the drivers/net/hw ones, combining the two config files, and the hw one contains the missing ones.
--- tools/testing/selftests/drivers/net/config | 3 +++ 1 file changed, 3 insertions(+)
tools/testing/selftests/drivers/net/config +3 -0
@@ -4,11 +4,14 @@ CONFIG_DEBUG_INFO_BTF_MODULES=n CONFIG_INET_PSP=y CONFIG_IPV6=y CONFIG_MACSEC=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_CLS_BPF=y CONFIG_NETCONSOLE=m CONFIG_NETCONSOLE_DYNAMIC=y CONFIG_NETCONSOLE_EXTENDED_LOG=y CONFIG_NETDEVSIM=m CONFIG_NET_SCH_ETF=m CONFIG_NET_SCH_FQ=m +CONFIG_NET_SCH_INGRESS=y CONFIG_VLAN_8021Q=m CONFIG_XDP_SOCKETS=y
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 720/744 ksmbd: validate num_subauth when copying ACE in set_ntacl_dacl
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haofeng Li <[email protected]>
commit 47f0b34f6bc98ed85bfdc293e8f3e432ec24958d upstream.
set_ntacl_dacl() copies each ACE from the attacker-controlled stored security descriptor verbatim into the response DACL without checking sid.num_subauth. The ACE bytes (including an unchecked num_subauth) originate from an authenticated SMB2_SET_INFO(SecInfo=DACL) that is stored raw via ksmbd_vfs_set_sd_xattr(); parse_dacl() rejects a bad ACE with break rather than an error, so parse_sec_desc() still returns success and the malformed SD reaches the xattr intact.
On a subsequent SMB2_QUERY_INFO(SecInfo=DACL) for an inode carrying a POSIX access ACL, build_sec_desc() -> set_ntacl_dacl() -> set_posix_acl_entries_dacl() walks the copied ACEs and reads
ntace->sid.sub_auth[ntace->sid.num_subauth - 1]
with num_subauth taken straight from the stored SD. Since sub_auth[] is fixed at SID_MAX_SUB_AUTHORITIES (15), a crafted num_subauth (e.g.
255) drives an out-of-bounds heap read of ~1 KB with an offset fully controlled by an authenticated client.
The sibling functions already gate this field:
parse_dacl() -- num_subauth == 0 || > SID_MAX_SUB_AUTHORITIES parse_sid() -- num_subauth > SID_MAX_SUB_AUTHORITIES smb_copy_sid() -- min_t(u8, num_subauth, SID_MAX_SUB_AUTHORITIES)
set_ntacl_dacl() is the lone inconsistent path that omits the check.
Add the same num_subauth validation in set_ntacl_dacl() before copying the ACE, matching the gate already enforced by parse_dacl().
--- fs/smb/server/smbacl.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
fs/smb/server/smbacl.c +7 -1
@@ -745,12 +745,18 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,if (nt_ace_size > aces_size)break ; +if (ntace->sid.num_subauth ==0 || + ntace->sid.num_subauth >SID_MAX_SUB_AUTHORITIES ) + goto next_ace; +memcpy ((char *)pndace + size, ntace, nt_ace_size);if (check_add_overflow (size, nt_ace_size, &size))break ; + num_aces++; + +next_ace: aces_size -= nt_ace_size; ntace = (struct smb_ace *)((char *)ntace + nt_ace_size); - num_aces++; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 721/744 ksmbd: restore DACL size on check_add_overflow() to avoid malformed ACL
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Guan <[email protected]>
commit bbf0a8e931204ecdab494a88d43b0a24a04285c5 upstream.
check_add_overflow() unconditionally writes the truncated sum into *d even on overflow, per its contract in include/linux/overflow.h. The four check_add_overflow() guards in set_posix_acl_entries_dacl() and set_ntacl_dacl() break out of the ACE-building loops on overflow, but the truncated *size is then consumed downstream at the end of set_ntacl_dacl():
pndacl->size = cpu_to_le16(le16_to_cpu(pndacl->size) + size);
This produces an on-wire NT ACL whose pndacl->size under-reports the bytes actually written by the preceding fill_ace_for_sid()/memcpy() calls, yielding a malformed ACL that can trigger out-of-bounds reads when re-parsed by clients or ksmbd itself.
Restore *size to its pre-addition value on each overflow branch (via *size -= ace_sz / size -= nt_ace_size) so that after the break, *size once again holds the cumulative size of the successfully-written ACEs. The committed ACL is then truncated-but-self-consistent rather than malformed.
The ksmbd DACL builders are the only check_add_overflow() sites found where an overflow path breaks out of a loop and the destination value is consumed afterward. The other nearby break-style cases either return -EINVAL on overflow (transport_ipc.c) or break without consuming the overflowed destination value afterward (buildid.c).
--- fs/smb/server/smbacl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
fs/smb/server/smbacl.c +6 -1
@@ -649,6 +649,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap, ace_sz =fill_ace_for_sid (ntace, sid,ACCESS_ALLOWED , flags, pace->e_perm,0777 );if (check_add_overflow (*size, ace_sz, size)) { + *size -= ace_sz;kfree (sid);break ; }
@@ -663,6 +664,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap, ace_sz =fill_ace_for_sid (ntace, sid,ACCESS_ALLOWED ,0x03 , pace->e_perm,0777 );if (check_add_overflow (*size, ace_sz, size)) { + *size -= ace_sz;kfree (sid);break ; }
@@ -708,6 +710,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap, ace_sz =fill_ace_for_sid (ntace, sid,ACCESS_ALLOWED ,0x0b , pace->e_perm,0777 );if (check_add_overflow (*size, ace_sz, size)) { + *size -= ace_sz;kfree (sid);break ; }
@@ -750,8 +753,10 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap, goto next_ace;memcpy ((char *)pndace + size, ntace, nt_ace_size); -if (check_add_overflow (size, nt_ace_size, &size)) +if (check_add_overflow (size, nt_ace_size, &size)) { + size -= nt_ace_size;break ; + } num_aces++; next_ace:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 722/744 ksmbd: bound DACL dedup walk to copied ACEs
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
commit 58d97fcd0bf1aee694e244cc28635b9df95b543b upstream.
set_ntacl_dacl() can stop copying ACEs before consuming the full input DACL when size accounting overflows.
When that happens, num_aces reflects only the ACEs that were actually copied into the output DACL, but set_posix_acl_entries_dacl() still receives nt_num_aces and uses it to walk the existing ACE array during dedup.
That makes the dedup walk scan past the copied ACE array and inspect buffer tail that does not contain valid ACEs.
Split the two meanings currently carried by the NT ACE count. Pass the number of copied NT ACEs to bound the dedup walk, and preserve the original "input DACL had NT ACEs" state separately for the Everyone/default ACL fallback.
This keeps the dedup walk aligned with the ACEs that are actually present in the rebuilt DACL.
--- fs/smb/server/smbacl.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
fs/smb/server/smbacl.c +10 -6
@@ -595,7 +595,8 @@ static void parse_dacl(struct mnt_idmap *idmap,static void set_posix_acl_entries_dacl (struct mnt_idmap *idmap,struct smb_ace *pndace,struct smb_fattr *fattr,u16 *num_aces, -u16 *size,u32 nt_aces_num) +u16 *size,u16 existing_nt_aces, +bool had_nt_aces) {struct posix_acl_entry *pace;struct smb_sid *sid;
@@ -627,14 +628,14 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap, gid =posix_acl_gid_translate (idmap, pace);id_to_sid (gid,SIDUNIX_GROUP , sid); - }else if (pace->e_tag ==ACL_OTHER && !nt_aces_num) { + }else if (pace->e_tag ==ACL_OTHER && !had_nt_aces) {smb_copy_sid (sid, &sid_everyone); }else {kfree (sid);continue ; } ntace = pndace; -for (j =0 ; j < nt_aces_num; j++) { +for (j =0 ; j < existing_nt_aces; j++) {if (ntace->sid.sub_auth[ntace->sid.num_subauth -1 ] == sid->sub_auth[sid->num_subauth -1 ]) goto pass_same_sid;
@@ -678,7 +679,7 @@ static void set_posix_acl_entries_dacl(struct mnt_idmap *idmap,kfree (sid); } -if (nt_aces_num) +if (had_nt_aces)return ; posix_default_acl:
@@ -732,6 +733,7 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap, {struct smb_ace *ntace, *pndace;u16 nt_num_aces =le16_to_cpu (nt_dacl->num_aces), num_aces =0 ; +u16 copied_nt_aces;unsigned short size =0 ;int i;
@@ -765,8 +767,10 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap, } } + copied_nt_aces = num_aces;set_posix_acl_entries_dacl (idmap, pndace, fattr, - &num_aces, &size, nt_num_aces); + &num_aces, &size, copied_nt_aces, + nt_num_aces !=0 ); pndacl->num_aces =cpu_to_le16 (num_aces); pndacl->size =cpu_to_le16 (le16_to_cpu (pndacl->size) + size); }
@@ -784,7 +788,7 @@ static void set_mode_dacl(struct mnt_idmap *idmap,if (fattr->cf_acls) {set_posix_acl_entries_dacl (idmap, pndace, fattr, - &num_aces, &size, num_aces); + &num_aces, &size, num_aces, false); goto out; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 723/744 ksmbd: validate ACE size against SID sub-authorities
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Namjae Jeon <[email protected]>
commit 5152c6d49e3fd4e9f2e857c57527aead752f1f87 upstream.
set_ntacl_dacl() validates sid.num_subauth before copying an ACE, but does not verify that the declared ACE size contains all sub-authorities described by that field. An undersized ACE can therefore be copied and later make the POSIX ACL deduplication walk inspect data beyond the copied ACE boundary.
The existing initial bound check is also too small. It only ensures that the ACE size field is accessible before set_ntacl_dacl() reads sid.num_subauth farther into the input buffer.
Require enough input for the fixed SID header before accessing num_subauth, reject ACEs smaller than that header, and skip ACEs whose declared size cannot contain the complete SID. This makes the validation consistent with the other ACE walk paths.
--- fs/smb/server/smbacl.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
fs/smb/server/smbacl.c +10 -3
@@ -743,15 +743,22 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap,for (i =0 ; i < nt_num_aces; i++) {unsigned short nt_ace_size; -if (offsetof(struct smb_ace , access_req) > aces_size) +if (aces_size < offsetof(struct smb_ace , sid) + +CIFS_SID_BASE_SIZE )break ; nt_ace_size =le16_to_cpu (ntace->size); -if (nt_ace_size > aces_size) +if (nt_ace_size > aces_size || + nt_ace_size < offsetof(struct smb_ace , sid) + +CIFS_SID_BASE_SIZE )break ;if (ntace->sid.num_subauth ==0 || - ntace->sid.num_subauth >SID_MAX_SUB_AUTHORITIES ) + ntace->sid.num_subauth >SID_MAX_SUB_AUTHORITIES || + nt_ace_size < offsetof(struct smb_ace , sid) + +CIFS_SID_BASE_SIZE + +sizeof (__le32) * + ntace->sid.num_subauth) goto next_ace;memcpy ((char *)pndace + size, ntace, nt_ace_size);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 724/744 drm/amd/display: Fix DTB DTO updates breaking live pixel rate sources
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harry Wentland <[email protected]>
commit 76a2db58e95e328007043f54ac3c7336ccbee440 upstream.
dcn32_update_clocks_update_dtb_dto() and its dcn35 counterpart reprogram the DTB DTO of every timing generator in the context whenever the DTBCLK reference changes, passing a zeroed pixel rate and never setting is_hdmi. Both dccg set_dtbclk_dto() implementations treat a zero pixel rate as a disable request. On dcn32 that branch drives PIPE_DTO_SRC_SEL to the DP DTO source, so a timing generator actively scanning out an HDMI stream has its pixel rate source re-muxed out from under the live raster and the OTG stops on the spot. On dcn35 it clears DTBCLK_DTO_ENABLE and restores DTBCLK_Pn clock gating, which does the same to a live 128b/132b stream.
Two displays where only one runs a 128b/132b link hit this reliably. is_dtbclk_required() holds the DTBCLK reference high while both are active, and the moment the 128b/132b stream is torn down (compositor switch, display disable, hot-unplug) the next safe_to_lower pass drops the reference to the lowest DPM level and the DTO walk freezes the surviving screen. On Navi31 the DAL mailbox then goes deaf on the DISPCLK hard-min that follows the walk in dcn32_update_clocks(), stranding both SMU mailboxes until reboot.
Set is_hdmi for HDMI and DVI signals so the disable path leaves the pixel rate source selection on the HDMI path, and pass the real pixel rate for 128b/132b streams so a reference change rescales their DTO instead of disabling it.
[ mschwartz: dcn32 and dcn35 clk_mgr hunks only. The rest is HDMI FRL
enablement, absent before 7.2, so the FRL conditions and the req_audio_dtbclk_khz assignment they guard are dropped and the FRL-centric changelog is rewritten. Added the pipe_ctx->stream check the new dereferences need. ]
--- .../gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c | 9 ++++++++- .../gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn32/dcn32_clk_mgr.c +8 -1
@@ -276,13 +276,20 @@ static void dcn32_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,struct dtbclk_dto_params dto_params = {0 };/* use mask to program DTO once per tg */ -if (pipe_ctx->stream_res.tg && +if (pipe_ctx->stream && pipe_ctx->stream_res.tg && !(tg_mask & (1 << pipe_ctx->stream_res.tg->inst))) { tg_mask |= (1 << pipe_ctx->stream_res.tg->inst); dto_params.otg_inst = pipe_ctx->stream_res.tg->inst; dto_params.ref_dtbclk_khz = ref_dtbclk_khz; +if (dccg->ctx->dc->link_srv->dp_is_128b_132b_signal (pipe_ctx)) + dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz /10 ; + +if (dc_is_hdmi_signal (pipe_ctx->stream->signal) || +dc_is_dvi_signal (pipe_ctx->stream->signal)) + dto_params.is_hdmi = true; + dccg->funcs->set_dtbclk_dto (clk_mgr->dccg, &dto_params);//dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params); }
drivers/gpu/drm/amd/display/dc/clk_mgr/dcn35/dcn35_clk_mgr.c +8 -1
@@ -264,13 +264,20 @@ static void dcn35_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr,struct dtbclk_dto_params dto_params = {0 };/* use mask to program DTO once per tg */ -if (pipe_ctx->stream_res.tg && +if (pipe_ctx->stream && pipe_ctx->stream_res.tg && !(tg_mask & (1 << pipe_ctx->stream_res.tg->inst))) { tg_mask |= (1 << pipe_ctx->stream_res.tg->inst); dto_params.otg_inst = pipe_ctx->stream_res.tg->inst; dto_params.ref_dtbclk_khz = ref_dtbclk_khz; +if (dccg->ctx->dc->link_srv->dp_is_128b_132b_signal (pipe_ctx)) + dto_params.pixclk_khz = pipe_ctx->stream->timing.pix_clk_100hz /10 ; + +if (dc_is_hdmi_signal (pipe_ctx->stream->signal) || +dc_is_dvi_signal (pipe_ctx->stream->signal)) + dto_params.is_hdmi = true; + dccg->funcs->set_dtbclk_dto (clk_mgr->dccg, &dto_params);//dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 725/744 audit: use unsigned int instead of unsigned
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ricardo Robaina <[email protected]>
[ Upstream commit 8b226771014beab1292081151a99530886ce54b4 ]
Address checkpatch.pl warning below, across the audit subsystem:
WARNING: Prefer 'unsigned int' to bare use of 'unsigned'
Minor cleanup, no functional changes.
Stable-dep-of: 81905b5acbe7 ("audit: fix recursive locking deadlock in audit_dupe_exe()")
--- include/linux/audit.h | 4 ++-- include/linux/audit_arch.h | 12 ++++++------ kernel/audit.c | 2 +- kernel/audit.h | 2 +- kernel/audit_tree.c | 2 +- kernel/audit_watch.c | 2 +- kernel/auditfilter.c | 8 ++++---- kernel/auditsc.c | 2 +- lib/compat_audit.c | 12 ++++++------ 9 files changed, 23 insertions(+), 23 deletions(-)
include/linux/audit.h +2 -2
@@ -133,8 +133,8 @@ enum audit_nfcfgop { AUDIT_NFT_OP_INVALID, }; -extern int __init audit_register_class (int class,unsigned *list); -extern int audit_classify_syscall (int abi,unsigned syscall); +extern int __init audit_register_class (int class,unsigned int *list); +extern int audit_classify_syscall (int abi,unsigned int syscall);extern int audit_classify_arch (int arch);/* audit_names->type values */
include/linux/audit_arch.h +6 -6
@@ -21,13 +21,13 @@ enum auditsc_class_t {AUDITSC_NVALS /* count */ }; -extern int audit_classify_compat_syscall (int abi,unsigned syscall); +extern int audit_classify_compat_syscall (int abi,unsigned int syscall);/* only for compat system calls */ -extern unsigned compat_write_class[]; -extern unsigned compat_read_class[]; -extern unsigned compat_dir_class[]; -extern unsigned compat_chattr_class[]; -extern unsigned compat_signal_class[]; +extern unsigned int compat_write_class[]; +extern unsigned int compat_read_class[]; +extern unsigned int compat_dir_class[]; +extern unsigned int compat_chattr_class[]; +extern unsigned int compat_signal_class[];#endif
kernel/audit.c +1 -1
@@ -2035,7 +2035,7 @@ void audit_log_vformat(struct audit_buff* here and AUDIT_BUFSIZ is at least 1024, then we can * log everything that printk could have logged. */ avail =audit_expand (ab, -max_t (unsigned,AUDIT_BUFSIZ ,1 +len-avail)); + max_t(unsigned int, AUDIT_BUFSIZ, 1+len-avail));if (!avail) goto out_va_end; len =vsnprintf (skb_tail_pointer (skb), avail, fmt, args2);
kernel/audit.h +1 -1
@@ -233,7 +233,7 @@ static inline int audit_hash_ino(u64 ino/* Indicates that audit should log the full pathname. */ #define AUDIT_NAME_FULL -1 -extern int audit_match_class (int class,unsigned syscall); +extern int audit_match_class (int class,unsigned int syscall);extern int audit_comparator (const u32 left,const u32 op,const u32 right);extern int audit_uid_comparator (kuid_t left,u32 op,kuid_t right);extern int audit_gid_comparator (kgid_t left,u32 op,kgid_t right);
kernel/audit_tree.c +1 -1
@@ -33,7 +33,7 @@ struct audit_chunk {struct audit_node {struct list_head list;struct audit_tree *owner; -unsigned index;/* index; upper bit indicates 'will prune' */ +unsigned int index;/* index; upper bit indicates 'will prune' */ } owners[] __counted_by(count); };
kernel/audit_watch.c +1 -1
@@ -244,7 +244,7 @@ static void audit_watch_log_rule_change(/* Update inode info in audit rules based on filesystem event. */ static void audit_update_watch (struct audit_parent *parent,const struct qstr *dname,dev_t dev, -u64 ino,unsigned invalidating) +u64 ino,unsigned int invalidating) {struct audit_watch *owatch, *nwatch, *nextw;struct audit_krule *r, *nextr;
kernel/auditfilter.c +4 -4
@@ -165,13 +165,13 @@ static inline int audit_to_inode(structstatic __u32 *classes[AUDIT_SYSCALL_CLASSES ]; -int __init audit_register_class (int class,unsigned *list) +int __init audit_register_class (int class,unsigned int *list) {__u32 *p =kcalloc (AUDIT_BITMASK_SIZE ,sizeof (__u32),GFP_KERNEL );if (!p)return -ENOMEM ;while (*list != ~0U ) { -unsigned n = *list++; +unsigned int n = *list++;if (n >=AUDIT_BITMASK_SIZE *32 -AUDIT_SYSCALL_CLASSES ) {kfree (p);return -EINVAL ;
@@ -186,7 +186,7 @@ int __init audit_register_class(int clasreturn 0 ; } -int audit_match_class (int class,unsigned syscall) +int audit_match_class (int class,unsigned int syscall) {if (unlikely (syscall >=AUDIT_BITMASK_SIZE *32 ))return 0 ;
@@ -237,7 +237,7 @@ static int audit_match_signal(struct aud/* Common user-space to kernel rule translation. */ static inline struct audit_entry *audit_to_entry_common (struct audit_rule_data *rule) { -unsigned listnr; +unsigned int listnr;struct audit_entry *entry;int i, err;
kernel/auditsc.c +1 -1
@@ -150,7 +150,7 @@ static const struct audit_nfcfgop_tab austatic int audit_match_perm (struct audit_context *ctx,int mask) { -unsigned n; +unsigned int n;if (unlikely (!ctx))return 0 ;
lib/compat_audit.c +6 -6
@@ -4,32 +4,32 @@#include <linux/audit_arch.h> #include <asm/unistd32.h> -unsigned compat_dir_class[] = { +unsigned int compat_dir_class[] = { #include <asm-generic/audit_dir_write.h> ~0U }; -unsigned compat_read_class[] = { +unsigned int compat_read_class[] = { #include <asm-generic/audit_read.h> ~0U }; -unsigned compat_write_class[] = { +unsigned int compat_write_class[] = { #include <asm-generic/audit_write.h> ~0U }; -unsigned compat_chattr_class[] = { +unsigned int compat_chattr_class[] = { #include <asm-generic/audit_change_attr.h> ~0U }; -unsigned compat_signal_class[] = { +unsigned int compat_signal_class[] = { #include <asm-generic/audit_signal.h> ~0U }; -int audit_classify_compat_syscall (int abi,unsigned syscall) +int audit_classify_compat_syscall (int abi,unsigned int syscall) {switch (syscall) {#ifdef __NR_open
Greg Kroah-Hartman
maintainerPATCH 726/744 audit: fix recursive locking deadlock in audit_dupe_exe()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ricardo Robaina <[email protected]>
[ Upstream commit 81905b5acbe77284734438df3fbec1158e6429a3 ]
A deadlock occurs in the audit subsystem when duplicating executable-related rules.
When a file is moved (e.g., via do_renameat2()), the VFS layer locks the parent directory (I_MUTEX_PARENT), which synchronously triggers an fsnotify_move event. If an existing executable audit rule matches the file being moved, the audit subsystem catches this event and calls audit_dupe_exe() to duplicate the watch and update the rule. Then, audit_alloc_mark() would call kern_path_parent() to resolve the path, leading to a blind attempt to acquire the exact same I_MUTEX_PARENT lock already held by the task, resulting in the following recursive locking deadlock:
============================================
WARNING: possible recursive locking detected 6.12.0-55.27.1.el10_0.x86_64+debug #1 Not tainted
--------------------------------------------
mv/5099 is trying to acquire lock:
ffff888132845358 (&inode->i_sb->s_type->i_mutex_dir_key/1){+.+.}-{3:3},
at: __kern_path_locked+0x10a/0x2f0
but task is already holding lock:
ffff888132846b58 (&inode->i_sb->s_type->i_mutex_dir_key/1){+.+.}-{3:3},
at: lock_two_directories+0x13f/0x2b0
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0
---- lock(&inode->i_sb->s_type->i_mutex_dir_key/1);
lock(&inode->i_sb->s_type->i_mutex_dir_key/1);
*** DEADLOCK ***
May be due to missing lock nesting notation
6 locks held by mv/5099:
#0: ffff888112a9c440 (sb_writers#13)
at: do_renameat2+0x34c/0xbc0
#1: ffff888112a9c790 (&type->s_vfs_rename_key#3)
at: do_renameat2+0x415/0xbc0
#2: ffff888132846b58 (&inode->i_sb->s_type->i_mutex_dir_key/1)
at: lock_two_directories+0x13f/0x2b0
#3: ffff888132845358 (&inode->i_sb->s_type->i_mutex_dir_key/5)
at: lock_two_directories+0x175/0x2b0
#4: ffffffffb3a1fb10 (&fsnotify_mark_srcu)
at: fsnotify+0x454/0x28a0
#5: ffffffffaf886230 (audit_filter_mutex)
at: audit_update_watch+0x36/0x11e0
stack backtrace: Call Trace: <TASK> dump_stack_lvl+0x6f/0xb0 print_deadlock_bug.cold+0xbd/0xca validate_chain+0x83a/0xf00 __lock_acquire+0xcac/0x1d20 lock_acquire.part.0+0x11b/0x360 down_write_nested+0x9f/0x230 __kern_path_locked+0x10a/0x2f0 kern_path_locked+0x26/0x40 audit_alloc_mark+0xfb/0x4f0 audit_dupe_exe+0x6c/0xe0 audit_dupe_rule+0x6c2/0xc00 audit_update_watch+0x4cc/0x11e0 audit_watch_handle_event+0x12c/0x1b0 send_to_group+0x5d0/0x8b0 fsnotify+0x615/0x28a0 fsnotify_move+0x1d8/0x630 vfs_rename+0xdcd/0x1df0 do_renameat2+0x9d4/0xbc0 __x64_sys_renameat+0x192/0x260 do_syscall_64+0x92/0x180 entry_SYSCALL_64_after_hwframe+0x76/0x7e RIP: 0033:0x7f0491fe8c4e Code: 0f 1f 40 00 48 8b 15 c1 e1 16 00 f7 d8 64 89 02 b8 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa 49 89 ca b8 08 01 00 00 0f 05 <48> 3d 00 f0 ff ff 77 0a c3 66 0f 1f 84 00 00 00 00 00 48 8b 15 89 RSP: 002b:00007ffc7210bf38 EFLAGS: 00000246 ORIG_RAX: 0000000000000108 RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f0491fe8c4e RDX: 0000000000000003 RSI: 00007ffc7210e6c8 RDI: 00000000ffffff9c RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000001 R10: 00005575eb2dae2a R11: 0000000000000246 R12: 00005575eb2dae2a R13: 00007ffc7210e6c8 R14: 0000000000000003 R15: 00000000ffffff9c </TASK>
The aforementioned deadlock can be consistently reproduced by running the script below:
audit-dupe-exe-deadlock.sh
--------------------------
#!/bin/bash
auditctl -D
mkdir -p /tmp/foo
touch /tmp/file
auditctl -a always,exit -F exe=/tmp/file -F path=/tmp/file -S all -k dr mv /tmp/file /tmp/foo/file
rm -Rf /tmp/foo
This patch fixes the issue by introducing struct audit_watch_ctx to pass the fsnotify event context down to audit_alloc_mark(). By utilizing the already-resolved directory inode provided by the event, we bypass the kern_path_parent() path resolution entirely, safely avoiding the recursive lock. Furthermore, it explicitly allows duplicate fsnotify marks (allow_dups = 1) during the rename update, allowing the new rule's mark to safely coexist with the old rule's mark until the old rule is freed.
P.S.: This issue was identified and reproduced during a comprehensive code coverage analysis of the audit subsystem. The full report is available at the link below:
https://people.redhat.com/rrobaina/audit-code-coverage-analysis.pdf
P.P.S: With the permission of both Ricardo and Nathan, I've squashed a fixup patch from Nathan that addresses a compile time error when CONFIG_AUDITSYSCALL=n.
--- kernel/audit.h | 17 ++++++++++++----- kernel/audit_fsnotify.c | 32 +++++++++++++++++++++++--------- kernel/audit_watch.c | 25 +++++++++++++++++-------- kernel/auditfilter.c | 9 +++++---- 4 files changed, 57 insertions(+), 26 deletions(-)
kernel/audit.h +12 -5
@@ -256,8 +256,13 @@ extern int audit_del_rule(struct audit_eextern void audit_free_rule_rcu (struct rcu_head *head);extern struct list_head audit_filter_list[]; -extern struct audit_entry *audit_dupe_rule (struct audit_krule *old); +struct audit_watch_ctx { +struct inode *dir; +struct inode *child; +}; +extern struct audit_entry *audit_dupe_rule (struct audit_krule *old, +struct audit_watch_ctx *ctx);extern void audit_log_d_path_exe (struct audit_buffer *ab,struct mm_struct *mm);
@@ -280,13 +285,15 @@ extern char *audit_watch_path(struct audextern int audit_watch_compare (struct audit_watch *watch,u64 ino,dev_t dev);extern struct audit_fsnotify_mark *audit_alloc_mark (struct audit_krule *krule, -char *pathname,int len); +char *pathname,int len, +struct audit_watch_ctx *ctx);extern char *audit_mark_path (struct audit_fsnotify_mark *mark);extern void audit_remove_mark (struct audit_fsnotify_mark *audit_mark);extern void audit_remove_mark_rule (struct audit_krule *krule);extern int audit_mark_compare (struct audit_fsnotify_mark *mark,u64 ino,dev_t dev); -extern int audit_dupe_exe (struct audit_krule *new,struct audit_krule *old); +extern int audit_dupe_exe (struct audit_krule *new,struct audit_krule *old, +struct audit_watch_ctx *ctx);extern int audit_exe_compare (struct task_struct *tsk,struct audit_fsnotify_mark *mark);
@@ -317,13 +324,13 @@ extern struct list_head *audit_killed_tr#define audit_watch_path (w) ""#define audit_watch_compare (w, i, d) 0 -#define audit_alloc_mark (k, p, l) (ERR_PTR(-EINVAL)) +#define audit_alloc_mark (k, p, l, c) (ERR_PTR(-EINVAL))#define audit_mark_path (m) ""#define audit_remove_mark (m) do { } while (0)#define audit_remove_mark_rule (k) do { } while (0)#define audit_mark_compare (m, i, d) 0#define audit_exe_compare (t, m) (-EINVAL) -#define audit_dupe_exe (n, o) (-EINVAL) +#define audit_dupe_exe (n, o, c) (-EINVAL)#define audit_remove_tree_rule (rule) BUG()#define audit_add_tree_rule (rule) -EINVAL
kernel/audit_fsnotify.c +23 -9
@@ -71,19 +71,30 @@ static void audit_update_mark(struct aud audit_mark->ino = inode ? inode->i_ino :AUDIT_INO_UNSET ; } -struct audit_fsnotify_mark *audit_alloc_mark (struct audit_krule *krule,char *pathname,int len) +struct audit_fsnotify_mark *audit_alloc_mark (struct audit_krule *krule,char *pathname, +int len,struct audit_watch_ctx *ctx) {struct audit_fsnotify_mark *audit_mark;struct path path;struct dentry *dentry; -int ret; +struct inode *dir, *child; +int ret, allow_dups;if (pathname[0 ] !='/' || pathname[len-1 ] =='/' )return ERR_PTR (-EINVAL ); - dentry =kern_path_parent (pathname, &path); -if (IS_ERR (dentry)) -return ERR_CAST (dentry);/* returning an error */ +if (!ctx) { + dentry =kern_path_parent (pathname, &path); +if (IS_ERR (dentry)) +return ERR_CAST (dentry);/* returning an error */ + dir =d_inode (path.dentry); + child =d_inode (dentry); + allow_dups =0 ; + }else { + dir = ctx->dir; + child = ctx->child; + allow_dups =1 ; + } audit_mark =kzalloc_obj (*audit_mark);if (unlikely (!audit_mark)) {
@@ -94,18 +105,21 @@ struct audit_fsnotify_mark *audit_alloc_fsnotify_init_mark (&audit_mark->mark, audit_fsnotify_group); audit_mark->mark.mask =AUDIT_FS_EVENTS ; audit_mark->path = pathname; -audit_update_mark (audit_mark, dentry->d_inode); audit_mark->rule = krule; - ret =fsnotify_add_inode_mark (&audit_mark->mark, path.dentry->d_inode,0 ); +audit_update_mark (audit_mark, child); + ret =fsnotify_add_inode_mark (&audit_mark->mark, dir, allow_dups); +if (ret <0 ) { audit_mark->path =NULL ;fsnotify_put_mark (&audit_mark->mark); audit_mark =ERR_PTR (ret); } out: -dput (dentry); -path_put (&path); +if (!ctx) { +dput (dentry); +path_put (&path); + }return audit_mark; }
kernel/audit_watch.c +17 -8
@@ -244,7 +244,8 @@ static void audit_watch_log_rule_change(/* Update inode info in audit rules based on filesystem event. */ static void audit_update_watch (struct audit_parent *parent,const struct qstr *dname,dev_t dev, -u64 ino,unsigned int invalidating) +u64 ino,unsigned int invalidating, +struct audit_watch_ctx *ctx) {struct audit_watch *owatch, *nwatch, *nextw;struct audit_krule *r, *nextr;
@@ -280,7 +281,7 @@ static void audit_update_watch(struct aulist_del (&oentry->rule.rlist);list_del_rcu (&oentry->list); - nentry =audit_dupe_rule (&oentry->rule); + nentry =audit_dupe_rule (&oentry->rule, ctx);if (IS_ERR (nentry)) {list_del (&oentry->rule.list);audit_panic ("error updating watch, removing" );
@@ -479,10 +480,17 @@ static int audit_watch_handle_event(struif (WARN_ON_ONCE (inode_mark->group != audit_watch_group))return 0 ; -if (mask & (FS_CREATE |FS_MOVED_TO ) && inode) -audit_update_watch (parent, dname, inode->i_sb->s_dev, inode->i_ino,0 ); -else if (mask & (FS_DELETE |FS_MOVED_FROM )) -audit_update_watch (parent, dname,AUDIT_DEV_UNSET ,AUDIT_INO_UNSET ,1 ); +if (mask & (FS_CREATE |FS_MOVED_TO ) && inode) { +struct audit_watch_ctx ctx = { .dir = dir, .child = inode }; + +audit_update_watch (parent, dname, inode->i_sb->s_dev, inode->i_ino,0 , + &ctx); + }else if (mask & (FS_DELETE |FS_MOVED_FROM )) { +struct audit_watch_ctx ctx = { .dir = dir, .child =NULL }; + +audit_update_watch (parent, dname,AUDIT_DEV_UNSET ,AUDIT_INO_UNSET ,1 , + &ctx); + }else if (mask & (FS_DELETE_SELF |FS_UNMOUNT |FS_MOVE_SELF ))audit_remove_parent_watches (parent);
@@ -505,7 +513,8 @@ static int __init audit_watch_init(void) }device_initcall (audit_watch_init); -int audit_dupe_exe (struct audit_krule *new,struct audit_krule *old) +int audit_dupe_exe (struct audit_krule *new,struct audit_krule *old, +struct audit_watch_ctx *ctx) {struct audit_fsnotify_mark *audit_mark;char *pathname;
@@ -514,7 +523,7 @@ int audit_dupe_exe(struct audit_krule *nif (!pathname)return -ENOMEM ; - audit_mark =audit_alloc_mark (new, pathname,strlen (pathname)); + audit_mark =audit_alloc_mark (new, pathname,strlen (pathname), ctx);if (IS_ERR (audit_mark)) {kfree (pathname);return PTR_ERR (audit_mark);
kernel/auditfilter.c +5 -4
@@ -589,7 +589,7 @@ static struct audit_entry *audit_data_to err =PTR_ERR (str); goto exit_free; } - audit_mark =audit_alloc_mark (&entry->rule, str, f_val); + audit_mark =audit_alloc_mark (&entry->rule, str, f_val,NULL );if (IS_ERR (audit_mark)) {kfree (str); err =PTR_ERR (audit_mark);
@@ -816,7 +816,8 @@ static inline int audit_dupe_lsm_field(s* rule with the new rule in the filterlist, then free the old rule. * The rlist element is undefined; list manipulations are handled apart from * the initial copy. */ -struct audit_entry *audit_dupe_rule (struct audit_krule *old) +struct audit_entry *audit_dupe_rule (struct audit_krule *old, +struct audit_watch_ctx *ctx) {u32 fcount = old->field_count;struct audit_entry *entry;
@@ -875,7 +876,7 @@ struct audit_entry *audit_dupe_rule(stru new->filterkey = fk;break ;case AUDIT_EXE : - err =audit_dupe_exe (new, old); + err =audit_dupe_exe (new, old, ctx);break ; }if (err) {
@@ -1414,7 +1415,7 @@ static int update_lsm_rule(struct audit_if (!security_audit_rule_known (r))return 0 ; - nentry =audit_dupe_rule (r); + nentry =audit_dupe_rule (r,NULL );if (entry->rule.exe)audit_remove_mark (entry->rule.exe);if (IS_ERR (nentry)) {
Greg Kroah-Hartman
maintainerPATCH 727/744 fuse-uring: fix race between registration and connection abortion
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joanne Koong <[email protected]>
[ Upstream commit 952b5d36f6a298f57c52a59e72076c69386a8aaf ]
This fixes this race:
- thread a: io_uring_enter -> register sqe -> fuse_uring_create_ring_ent -> allocate ent but doesn't grab queue_ref yet
- thread b: fuse_conn_destroy() -> fuse_chan_abort() -> fuse_uring_abort() is a no-op due to queue ref being 0
- thread a: grabs the queue_ref, queue_ref is now 1, rest of fuse_uring_do_register() logic executes
- thread b: fuse_chan_abort() returns, fuse_chan_wait_aborted() now runs and calls
"wait_event(ring->stop_waitq, atomic_read(&ring->queue_refs) == 0);"
The abort/unmount thread will hang indefinitely in unkillable state as nothing will decrement queue_refs or wake stop_waitq, and the ring, queue, and ent are leaked.
Fix this by checking fch->connected under fch->lock after the created ent has grabbed a ref count on the queue. This ensures that in the scenario above, it is guaranteed that we either release the queue ref and wake up stop_waitq (in case fuse_chan_wait_aborted() is already waiting) in fuse_uring_do_register() when we detect !fch->connected, or if the connection is aborted after the check, it is guaranteed that the async teardown worker will be running in the background cleaning up ents and decrementing the ent's ref on the queue, which will unblock the eventual queue and ring teardown.
--- fs/fuse/dev_uring.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
fs/fuse/dev_uring.c +16 -6
@@ -995,15 +995,26 @@ static bool is_ring_ready(struct fuse_ri/* * fuse_uring_req_fetch command handling */ -static void fuse_uring_do_register (struct fuse_ring_ent *ent, -struct io_uring_cmd *cmd, -unsigned int issue_flags) +static int fuse_uring_do_register (struct fuse_ring_ent *ent, +struct io_uring_cmd *cmd, +unsigned int issue_flags) {struct fuse_ring_queue *queue = ent->queue;struct fuse_ring *ring = queue->ring;struct fuse_conn *fc = ring->fc;struct fuse_iqueue *fiq = &fc->iq; +spin_lock (&fc->lock); +/* abort teardown path is running or has run */ +if (!fc->connected) { +spin_unlock (&fc->lock); +if (atomic_dec_and_test (&ring->queue_refs)) +wake_up_all (&ring->stop_waitq); +kfree (ent); +return -ECONNABORTED ; + } +spin_unlock (&fc->lock); +fuse_uring_prepare_cancel (cmd, issue_flags, ent);spin_lock (&queue->lock);
@@ -1020,6 +1031,7 @@ static void fuse_uring_do_register(strucwake_up_all (&fc->blocked_waitq); } } +return 0 ; }/*
@@ -1136,9 +1148,7 @@ static int fuse_uring_register(struct ioif (IS_ERR (ent))return PTR_ERR (ent); -fuse_uring_do_register (ent, cmd, issue_flags); - -return 0 ; +return fuse_uring_do_register (ent, cmd, issue_flags); }/*
Greg Kroah-Hartman
maintainerPATCH 728/744 xfs: dont replace the wrong part of the cow fork
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Darrick J. Wong" <[email protected]>
[ Upstream commit a1caeeadbf57ff86dfc3454398c46de86056a74e ]
LOLLM points out that xfs_iext_lookup_extent can return a @got where got->br_startoff < startoff. In this case, xrep_cow_replace_range replaces the entire mapping instead of just the part that had been marked bad in the bitmap, but advances the bitmap cursor in xrep_cow_replace by the amount replaced. As a result, we fail to replace the end of the bad range, and replace part of the good range.
Fix this by rewriting the replace method to handle replacing the middle of a cow fork mapping. This we do by returning both the current mapping as @got, and the subset of the mapping that we want to replace as @rep, using @rep to store the results of the new allocation, and comparing @rep to @got to figure out the exact transformations needed.
--- fs/xfs/scrub/cow_repair.c | 203 +++++++++++++++++++++++++++++----------------- fs/xfs/scrub/trace.h | 28 +++--- 2 files changed, 148 insertions(+), 83 deletions(-)
fs/xfs/scrub/cow_repair.c +131 -72
@@ -80,12 +80,6 @@ struct xrep_cow {unsigned int next_bno; }; -/* CoW staging extent. */ -struct xrep_cow_extent { -xfs_fsblock_t fsbno; -xfs_extlen_t len; -}; -/* * Mark the part of the file range that corresponds to the given physical * space. Caller must ensure that the physical range is within xc->irec.
@@ -401,22 +395,21 @@ out_rtg: STATIC intxrep_cow_alloc (struct xfs_scrub *sc, -xfs_extlen_t maxlen, -struct xrep_cow_extent *repl) +struct xfs_bmbt_irec *del) {struct xfs_alloc_arg args = { .tp = sc->tp, .mp = sc->mp, .oinfo =XFS_RMAP_OINFO_SKIP_UPDATE , .minlen =1 , - .maxlen = maxlen, + .maxlen = del->br_blockcount, .prod =1 , .resv =XFS_AG_RESV_NONE , .datatype =XFS_ALLOC_USERDATA , };int error; - error =xfs_trans_reserve_more (sc->tp, maxlen,0 ); + error =xfs_trans_reserve_more (sc->tp, del->br_blockcount,0 );if (error)return error;
@@ -429,8 +422,8 @@ xrep_cow_alloc(xfs_refcount_alloc_cow_extent (sc->tp, false, args.fsbno, args.len); - repl->fsbno = args.fsbno; - repl->len = args.len; + del->br_startblock = args.fsbno; + del->br_blockcount = args.len;return 0 ; }
@@ -441,10 +434,12 @@ xrep_cow_alloc( STATIC intxrep_cow_alloc_rt (struct xfs_scrub *sc, -xfs_extlen_t maxlen, -struct xrep_cow_extent *repl) +struct xfs_bmbt_irec *del) { -xfs_rtxlen_t maxrtx =xfs_rtb_to_rtx (sc->mp, maxlen); +xfs_fsblock_t fsbno; +xfs_rtxlen_t maxrtx = +min (U32_MAX ,xfs_blen_to_rtbxlen (sc->mp, del->br_blockcount)); +xfs_extlen_t len;int error; error =xfs_trans_reserve_more (sc->tp,0 , maxrtx);
@@ -452,11 +447,14 @@ xrep_cow_alloc_rt(return error; error =xfs_rtallocate_rtgs (sc->tp,NULLRTBLOCK ,1 , maxrtx,1 , false, - false, &repl->fsbno, &repl->len); + false, &fsbno, &len);if (error)return error; -xfs_refcount_alloc_cow_extent (sc->tp, true, repl->fsbno, repl->len); +xfs_refcount_alloc_cow_extent (sc->tp, true, fsbno, len); + + del->br_startblock = fsbno; + del->br_blockcount = len;return 0 ; }
@@ -470,19 +468,19 @@ static inline intxrep_cow_find_mapping ( struct xrep_cow *xc, struct xfs_iext_cursor *icur, - xfs_fileoff_t startoff, - struct xfs_bmbt_irec *got) + xfs_fileoff_t badoff, + xfs_extlen_t badlen, + struct xfs_bmbt_irec *got, + struct xfs_bmbt_irec *rep) { struct xfs_inode *ip = xc->sc->ip;struct xfs_ifork *ifp =xfs_ifork_ptr (ip,XFS_COW_FORK ); -if (!xfs_iext_lookup_extent (ip, ifp, startoff, icur, got)) +if (!xfs_iext_lookup_extent (ip, ifp, badoff, icur, got)) goto bad; +memcpy (rep, got,sizeof (*rep)); -if (got->br_startoff > startoff) - goto bad; - -if (got->br_blockcount ==0 ) +if (got->br_startoff > badoff) goto bad;if (isnullstartblock (got->br_startblock))
@@ -491,6 +489,24 @@ xrep_cow_find_mapping(if (xfs_bmap_is_written_extent (got)) goto bad; +if (got->br_startoff < badoff) { +const int64_t delta = badoff - got->br_startoff; + + rep->br_blockcount -= delta; + rep->br_startoff += delta; + rep->br_startblock += delta; + } + +if (got->br_startoff + got->br_blockcount > badoff + badlen) { +const int64_t delta = (got->br_startoff + got->br_blockcount) - + (badoff + badlen); + + rep->br_blockcount -= delta; + } + +if (got->br_blockcount ==0 ) + goto bad; +return 0 ; bad:ASSERT (0 );
@@ -501,46 +517,92 @@ bad:#define REPLACE_RIGHT_SIDE (1U << 1)/* -* Given a CoW fork mapping @got and a replacement mapping @repl, remap the -* beginning of @got with the space described by @rep. +* Given a CoW fork mapping @got and a replacement mapping @rep, map the space +* described by @rep into the cow fork, pushing aside @got as necessary. @icur +* must point to iext tree leaf containing @got. */ static inline void xrep_cow_replace_mapping ( -struct xfs_inode *ip, -struct xfs_iext_cursor *icur, -const struct xfs_bmbt_irec *got, -const struct xrep_cow_extent *repl) +struct xfs_inode *ip, +struct xfs_iext_cursor *icur, +struct xfs_bmbt_irec *got, +struct xfs_bmbt_irec *rep) { -struct xfs_bmbt_irec new = *got;/* struct copy */ +struct xfs_ifork *ifp =xfs_ifork_ptr (ip,XFS_COW_FORK ); +xfs_fileoff_t rep_endoff = + rep->br_startoff + rep->br_blockcount; +xfs_fileoff_t got_endoff = + got->br_startoff + got->br_blockcount; +uint32_t state =BMAP_COWFORK ; -ASSERT (repl->len >0 ); +ASSERT (rep->br_blockcount >0 );ASSERT (!isnullstartblock (got->br_startblock)); +ASSERT (got->br_startoff <= rep->br_startoff); +ASSERT (got_endoff >= rep_endoff); -trace_xrep_cow_replace_mapping (ip, got, repl->fsbno, repl->len); +trace_xrep_cow_replace_mapping (ip, got, rep); -if (got->br_blockcount == repl->len) { +if (got->br_startoff == rep->br_startoff) + state |=BMAP_LEFT_FILLING ; +if (got_endoff == rep_endoff) + state |=BMAP_RIGHT_FILLING ; + +switch (state & (BMAP_LEFT_FILLING |BMAP_RIGHT_FILLING )) { +case BMAP_LEFT_FILLING |BMAP_RIGHT_FILLING :/* -* The new extent is a complete replacement for the existing -* extent. Update the COW fork record. +* Replacement matches the whole mapping, update the record. */ - new.br_startblock = repl->fsbno; -xfs_iext_update_extent (ip,BMAP_COWFORK , icur, &new); -return ; - } +xfs_iext_update_extent (ip, state, icur, rep); +break ; +case BMAP_LEFT_FILLING : +/* +* Replace the first part of the mapping: Update the cursor +* position with the new mapping, then add a record with the +* tail of the old mapping. +*/ + got->br_startoff = rep_endoff; + got->br_blockcount -= rep->br_blockcount; + got->br_startblock += rep->br_blockcount; + +xfs_iext_update_extent (ip, state, icur, rep); +xfs_iext_next (ifp, icur); +xfs_iext_insert (ip, icur, got, state); +break ; +case BMAP_RIGHT_FILLING : +/* +* Replacing the last part of the mapping. Shorten the current +* mapping then add a record with the new mapping. +*/ + got->br_blockcount -= rep->br_blockcount; -/* -* The new extent can replace the beginning of the COW fork record. -* Move the left side of @got upwards, then insert the new record. -*/ - new.br_startoff += repl->len; - new.br_startblock += repl->len; - new.br_blockcount -= repl->len; -xfs_iext_update_extent (ip,BMAP_COWFORK , icur, &new); - - new.br_startoff = got->br_startoff; - new.br_startblock = repl->fsbno; - new.br_blockcount = repl->len; -xfs_iext_insert (ip, icur, &new,BMAP_COWFORK ); +xfs_iext_update_extent (ip, state, icur, got); +xfs_iext_next (ifp, icur); +xfs_iext_insert (ip, icur, rep, state); +break ; +case 0 : +/* +* Replacing the middle of the extent. Shorten the current +* mapping, add a new record with the new mapping, and add a +* second new record with the tail of the old mapping. +*/ + got->br_blockcount = rep->br_startoff - got->br_startoff; + +struct xfs_bmbt_irec new = { + .br_startoff = rep_endoff, + .br_blockcount = got_endoff - rep_endoff, + .br_state = got->br_state, + .br_startblock = got->br_startblock + + rep->br_blockcount + + got->br_blockcount, + }; + +xfs_iext_update_extent (ip, state, icur, got); +xfs_iext_next (ifp, icur); +xfs_iext_insert (ip, icur, rep, state); +xfs_iext_next (ifp, icur); +xfs_iext_insert (ip, icur, &new, state); +break ; + } }/*
@@ -554,33 +616,30 @@ xrep_cow_replace_range( xfs_extlen_t *blockcount) {struct xfs_iext_cursor icur; -struct xrep_cow_extent repl; -struct xfs_bmbt_irec got; +struct xfs_bmbt_irec got, rep;struct xfs_scrub *sc = xc->sc; -xfs_fileoff_t nextoff; -xfs_extlen_t alloc_len; +xfs_fsblock_t old_fsbno;int error;/* -* Put the existing CoW fork mapping in @got. If @got ends before -* @rep, truncate @rep so we only replace one extent mapping at a time. +* Put the existing CoW fork mapping in @got, and put in @rep the +* contents of @got trimmed to @startoff/@blockcount. We only want +* to replace the bad region, and only one mapping at a time. */ - error =xrep_cow_find_mapping (xc, &icur, startoff, &got); + error =xrep_cow_find_mapping (xc, &icur, startoff, *blockcount, &got, + &rep);if (error)return error; - nextoff =min (startoff + *blockcount, - got.br_startoff + got.br_blockcount); + old_fsbno = rep.br_startblock;/* * Allocate a replacement extent. If we don't fill all the blocks, * shorten the quantity that will be deleted in this step. */ - alloc_len =min_t (xfs_fileoff_t,XFS_MAX_BMBT_EXTLEN , - nextoff - startoff);if (XFS_IS_REALTIME_INODE (sc->ip)) - error =xrep_cow_alloc_rt (sc, alloc_len, &repl); + error =xrep_cow_alloc_rt (sc, &rep);else - error =xrep_cow_alloc (sc, alloc_len, &repl); + error =xrep_cow_alloc (sc, &rep);if (error)return error;
@@ -588,7 +647,7 @@ xrep_cow_replace_range(* Replace the old mapping with the new one, and commit the metadata * changes made so far. */ -xrep_cow_replace_mapping (sc->ip, &icur, &got, &repl); +xrep_cow_replace_mapping (sc->ip, &icur, &got, &rep);xfs_inode_set_cowblocks_tag (sc->ip); error =xfs_defer_finish (&sc->tp);
@@ -597,15 +656,15 @@ xrep_cow_replace_range(/* Note the old CoW staging extents; we'll reap them all later. */ if (XFS_IS_REALTIME_INODE (sc->ip)) - error =xrtb_bitmap_set (&xc->old_cowfork_rtblocks, - got.br_startblock, repl.len); + error =xrtb_bitmap_set (&xc->old_cowfork_rtblocks, old_fsbno, + rep.br_blockcount);else - error =xfsb_bitmap_set (&xc->old_cowfork_fsblocks, - got.br_startblock, repl.len); + error =xfsb_bitmap_set (&xc->old_cowfork_fsblocks, old_fsbno, + rep.br_blockcount);if (error)return error; - *blockcount = repl.len; + *blockcount = rep.br_blockcount;return 0 ; }
fs/xfs/scrub/trace.h +17 -11
@@ -2672,9 +2672,9 @@ TRACE_EVENT(xrep_cow_mark_file_range, ); TRACE_EVENT(xrep_cow_replace_mapping, - TP_PROTO(struct xfs_inode *ip, const struct xfs_bmbt_irec *irec, - xfs_fsblock_t new_startblock, xfs_extlen_t new_blockcount), - TP_ARGS(ip, irec, new_startblock, new_blockcount), + TP_PROTO(struct xfs_inode *ip, const struct xfs_bmbt_irec *got, + const struct xfs_bmbt_irec *rep), + TP_ARGS(ip, got, rep), TP_STRUCT__entry( __field(dev_t, dev) __field(xfs_ino_t, ino)
@@ -2682,28 +2682,34 @@ TRACE_EVENT(xrep_cow_replace_mapping, __field(xfs_fileoff_t, startoff) __field(xfs_filblks_t, blockcount) __field(xfs_exntst_t, state) + __field(xfs_fileoff_t, new_startoff) __field(xfs_fsblock_t, new_startblock) __field(xfs_extlen_t, new_blockcount) +__field (xfs_exntst_t, new_state) ),TP_fast_assign ( __entry->dev = ip->i_mount->m_super->s_dev; __entry->ino = ip->i_ino; - __entry->startoff = irec->br_startoff; - __entry->startblock = irec->br_startblock; - __entry->blockcount = irec->br_blockcount; - __entry->state = irec->br_state; - __entry->new_startblock = new_startblock; - __entry->new_blockcount = new_blockcount; + __entry->startoff = got->br_startoff; + __entry->startblock = got->br_startblock; + __entry->blockcount = got->br_blockcount; + __entry->state = got->br_state; + __entry->new_startoff = rep->br_startoff; + __entry->new_startblock = rep->br_startblock; + __entry->new_blockcount = rep->br_blockcount; + __entry->new_state = rep->br_state; ), -TP_printk ("dev %d:%d ino 0x%llx startoff 0x%llx startblock 0x%llx fsbcount 0x%llx state 0x%x new_startblock 0x%llx new_fsbcount 0x%x" , +TP_printk ("dev %d:%d ino 0x%llx startoff 0x%llx startblock 0x%llx fsbcount 0x%llx state 0x%x new_startoff 0x%llx new_startblock 0x%llx new_fsbcount 0x%x new_state 0x%x" ,MAJOR (__entry->dev),MINOR (__entry->dev), __entry->ino, __entry->startoff, __entry->startblock, __entry->blockcount, __entry->state, + __entry->new_startoff, __entry->new_startblock, - __entry->new_blockcount) + __entry->new_blockcount, + __entry->new_state) ); TRACE_EVENT(xrep_cow_free_staging,
Greg Kroah-Hartman
maintainerPATCH 729/744 SUNRPC: Add helpers to convert xdr_buf byte ranges to scatterlists
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit e9be933959b581effd426f93b86654f5fbf0c574 ]
The crypto/krb5 library accepts data in scatterlist form, but the GSS-API layer presents RPC payloads as struct xdr_buf. Bridge that gap with a pair of helper functions:
xdr_buf_to_sg() - populate a caller-supplied scatterlist
array from a byte range
xdr_buf_to_sg_alloc() - populate a caller-supplied inline
scatterlist, chaining to a heap- allocated overflow for large payloads
The inline array (typically stack-allocated at eight entries) covers the common case of small RPCs with no heap allocation on the encrypt/decrypt path. Only buffers spanning many pages incur a kmalloc for the chained extension.
The segment-walking logic follows the same head, page array, tail traversal as xdr_process_buf(), but populates a scatterlist directly rather than invoking a per-segment callback. sg_next() traversal makes the walker safe for chained scatterlists. Once subsequent patches reroute all per-message crypto operations through crypto/krb5, xdr_process_buf() loses its last callers and is removed.
Stable-dep-of: 18c1cc698861 ("SUNRPC: Return an error from xdr_buf_to_bvec() on overflow")
--- include/linux/sunrpc/xdr.h | 15 +++ net/sunrpc/xdr.c | 199 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 214 insertions(+)
include/linux/sunrpc/xdr.h +15 -0
@@ -140,6 +140,21 @@ int xdr_alloc_bvec(struct xdr_buf *buf,void xdr_free_bvec (struct xdr_buf *buf);unsigned int xdr_buf_to_bvec (struct bio_vec *bvec,unsigned int bvec_size,const struct xdr_buf *xdr); +int xdr_buf_to_sg (const struct xdr_buf *buf,unsigned int offset, +unsigned int len,struct scatterlist *sg,unsigned int nsg); +int xdr_buf_to_sg_alloc (const struct xdr_buf *buf,unsigned int offset, +unsigned int len,struct scatterlist *sg_head, +unsigned int sg_head_nents, +struct scatterlist **sg_overflow,gfp_t gfp); + +/* +* Inline scatterlist entries for xdr_buf_to_sg_alloc(). Sized to cover the +* head kvec, tail kvec, and a few page fragments without any heap allocation. +*/ +enum { +XDR_BUF_TO_SG_NENTS =8 , +}; +static inline __be32 *xdr_encode_array (__be32 *p,const void *s,unsigned int len) {
net/sunrpc/xdr.c +199 -0
205 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 730/744 SUNRPC: Return an error from xdr_buf_to_bvec() on overflow
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 18c1cc69886192e33536498289d26dba6894e3d5 ]
xdr_buf_to_bvec() returns a slot count even when the caller's bvec budget is exhausted partway through the xdr_buf. Callers feed that count into iov_iter_bvec() and continue as if the conversion had succeeded, silently sending or writing fewer bytes than the data length declares. For an NFS WRITE the server reports the truncated transfer to the client as full success.
The overflow represents an internal invariant violation: a higher layer reserved a bvec budget too small for the xdr_buf it then asked the encoder to convert. That is a server-side fault, not a media I/O failure and not a malformed client argument.
Change xdr_buf_to_bvec() to return a signed int and have the overflow label return -ESERVERFAULT. Update the three callers to detect the negative return and fail the request: nfsd_vfs_write() folds the error into host_err, which nfserrno() translates to nfserr_serverfault for the WRITE reply; svc_udp_sendto() and svc_tcp_sendmsg() propagate the error out of the send path.
--- fs/nfsd/vfs.c | 6 +++++- include/linux/sunrpc/xdr.h | 4 ++-- net/sunrpc/svcsock.c | 14 ++++++++++++-- net/sunrpc/xdr.c | 11 ++++++----- 4 files changed, 25 insertions(+), 10 deletions(-)
fs/nfsd/vfs.c +5 -1
@@ -1439,7 +1439,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, sunsigned long exp_op_flags =0 ;unsigned int pflags = current->flags;bool restore_flags = false; -unsigned int nvecs; +int nvecs;trace_nfsd_write_opened (rqstp, fhp, offset, *cnt);
@@ -1479,6 +1479,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, s } nvecs =xdr_buf_to_bvec (rqstp->rq_bvec, rqstp->rq_maxpages, payload); +if (nvecs <0 ) { + host_err = nvecs; + goto out_nfserr; + } since =READ_ONCE (file->f_wb_err);if (verf)
include/linux/sunrpc/xdr.h +2 -2
@@ -138,8 +138,8 @@ void xdr_terminate_string(const struct xsize_t xdr_buf_pagecount (const struct xdr_buf *buf);int xdr_alloc_bvec (struct xdr_buf *buf,gfp_t gfp);void xdr_free_bvec (struct xdr_buf *buf); -unsigned int xdr_buf_to_bvec (struct bio_vec *bvec,unsigned int bvec_size, -const struct xdr_buf *xdr); +int xdr_buf_to_bvec (struct bio_vec *bvec,unsigned int bvec_size, +const struct xdr_buf *xdr);int xdr_buf_to_sg (const struct xdr_buf *buf,unsigned int offset,unsigned int len,struct scatterlist *sg,unsigned int nsg); int xdr_buf_to_sg_alloc(const struct xdr_buf *buf, unsigned int offset,
net/sunrpc/svcsock.c +12 -2
@@ -742,7 +742,7 @@ static int svc_udp_sendto(struct svc_rqs .msg_flags = MSG_SPLICE_PAGES, .msg_controllen = sizeof(buffer), }; -unsigned int count; +int count;int err;svc_udp_release_ctxt (xprt, rqstp->rq_xprt_ctxt);
@@ -756,6 +756,10 @@ static int svc_udp_sendto(struct svc_rqs goto out_notconn; count =xdr_buf_to_bvec (svsk->sk_bvec,SUNRPC_MAX_UDP_SENDPAGES , xdr); +if (count <0 ) { + err = count; + goto out_trace; + }iov_iter_bvec (&msg.msg_iter,ITER_SOURCE , svsk->sk_bvec, count, rqstp->rq_res.len);
@@ -767,6 +771,7 @@ static int svc_udp_sendto(struct svc_rqs err =sock_sendmsg (svsk->sk_sock, &msg); } +out_trace:trace_svcsock_udp_send (xprt, err);mutex_unlock (&xprt->xpt_mutex);
@@ -1247,7 +1252,7 @@ static int svc_tcp_sendmsg(struct svc_sostruct msghdr msg = { .msg_flags =MSG_SPLICE_PAGES , }; -unsigned int count; +int count;void *buf;int ret;
@@ -1263,10 +1268,15 @@ static int svc_tcp_sendmsg(struct svc_so count =xdr_buf_to_bvec (svsk->sk_bvec +1 , rqstp->rq_maxpages, &rqstp->rq_res); +if (count <0 ) { + ret = count; + goto out; + }iov_iter_bvec (&msg.msg_iter,ITER_SOURCE , svsk->sk_bvec,1 + count,sizeof (marker) + rqstp->rq_res.len); ret =sock_sendmsg (svsk->sk_sock, &msg); +out:page_frag_free (buf);return ret; }
net/sunrpc/xdr.c +6 -5
@@ -139,13 +139,14 @@ xdr_free_bvec(struct xdr_buf *buf)/** * xdr_buf_to_bvec - Copy components of an xdr_buf into a bio_vec array * @bvec: bio_vec array to populate -* @bvec_size: element count of @bio_vec +* @bvec_size: element count of @bvec * @xdr: xdr_buf to be copied * -* Returns the number of entries consumed in @bvec. +* Returns the number of entries consumed in @bvec on success, or +* -ESERVERFAULT when @xdr does not fit within @bvec_size entries. */ -unsigned int xdr_buf_to_bvec (struct bio_vec *bvec,unsigned int bvec_size, -const struct xdr_buf *xdr) +int xdr_buf_to_bvec (struct bio_vec *bvec,unsigned int bvec_size, +const struct xdr_buf *xdr) {const struct kvec *head = xdr->head;const struct kvec *tail = xdr->tail;
@@ -187,7 +188,7 @@ unsigned int xdr_buf_to_bvec(struct bio_ bvec_overflow:pr_warn_once ("%s: bio_vec array overflow\n" , __func__); -return count; +return -ESERVERFAULT ; }EXPORT_SYMBOL_GPL (xdr_buf_to_bvec);
Greg Kroah-Hartman
maintainerPATCH 731/744 mm/sparse-vmemmap: pass @pgmap argument to memory deactivation paths
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Muchun Song <[email protected]>
[ Upstream commit 3bbc54dd1b62f1a4b218c70aafbeceeba7c90c5d ]
Currently, the memory hot-remove call chain -- arch_remove_memory(), __remove_pages(), sparse_remove_section() and section_deactivate() -- does not carry the struct dev_pagemap pointer. This prevents the lower levels from knowing whether the section was originally populated with vmemmap optimizations (e.g., DAX with vmemmap optimization enabled).
Without this information, we cannot call vmemmap_can_optimize() to determine if the vmemmap pages were optimized. As a result, the vmemmap page accounting during teardown will mistakenly assume a non-optimized allocation, leading to incorrect memmap statistics.
To lay the groundwork for fixing the vmemmap page accounting, we need to pass the @pgmap pointer down to the deactivation location. Plumb the @pgmap argument through the APIs of arch_remove_memory(), __remove_pages() and sparse_remove_section(), mirroring the corresponding *_activate() paths.
Stable-dep-of: 721a73e30c9e ("mm/sparse-vmemmap: fix DAX vmemmap accounting with optimization")
--- arch/arm64/mm/mmu.c | 5 +++-- arch/loongarch/mm/init.c | 5 +++-- arch/powerpc/mm/mem.c | 5 +++-- arch/riscv/mm/init.c | 5 +++-- arch/s390/mm/init.c | 5 +++-- arch/x86/mm/init_64.c | 5 +++-- include/linux/memory_hotplug.h | 8 +++++--- mm/memory_hotplug.c | 13 +++++++------ mm/memremap.c | 4 ++-- mm/sparse-vmemmap.c | 12 ++++++------ 10 files changed, 38 insertions(+), 29 deletions(-)
arch/arm64/mm/mmu.c +3 -2
@@ -2032,12 +2032,13 @@ err:return ret; } -void arch_remove_memory (u64 start,u64 size,struct vmem_altmap *altmap) +void arch_remove_memory (u64 start,u64 size,struct vmem_altmap *altmap, +struct dev_pagemap *pgmap) {unsigned long start_pfn = start >>PAGE_SHIFT ;unsigned long nr_pages = size >>PAGE_SHIFT ; -__remove_pages (start_pfn, nr_pages, altmap); +__remove_pages (start_pfn, nr_pages, altmap, pgmap);__remove_pgd_mapping (swapper_pg_dir,__phys_to_virt (start), size); }
arch/loongarch/mm/init.c +3 -2
@@ -119,12 +119,13 @@ int arch_add_memory(int nid, u64 start, return ret; } -void arch_remove_memory (u64 start,u64 size,struct vmem_altmap *altmap) +void arch_remove_memory (u64 start,u64 size,struct vmem_altmap *altmap, +struct dev_pagemap *pgmap) {unsigned long start_pfn = start >>PAGE_SHIFT ;unsigned long nr_pages = size >>PAGE_SHIFT ; -__remove_pages (start_pfn, nr_pages, altmap); +__remove_pages (start_pfn, nr_pages, altmap, pgmap); }#endif
arch/powerpc/mm/mem.c +3 -2
@@ -158,12 +158,13 @@ int __ref arch_add_memory(int nid, u64 s return rc; } -void __ref arch_remove_memory (u64 start,u64 size,struct vmem_altmap *altmap) +void __ref arch_remove_memory (u64 start,u64 size,struct vmem_altmap *altmap, +struct dev_pagemap *pgmap) {unsigned long start_pfn = start >>PAGE_SHIFT ;unsigned long nr_pages = size >>PAGE_SHIFT ; -__remove_pages (start_pfn, nr_pages, altmap); +__remove_pages (start_pfn, nr_pages, altmap, pgmap);arch_remove_linear_mapping (start, size); }#endif
arch/riscv/mm/init.c +3 -2
@@ -1742,9 +1742,10 @@ int __ref arch_add_memory(int nid, u64 sreturn ret; } -void __ref arch_remove_memory (u64 start,u64 size,struct vmem_altmap *altmap) +void __ref arch_remove_memory (u64 start,u64 size,struct vmem_altmap *altmap, +struct dev_pagemap *pgmap) { -__remove_pages (start >>PAGE_SHIFT , size >>PAGE_SHIFT , altmap); +__remove_pages (start >>PAGE_SHIFT , size >>PAGE_SHIFT , altmap, pgmap);remove_linear_mapping (start, size);flush_tlb_all (); }
arch/s390/mm/init.c +3 -2
@@ -276,12 +276,13 @@ int arch_add_memory(int nid, u64 start, return rc; } -void arch_remove_memory (u64 start,u64 size,struct vmem_altmap *altmap) +void arch_remove_memory (u64 start,u64 size,struct vmem_altmap *altmap, +struct dev_pagemap *pgmap) {unsigned long start_pfn = start >>PAGE_SHIFT ;unsigned long nr_pages = size >>PAGE_SHIFT ; -__remove_pages (start_pfn, nr_pages, altmap); +__remove_pages (start_pfn, nr_pages, altmap, pgmap);vmem_remove_mapping (start, size); }#endif /* CONFIG_MEMORY_HOTPLUG */
arch/x86/mm/init_64.c +3 -2
@@ -1300,12 +1300,13 @@ kernel_physical_mapping_remove(unsigned remove_pagetable(start, end, true, NULL); } -void __ref arch_remove_memory (u64 start,u64 size,struct vmem_altmap *altmap) +void __ref arch_remove_memory (u64 start,u64 size,struct vmem_altmap *altmap, +struct dev_pagemap *pgmap) {unsigned long start_pfn = start >>PAGE_SHIFT ;unsigned long nr_pages = size >>PAGE_SHIFT ; -__remove_pages (start_pfn, nr_pages, altmap); +__remove_pages (start_pfn, nr_pages, altmap, pgmap);kernel_physical_mapping_remove (start, start + size); }#endif /* CONFIG_MEMORY_HOTPLUG */
include/linux/memory_hotplug.h +5 -3
@@ -135,9 +135,10 @@ static inline bool movable_node_is_enablreturn movable_node_enabled; } -extern void arch_remove_memory (u64 start,u64 size,struct vmem_altmap *altmap); +extern void arch_remove_memory (u64 start,u64 size,struct vmem_altmap *altmap, +struct dev_pagemap *pgmap);extern void __remove_pages (unsigned long start_pfn,unsigned long nr_pages, -struct vmem_altmap *altmap); +struct vmem_altmap *altmap,struct dev_pagemap *pgmap);/* reasonably generic interface to expand the physical pages */ extern int __add_pages(int nid, unsigned long start_pfn, unsigned long nr_pages,
@@ -307,7 +308,8 @@ extern int sparse_add_section(int nid, u unsigned long nr_pages, struct vmem_altmap *altmap, struct dev_pagemap *pgmap);extern void sparse_remove_section (unsigned long pfn,unsigned long nr_pages, -struct vmem_altmap *altmap); +struct vmem_altmap *altmap, +struct dev_pagemap *pgmap);extern struct zone *zone_for_pfn_range (enum mmop online_type,int nid,struct memory_group *group,unsigned long start_pfn,unsigned long nr_pages);
mm/memory_hotplug.c +7 -6
@@ -576,6 +576,7 @@ void remove_pfn_range_from_zone(struct z* @pfn: starting pageframe (must be aligned to start of a section) * @nr_pages: number of pages to remove (must be multiple of section size) * @altmap: alternative device page map or %NULL if default memmap is used +* @pgmap: device page map or %NULL if not ZONE_DEVICE * * Generic helper function to remove section mappings and sysfs entries * for the section of the memory we are removing. Caller needs to make
@@ -583,7 +584,7 @@ void remove_pfn_range_from_zone(struct z* calling offline_pages(). */ void __remove_pages (unsigned long pfn,unsigned long nr_pages, -struct vmem_altmap *altmap) +struct vmem_altmap *altmap,struct dev_pagemap *pgmap) {const unsigned long end_pfn = pfn + nr_pages;unsigned long cur_nr_pages;
@@ -598,7 +599,7 @@ void __remove_pages(unsigned long pfn, u/* Select all remaining pages up to the next section boundary */ cur_nr_pages =min (end_pfn - pfn,SECTION_ALIGN_UP (pfn +1 ) - pfn); -sparse_remove_section (pfn, cur_nr_pages, altmap); +sparse_remove_section (pfn, cur_nr_pages, altmap, pgmap); } }
@@ -1427,7 +1428,7 @@ static void remove_memory_blocks_and_altremove_memory_block_devices (cur_start, memblock_size); -arch_remove_memory (cur_start, memblock_size, altmap); +arch_remove_memory (cur_start, memblock_size, altmap,NULL );/* Verify that all vmemmap pages have actually been freed. */ WARN (altmap->alloc,"Altmap not fully unmapped" );
@@ -1470,7 +1471,7 @@ static int create_altmaps_and_memory_blo ret =create_memory_block_devices (cur_start, memblock_size, nid, params.altmap, group);if (ret) { -arch_remove_memory (cur_start, memblock_size, params.altmap); +arch_remove_memory (cur_start, memblock_size, params.altmap,NULL );kfree (params.altmap); goto out; }
@@ -1556,7 +1557,7 @@ int add_memory_resource(int nid, struct/* create memory block devices after memory was added */ ret =create_memory_block_devices (start, size, nid,NULL , group);if (ret) { -arch_remove_memory (start, size, params.altmap); +arch_remove_memory (start, size, params.altmap,NULL ); goto error; } }
@@ -2268,7 +2269,7 @@ static int try_remove_memory(u64 start,* No altmaps present, do the removal directly */ remove_memory_block_devices (start, size); -arch_remove_memory (start, size,NULL ); +arch_remove_memory (start, size,NULL ,NULL ); }else {/* all memblocks in the range have altmaps */ remove_memory_blocks_and_altmaps (start, size);
mm/memremap.c +2 -2
@@ -97,10 +97,10 @@ static void pageunmap_range(struct dev_p PHYS_PFN(range_len(range)));if (pgmap->type ==MEMORY_DEVICE_PRIVATE ) {__remove_pages (PHYS_PFN (range->start), -PHYS_PFN (range_len (range)),NULL ); +PHYS_PFN (range_len (range)),NULL , pgmap); }else {arch_remove_memory (range->start,range_len (range), -pgmap_altmap (pgmap)); +pgmap_altmap (pgmap), pgmap);kasan_remove_zero_shadow (__va (range->start),range_len (range)); }mem_hotplug_done ();
mm/sparse-vmemmap.c +6 -6
@@ -665,7 +665,7 @@ static struct page * __meminit populate_ }static void depopulate_section_memmap (unsigned long pfn,unsigned long nr_pages, -struct vmem_altmap *altmap) +struct vmem_altmap *altmap,struct dev_pagemap *pgmap) {unsigned long start = (unsigned long )pfn_to_page (pfn);unsigned long end = start + nr_pages *sizeof (struct page );
@@ -746,7 +746,7 @@ static int fill_subsection_map(unsigned* usage map, but still need to free the vmemmap range. */ static void section_deactivate (unsigned long pfn,unsigned long nr_pages, -struct vmem_altmap *altmap) +struct vmem_altmap *altmap,struct dev_pagemap *pgmap) {struct mem_section *ms =__pfn_to_section (pfn);bool section_is_early =early_section (ms);
@@ -784,7 +784,7 @@ static void section_deactivate(unsigned* section_activate() and pfn_valid() . */ if (!section_is_early) -depopulate_section_memmap (pfn, nr_pages, altmap); +depopulate_section_memmap (pfn, nr_pages, altmap, pgmap);else if (memmap)free_map_bootmem (memmap);
@@ -828,7 +828,7 @@ static struct page * __meminit section_a memmap =populate_section_memmap (pfn, nr_pages, nid, altmap, pgmap);if (!memmap) { -section_deactivate (pfn, nr_pages, altmap); +section_deactivate (pfn, nr_pages, altmap, pgmap);return ERR_PTR (-ENOMEM ); }
@@ -889,13 +889,13 @@ int __meminit sparse_add_section(int nid }void sparse_remove_section (unsigned long pfn,unsigned long nr_pages, -struct vmem_altmap *altmap) +struct vmem_altmap *altmap,struct dev_pagemap *pgmap) {struct mem_section *ms =__pfn_to_section (pfn);if (WARN_ON_ONCE (!valid_section (ms)))return ; -section_deactivate (pfn, nr_pages, altmap); +section_deactivate (pfn, nr_pages, altmap, pgmap); }#endif /* CONFIG_MEMORY_HOTPLUG */
Greg Kroah-Hartman
maintainerPATCH 732/744 mm/sparse-vmemmap: fix DAX vmemmap accounting with optimization
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Muchun Song <[email protected]>
[ Upstream commit 721a73e30c9e3e8fcffe1725bcede1bbd20b4918 ]
When vmemmap optimization is enabled for DAX, the nr_memmap_pages counter in /proc/vmstat is incorrect. The current code always accounts for the full, non-optimized vmemmap size, but vmemmap optimization reduces the actual number of vmemmap pages by reusing tail pages. This causes the system to overcount vmemmap usage, leading to inaccurate page statistics in /proc/vmstat.
Fix this by introducing section_nr_vmemmap_pages(), which returns the exact vmemmap page count for a given pfn range based on whether optimization is in effect.
--- mm/sparse-vmemmap.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-)
mm/sparse-vmemmap.c +30 -4
@@ -652,6 +652,31 @@ void offline_mem_sections(unsigned long } } +static int __meminit section_nr_vmemmap_pages (unsigned long pfn,unsigned long nr_pages, +struct vmem_altmap *altmap,struct dev_pagemap *pgmap) +{ +const unsigned int order = pgmap ? pgmap->vmemmap_shift :0 ; +const unsigned long pages_per_compound =1UL << order; + +VM_WARN_ON_ONCE (!IS_ALIGNED (pfn | nr_pages,PAGES_PER_SUBSECTION )); +VM_WARN_ON_ONCE (nr_pages >PAGES_PER_SECTION ); + +if (!vmemmap_can_optimize (altmap, pgmap)) +return DIV_ROUND_UP (nr_pages *sizeof (struct page ),PAGE_SIZE ); + +if (order <PFN_SECTION_SHIFT ) { +VM_WARN_ON_ONCE (!IS_ALIGNED (pfn | nr_pages, pages_per_compound)); +return VMEMMAP_RESERVE_NR * nr_pages / pages_per_compound; + } + +VM_WARN_ON_ONCE (!IS_ALIGNED (pfn | nr_pages,PAGES_PER_SECTION )); + +if (IS_ALIGNED (pfn, pages_per_compound)) +return VMEMMAP_RESERVE_NR ; + +return 0 ; +} +static struct page *__meminit populate_section_memmap (unsigned long pfn,unsigned long nr_pages,int nid,struct vmem_altmap *altmap,struct dev_pagemap *pgmap)
@@ -659,7 +684,7 @@ static struct page * __meminit populate_struct page *page =__populate_section_memmap (pfn, nr_pages, nid, altmap, pgmap); - memmap_pages_add(DIV_ROUND_UP(nr_pages * sizeof(struct page), PAGE_SIZE)); +memmap_pages_add (section_nr_vmemmap_pages (pfn, nr_pages, altmap, pgmap));return page; }
@@ -670,7 +695,7 @@ static void depopulate_section_memmap(ununsigned long start = (unsigned long )pfn_to_page (pfn);unsigned long end = start + nr_pages *sizeof (struct page ); -memmap_pages_add (-1L * (DIV_ROUND_UP (nr_pages *sizeof (struct page ),PAGE_SIZE ))); +memmap_pages_add (-section_nr_vmemmap_pages (pfn, nr_pages, altmap, pgmap));vmemmap_free (start, end, altmap); }
@@ -678,9 +703,10 @@ static void free_map_bootmem(struct page {unsigned long start = (unsigned long )memmap;unsigned long end = (unsigned long )(memmap +PAGES_PER_SECTION ); +unsigned long pfn =page_to_pfn (memmap); -memmap_boot_pages_add (-1L * (DIV_ROUND_UP (PAGES_PER_SECTION *sizeof (struct page ), -PAGE_SIZE ))); +memmap_boot_pages_add (-section_nr_vmemmap_pages (pfn,PAGES_PER_SECTION , +NULL ,NULL ));vmemmap_free (start, end,NULL ); }
Greg Kroah-Hartman
maintainerPATCH 733/744 thunderbolt: Keep XDomain reference during the lifetime of a service
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mika Westerberg <[email protected]>
[ Upstream commit 8b4060998637f06975fceee9b73845d8672d411e ]
This is needed because we release the service ID in tb_service_release() and the ID array is owned by the parent XDomain.
Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect")
--- drivers/thunderbolt/xdomain.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/thunderbolt/xdomain.c +2 -1
@@ -1012,6 +1012,7 @@ static void tb_service_release(struct deida_free (&xd->service_ids, svc->id);kfree (svc->key);kfree (svc); +tb_xdomain_put (xd); }const struct device_type tb_service_type = {
@@ -1120,7 +1121,7 @@ static void enumerate_services(struct tb svc->id = id; svc->dev.bus = &tb_bus_type; svc->dev.type = &tb_service_type; - svc->dev.parent = &xd->dev; + svc->dev.parent =get_device (&xd->dev);dev_set_name (&svc->dev,"%s.%d" ,dev_name (&xd->dev), svc->id);tb_service_debugfs_init (svc);
Greg Kroah-Hartman
maintainerPATCH 734/744 thunderbolt: Remove service debugfs entries during unregister
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mika Westerberg <[email protected]>
[ Upstream commit 4d5fc3f4068568dfcb8cbe2852b4adc56394aa26 ]
We add them as part of the register path so to keep it symmetric remove them as part of the unregister path. This also removes them even if the service itself is not yet released (but is unregistered), thus allowing new register with the same service name to happen.
Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect")
--- drivers/thunderbolt/xdomain.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
drivers/thunderbolt/xdomain.c +11 -3
@@ -1008,7 +1008,6 @@ static void tb_service_release(struct de struct tb_service *svc = container_of(dev, struct tb_service, dev);struct tb_xdomain *xd =tb_service_parent (svc); -tb_service_debugfs_remove (svc);ida_free (&xd->service_ids, svc->id);kfree (svc->key);kfree (svc);
@@ -1023,6 +1022,14 @@ const struct device_type tb_service_type };EXPORT_SYMBOL_GPL (tb_service_type); +static void __unregister_service (struct device *dev) +{ +struct tb_service *svc =tb_to_service (dev); + +tb_service_debugfs_remove (svc); +device_unregister (&svc->dev); +} +static int remove_missing_service (struct device *dev,void *data) {struct tb_xdomain *xd = data;
@@ -1034,7 +1041,7 @@ static int remove_missing_service(structif (!tb_property_find (xd->remote_properties, svc->key,TB_PROPERTY_TYPE_DIRECTORY )) -device_unregister (dev); +__unregister_service (dev);return 0 ; }
@@ -1127,6 +1134,7 @@ static void enumerate_services(struct tbtb_service_debugfs_init (svc);if (device_register (&svc->dev)) { +tb_service_debugfs_remove (svc);put_device (&svc->dev);break ; }
@@ -2059,7 +2067,7 @@ void tb_xdomain_add(struct tb_xdomain *xstatic int unregister_service (struct device *dev,void *data) { -device_unregister (dev); +__unregister_service (dev);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 735/744 thunderbolt: Remove XDomain from the bus without holding tb->lock
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mika Westerberg <[email protected]>
[ Upstream commit a8937f35cf39c39c64325aa84d0463d866850857 ]
Currently we call device_unregister() for services and the XDomain itself with tb->lock held. This prevents the service drivers from calling any functions that may take it. For this reason separate removing the XDomain from the topology data structures (where we need the lock) from unregistering the device from the bus (where remove callbacks of the drivers are being called).
Stable-dep-of: 2c5d2d3c3f70 ("thunderbolt: Prevent XDomain delayed work use-after-free on disconnect")
--- drivers/thunderbolt/debugfs.c | 2 + drivers/thunderbolt/domain.c | 30 +++++++++++++++++++++ drivers/thunderbolt/icm.c | 5 +++ drivers/thunderbolt/switch.c | 14 +++++++++ drivers/thunderbolt/tb.c | 59 ++++++++++++++++++++---------------------- drivers/thunderbolt/tb.h | 2 + drivers/thunderbolt/xdomain.c | 53 +++++++++++++++++++++++-------------- 7 files changed, 115 insertions(+), 50 deletions(-)
drivers/thunderbolt/debugfs.c +2 -0
@@ -1786,6 +1786,8 @@ static void margining_port_remove(structif (!port->usb4)return ; +if (!port->usb4->margining) +return ;snprintf (dir_name,sizeof (dir_name),"port%d" , port->port); parent =debugfs_lookup (dir_name, port->sw->debugfs_dir);
drivers/thunderbolt/domain.c +30 -0
@@ -850,6 +850,36 @@ int tb_domain_disconnect_all_paths(strucreturn bus_for_each_dev (&tb_bus_type,NULL , tb, disconnect_xdomain); } +struct unregister_context { +const struct tb *tb; +int n; +}; + +static int unregister_unplugged_xdomain (struct device *dev,void *data) +{ +struct unregister_context *ctx = data; +struct tb_xdomain *xd; + + xd =tb_to_xdomain (dev); +if (xd && xd->tb == ctx->tb && xd->is_unplugged) { +tb_xdomain_unregister (xd); + ctx->n++; + } +return 0 ; +} + +int tb_domain_unregister_unplugged_xdomains (struct tb *tb) +{ +struct unregister_context ctx; + + ctx.tb =tb_domain_get (tb); + ctx.n =0 ; +bus_for_each_dev (&tb_bus_type,NULL , &ctx, unregister_unplugged_xdomain); +tb_domain_put (tb); + +return ctx.n; +} +int tb_domain_init (void ) {int ret;
drivers/thunderbolt/icm.c +5 -0
@@ -738,6 +738,7 @@ static void remove_xdomain(struct tb_xdo sw =tb_to_switch (xd->dev.parent);tb_port_at (xd->route, sw)->xdomain =NULL ; + xd->is_unplugged = true;tb_xdomain_remove (xd); }
@@ -1762,6 +1763,8 @@ static void icm_handle_notification(strukfree (n->pkg);kfree (n); + +tb_domain_unregister_unplugged_xdomains (tb); } static void icm_handle_event(struct tb *tb, enum tb_cfg_pkg_type type,
@@ -2112,6 +2115,8 @@ static void icm_rescan_work(struct work_if (tb->root_switch)icm_free_unplugged_children (tb->root_switch);mutex_unlock (&tb->lock); + +tb_domain_unregister_unplugged_xdomains (tb); }static void icm_complete (struct tb *tb)
drivers/thunderbolt/switch.c +14 -0
@@ -3625,6 +3625,20 @@ int tb_switch_resume(struct tb_switch *stb_port_warn (port,"lost during suspend, disconnecting\n" );tb_sw_set_unplugged (port->remote->sw); + }else if (port->xdomain) { +/* +* If the user replaced the XDomain with +* another router, this will succeed in +* which case we must remove the XDomain +* before adding the new router. +*/ + err =tb_cfg_get_upstream_port (sw->tb->ctl, + port->xdomain->route); +if (err >0 ) { +tb_port_warn (port, +"XDomain was disconnected\n" ); + port->xdomain->is_unplugged = true; + } } } }
drivers/thunderbolt/tb.c +29 -30
100 lines not on this page · raw message
drivers/thunderbolt/tb.h +2 -0
@@ -793,6 +793,7 @@ int tb_domain_disconnect_xdomain_paths(s int transmit_path, int transmit_ring, int receive_path, int receive_ring);int tb_domain_disconnect_all_paths (struct tb *tb); +int tb_domain_unregister_unplugged_xdomains (struct tb *tb);static inline struct tb *tb_domain_get (struct tb *tb) {
@@ -1263,6 +1264,7 @@ struct tb_xdomain *tb_xdomain_alloc(stru const uuid_t *remote_uuid);void tb_xdomain_add (struct tb_xdomain *xd);void tb_xdomain_remove (struct tb_xdomain *xd); +void tb_xdomain_unregister (struct tb_xdomain *xd);struct tb_xdomain *tb_xdomain_find_by_link_depth (struct tb *tb,u8 link,u8 depth);
drivers/thunderbolt/xdomain.c +33 -20
74 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 736/744 thunderbolt: Prevent XDomain delayed work use-after-free on disconnect
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit 2c5d2d3c3f70cde2565d7b279b544893a2035842 ]
tb_xdp_handle_request() runs on system_wq and queues xd->state_work via queue_delayed_work() in three request handlers:PROPERTIES_CHANGED_REQUEST, UUID_REQUEST (via start_handshake), and LINK_STATE_CHANGE_REQUEST. Similarly, update_xdomain() queues xd->properties_changed_work when local properties change.
Concurrently, tb_xdomain_remove() calls stop_handshake() which does cancel_delayed_work_sync() on both delayed works. Later, tb_xdomain_unregister() calls device_unregister() which eventually frees the xdomain. Since commit 559c1e1e0134 ("thunderbolt: Run tb_xdp_handle_request() in system workqueue") moved the request handler off tb->wq, the handler and the remove path are no longer serialized. If queue_delayed_work() executes after cancel_delayed_work_sync() but before the xdomain is freed, the delayed work fires on a freed object.
Add xd->removing that tb_xdomain_remove() sets under xd->lock before calling stop_handshake(). Each external queue site holds the same lock and checks removing before calling queue_delayed_work(). This provides the mutual exclusion needed:
either the queue site acquires the lock first and queues work that the subsequent cancel will see, or the remove path acquires the lock first and the queue site observes removing == true and skips the queue.
--- drivers/thunderbolt/xdomain.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-)
drivers/thunderbolt/xdomain.c +13 -13
@@ -909,6 +909,19 @@ void tb_unregister_service_driver(struct }EXPORT_SYMBOL_GPL (tb_unregister_service_driver); +static int update_xdomain (struct device *dev,void *data) +{ +struct tb_xdomain *xd; + + xd =tb_to_xdomain (dev); +if (xd) { +queue_delayed_work (xd->tb->wq, &xd->properties_changed_work, +msecs_to_jiffies (50 )); + } + +return 0 ; +} +static ssize_t key_show (struct device *dev,struct device_attribute *attr,char *buf) {
@@ -2500,19 +2513,6 @@ bool tb_xdomain_handle_request(struct tbreturn ret >0 ; } -static int update_xdomain (struct device *dev,void *data) -{ -struct tb_xdomain *xd; - - xd =tb_to_xdomain (dev); -if (xd) { -queue_delayed_work (xd->tb->wq, &xd->properties_changed_work, -msecs_to_jiffies (50 )); - } - -return 0 ; -} -static void update_all_xdomains (void ) {bus_for_each_dev (&tb_bus_type,NULL ,NULL , update_xdomain);
Greg Kroah-Hartman
maintainerPATCH 737/744 net: mana: Optimize irq affinity for low vcpu configs
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shradha Gupta <[email protected]>
[ Upstream commit 5316394b1752f6cf3f9901e7fefdec1cd1d97fd3 ]
Before the commit 755391121038 ("net: mana: Allocate MSI-X vectors dynamically"), all the MANA IRQs were assigned statically and together during early driver load.
After this commit, the IRQ allocation for MANA was done in two phases. HWC IRQ allocated earlier and then, queue IRQs dynamically added at a later point. By this time, the IRQ weights on vCPUs can become imbalanced and if IRQ count is greater than the vCPU count the topology aware IRQ distribution logic in MANA can cause multiple MANA IRQs to land on the same vCPUs, while other sibling vCPUs have none (case 1).
On SMP enabled, low-vCPU systems, this becomes a bigger problem as the softIRQ handling overhead of two IRQs on the same vCPUs becomes much more than their overheads if they were spread across sibling vCPUs.
In such cases when many parallel TCP connections are tested, the throughput drops significantly.
Fix the affinity assignment logic, in cases where the IRQ count is greater than the vCPU count and when IRQs are added dynamically, by utilizing all the vCPUs irrespective of their NUMA/core bindings (case 2).
The results of setting the affinity and hint to NULL were also studied, and we observed that, with this logic if there are pre-existing IRQs allocated on the VM (apart from MANA), during MANA IRQs allocation, it leads to clustering of the MANA queue IRQs again (case 3).
=======================================================
Case 1: without this patch
=======================================================
4 vcpu(2 cores), 5 MANA IRQs (1 HWC + 4 Queue)
TYPE effective vCPU aff
=======================================================
IRQ0: HWC 0
IRQ1: mana_q1 0
IRQ2: mana_q2 2
IRQ3: mana_q3 0
IRQ4: mana_q4 3
%soft on each vCPU(mpstat -P ALL 1) on receiver
vCPU 0 1 2 3
=======================================================
pass 1: 38.85 0.03 24.89 24.65
pass 2: 39.15 0.03 24.57 25.28
pass 3: 40.36 0.03 23.20 23.17
=======================================================
Case 2: with this patch
=======================================================
4 vcpu(2 cores), 5 MANA IRQs (1 HWC + 4 Queue)
TYPE effective vCPU aff
=======================================================
IRQ0: HWC 0 IRQ1: mana_q1 0 IRQ2: mana_q2 1 IRQ3: mana_q3 2 IRQ4: mana_q4 3
%soft on each vCPU(mpstat -P ALL 1) on receiver
vCPU 0 1 2 3
=======================================================
pass 1: 15.42 15.85 14.99 14.51 pass 2: 15.53 15.94 15.81 15.93 pass 3: 16.41 16.35 16.40 16.36
=======================================================
Case 3: with affinity set to NULL
=======================================================
4 vCPU(2 cores), 5 MANA IRQs (1 HWC + 4 Queue)
TYPE effective vCPU aff
=======================================================
IRQ0: HWC 0
IRQ1: mana_q1 2
IRQ2: mana_q2 3
IRQ3: mana_q3 2
IRQ4: mana_q4 3
=======================================================
Throughput Impact(in Gbps, same env)
=======================================================
TCP conn with patch w/o patch aff NULL
20480 15.65 7.73 5.25
10240 15.63 8.93 5.77
8192 15.64 9.69 7.16
6144 15.64 13.16 9.33
4096 15.69 15.75 13.50
2048 15.69 15.83 13.61
1024 15.71 15.28 13.60
--- drivers/net/ethernet/microsoft/mana/gdma_main.c | 78 +++++++++++++++++++----- 1 file changed, 64 insertions(+), 14 deletions(-)
drivers/net/ethernet/microsoft/mana/gdma_main.c +64 -14
@@ -197,6 +197,8 @@ static int mana_gd_query_max_resources(s }else {/* If dynamic allocation is enabled we have already allocated * hwc msi +* Also, we make sure in this case the following is always true +* (num_msix_usable - 1 HWC) <= num_online_cpus() */ gc->num_msix_usable =min (resp.max_msix,num_online_cpus () +1 ); }
@@ -1667,8 +1669,8 @@ void mana_gd_free_res_map(struct gdma_re* do the same thing. */ -static int irq_setup (unsigned int *irqs,unsigned int len,int node, -bool skip_first_cpu) +static int mana_irq_setup_numa_aware (unsigned int *irqs,unsigned int len, +int node,bool skip_first_cpu) {const struct cpumask *next, *prev = cpu_none_mask; cpumask_var_t cpus __free(free_cpumask_var);
@@ -1704,11 +1706,24 @@ done:return 0 ; } +/* must be called with cpus_read_lock() held */ +static void mana_irq_setup_linear (unsigned int *irqs,unsigned int len) +{ +int cpu; + +for_each_online_cpu (cpu) { +if (len ==0 ) +break ; + +irq_set_affinity_and_hint (*irqs++,cpumask_of (cpu)); + len--; + } +} +static int mana_gd_setup_dyn_irqs (struct pci_dev *pdev,int nvec) {struct gdma_context *gc =pci_get_drvdata (pdev);struct gdma_irq_context *gic; -bool skip_first_cpu = false;int *irqs, irq, err, i; irqs =kmalloc_objs (int, nvec);
@@ -1716,10 +1731,12 @@ static int mana_gd_setup_dyn_irqs(structreturn -ENOMEM ;/* +* In this function, num_msix_usable = HWC IRQ + Queue IRQ. +* nvec is only Queue IRQ (HWC already setup). * While processing the next pci irq vector, we start with index 1, * as IRQ vector at index 0 is already processed for HWC. * However, the population of irqs array starts with index 0, to be -* further used in irq_setup() +* further used in mana_irq_setup_numa_aware() */ for (i =1 ; i <= nvec; i++) { gic =kzalloc_obj (*gic);
@@ -1749,18 +1766,51 @@ static int mana_gd_setup_dyn_irqs(struct }/* -* When calling irq_setup() for dynamically added IRQs, if number of -* CPUs is more than or equal to allocated MSI-X, we need to skip the -* first CPU sibling group since they are already affinitized to HWC IRQ +* When calling mana_irq_setup_numa_aware() for dynamically added IRQs, +* if number of CPUs is more than or equal to allocated MSI-X, we need to +* skip the first CPU sibling group since they are already affinitized to +* HWC IRQ */ cpus_read_lock (); -if (gc->num_msix_usable <=num_online_cpus ()) - skip_first_cpu = true; +if (gc->num_msix_usable <=num_online_cpus ()) { + err =mana_irq_setup_numa_aware (irqs, nvec, gc->numa_node, + true); +if (err) { +cpus_read_unlock (); + goto free_irq; + } + }else { +/* +* When num_msix_usable are more than num_online_cpus, our +* queue IRQs should be equal to num of online vCPUs. +* We try to make sure queue IRQs spread across all vCPUs. +* In such a case NUMA or CPU core affinity does not matter. +* Note: in this case the total mana IRQ should always be +* num_online_cpus + 1. The first HWC IRQ is already handled +* in HWC setup calls +* However, if CPUs went offline since num_msix_usable was +* computed, queue IRQs will be more than num_online_cpus(). +* In such cases remaining extra IRQs will retain their default +* affinity. +*/ +int first_unassigned =num_online_cpus (); - err =irq_setup (irqs, nvec, gc->numa_node, skip_first_cpu); -if (err) { -cpus_read_unlock (); - goto free_irq; +if (nvec > first_unassigned) { +char buf[32 ]; + +if (first_unassigned == nvec -1 ) +snprintf (buf,sizeof (buf),"%d" , + first_unassigned); +else +snprintf (buf,sizeof (buf),"%d-%d" , + first_unassigned, nvec -1 ); + +dev_dbg (&pdev->dev, +"MANA IRQ indices #%s will retain the default CPU affinity\n" , + buf); + } + +mana_irq_setup_linear (irqs, nvec); }cpus_read_unlock ();
@@ -1846,7 +1896,7 @@ static int mana_gd_setup_irqs(struct pci nvec -=1 ; } - err =irq_setup (irqs, nvec, gc->numa_node, false); + err =mana_irq_setup_numa_aware (irqs, nvec, gc->numa_node, false);if (err) {cpus_read_unlock (); goto free_irq;
Greg Kroah-Hartman
maintainerPATCH 738/744 bootconfig: move xbc_snprint_cmdline() to lib/bootconfig.c
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 5a643e4623238e14b03d75ca0d4eda0645720cee ]
Move xbc_snprint_cmdline() from init/main.c to lib/bootconfig.c so the function (and its xbc_namebuf scratch buffer) becomes part of the shared parser library. tools/bootconfig already compiles lib/bootconfig.c directly, which lets a follow-up patch reuse the same renderer in the userspace tool to convert a bootconfig file into a flat cmdline string at build time.
No functional change.
Stable-dep-of: dec4d8118c17 ("bootconfig: fix NULL-pointer arithmetic in xbc_snprint_cmdline()")
--- include/linux/bootconfig.h | 3 ++ init/main.c | 45 ------------------------------------ lib/bootconfig.c | 56 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 45 deletions(-)
include/linux/bootconfig.h +3 -0
@@ -265,6 +265,9 @@ static inline struct xbc_node * __init xint __init xbc_node_compose_key_after (struct xbc_node *root,struct xbc_node *node,char *buf,size_t size); +/* Render key/value pairs under @root as a flat cmdline string */ +int __init xbc_snprint_cmdline (char *buf,size_t size,struct xbc_node *root); +/** * xbc_node_compose_key() - Compose full key string of the XBC node * @node: An XBC node.
init/main.c +0 -45
51 lines not on this page · raw message
lib/bootconfig.c +56 -0
62 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 739/744 bootconfig: fix NULL-pointer arithmetic in xbc_snprint_cmdline()
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit dec4d8118c179b3d12bca7e609054c6011c4f2ce ]
xbc_snprint_cmdline() is meant to be called twice: first with buf=NULL, size=0 to probe the rendered length, then with a real buffer to fill it (the standard snprintf() two-pass pattern). The probe call makes the function compute "buf + size" (NULL + 0) and, on every iteration, advance "buf += ret" from that NULL base and pass the result back into snprintf().
Pointer arithmetic on a NULL pointer is undefined behavior. It is harmless in the in-kernel callers today, but the follow-up patches run this same code in the userspace tools/bootconfig parser at kernel build time, where host UBSan / FORTIFY_SOURCE abort the build.
Track a running written length (size_t) instead of mutating @buf, and only form "buf + len" when @buf is non-NULL. snprintf(NULL, 0, ...) is itself well defined and returns the would-be length, so the two-pass "probe then fill" usage returns identical byte counts.
--- lib/bootconfig.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-)
lib/bootconfig.c +16 -7
@@ -427,10 +427,18 @@ static char xbc_namebuf[XBC_KEYLEN_MAX]int __init xbc_snprint_cmdline (char *buf,size_t size,struct xbc_node *root) {struct xbc_node *knode, *vnode; -char *end = buf + size;const char *val, *q; +size_t len =0 ;int ret; +/* +* Track the running written length rather than advancing @buf, so we +* never form "buf + size" or "buf += ret" while @buf is NULL (the +* size-probe call passes buf=NULL, size=0). NULL pointer arithmetic +* is undefined behavior and trips host UBSan / FORTIFY_SOURCE when +* this renderer runs at kernel build time. snprintf(NULL, 0, ...) +* itself is well defined and returns the would-be length. +*/ xbc_node_for_each_key_value (root, knode, val) { ret =xbc_node_compose_key_after (root, knode, xbc_namebuf,XBC_KEYLEN_MAX );
@@ -439,10 +447,11 @@ int __init xbc_snprint_cmdline(char *buf vnode =xbc_node_get_child (knode);if (!vnode) { - ret =snprintf (buf,rest (buf, end),"%s " , xbc_namebuf); + ret =snprintf (buf ? buf + len :NULL ,rest (len, size), +"%s " , xbc_namebuf);if (ret <0 )return ret; - buf += ret; + len += ret;continue ; }xbc_array_for_each_value (vnode, val) {
@@ -452,15 +461,15 @@ int __init xbc_snprint_cmdline(char *buf* whitespace. */ q =strpbrk (val," \t\r\n" ) ?"\"" :"" ; - ret =snprintf (buf,rest (buf, end),"%s=%s%s%s " , - xbc_namebuf, q, val, q); + ret =snprintf (buf ? buf + len :NULL ,rest (len, size), +"%s=%s%s%s " , xbc_namebuf, q, val, q);if (ret <0 )return ret; - buf += ret; + len += ret; } } -return buf - (end - size); +return len; }#undef rest
Greg Kroah-Hartman
maintainerPATCH 740/744 sched_ext: Move shared helpers from ext.c into internal.h and cid.h
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tejun Heo <[email protected]>
[ Upstream commit 4437ad129cf5b37c00a5bc9fa5989d1da4d64d07 ]
idle.c and cid.c are included into build_policy.c together with ext.c and use helpers that ext.c defines. Because the helpers live in ext.c, the two files can not parse as standalone units and clangd reports errors in them.
Move the helpers to the headers they belong to. The op-dispatch macros and helpers plus scx_parent() to internal.h, and scx_cpu_arg()/scx_cpu_ret() to cid.h. No functional change. idle.c and cid.c now parse clean standalone.
Stable-dep-of: 18d62044cda7 ("sched_ext: Preserve rq tracking across local DSQ dispatch")
--- kernel/sched/ext.c | 29 ----------------------------- kernel/sched/ext_internal.h | 30 ++++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 29 deletions(-)
kernel/sched/ext.c +0 -29
@@ -218,8 +218,6 @@ static __printf(4, 5) bool scx_exit(stru #define scx_error(sch, fmt, args...) scx_exit((sch), SCX_EXIT_ERROR, 0, fmt, ##args)#define scx_verror (sch, fmt, args) scx_vexit((sch), SCX_EXIT_ERROR, 0, fmt, args) -#define SCX_HAS_OP (sch, op) test_bit(SCX_OP_IDX(op), (sch)->has_op) -static long jiffies_delta_msecs (unsigned long at,unsigned long now) {if (time_after (at, now))
@@ -235,20 +233,6 @@ static bool u32_before(u32 a, u32 b)#ifdef CONFIG_EXT_SUB_SCHED /** -* scx_parent - Find the parent sched -* @sch: sched to find the parent of -* -* Returns the parent scheduler or %NULL if @sch is root. -*/ -static struct scx_sched *scx_parent (struct scx_sched *sch) -{ -if (sch->level) -return sch->ancestors[sch->level -1 ]; -else -return NULL ; -} - -/** * scx_next_descendant_pre - find the next descendant for pre-order walk * @pos: the current position (%NULL to initiate traversal) * @root: sched whose descendants to walk
@@ -295,7 +279,6 @@ static void scx_set_task_sched(struct ta rcu_assign_pointer(p->scx.sched, sch); }#else /* CONFIG_EXT_SUB_SCHED */ -static struct scx_sched *scx_parent (struct scx_sched *sch) {return NULL ; }static struct scx_sched *scx_next_descendant_pre (struct scx_sched *pos,struct scx_sched *root) {return pos ?NULL : root; }static void scx_set_task_sched (struct task_struct *p,struct scx_sched *sch) {}#endif /* CONFIG_EXT_SUB_SCHED */
@@ -455,18 +438,6 @@ static bool rq_is_open(struct rq *rq, u6*/ DEFINE_PER_CPU(struct rq *, scx_locked_rq_state); -static inline void update_locked_rq (struct rq *rq) -{ -/* -* Check whether @rq is actually locked. This can help expose bugs -* or incorrect assumptions about the context in which a kfunc or -* callback is executed. -*/ -if (rq) -lockdep_assert_rq_held (rq); -__this_cpu_write (scx_locked_rq_state, rq); -} -/* * SCX ops can recurse via scx_bpf_sub_dispatch() - the inner call must not * clobber the outer's scx_locked_rq_state. Save it on entry, restore on exit.
kernel/sched/ext_internal.h +30 -0
@@ -1377,6 +1377,20 @@ static inline struct rq *scx_locked_rq(vreturn __this_cpu_read (scx_locked_rq_state); } +static inline void update_locked_rq (struct rq *rq) +{ +/* +* Check whether @rq is actually locked. This can help expose bugs +* or incorrect assumptions about the context in which a kfunc or +* callback is executed. +*/ +if (rq) +lockdep_assert_rq_held (rq); +__this_cpu_write (scx_locked_rq_state, rq); +} + +#define SCX_HAS_OP (sch, op) test_bit(SCX_OP_IDX(op), (sch)->has_op) +static inline bool scx_bypassing (struct scx_sched *sch,s32 cpu) { return unlikely(per_cpu_ptr(sch->pcpu, cpu)->flags &
@@ -1457,6 +1471,20 @@ static inline struct scx_sched *scx_prog return NULL; } + +/** +* scx_parent - Find the parent sched +* @sch: sched to find the parent of +* +* Returns the parent scheduler or %NULL if @sch is root. +*/ +static inline struct scx_sched *scx_parent (struct scx_sched *sch) +{ +if (sch->level) +return sch->ancestors[sch->level -1 ]; +else +return NULL ; +}#else /* CONFIG_EXT_SUB_SCHED */ static inline struct scx_sched *scx_task_sched (const struct task_struct *p) {
@@ -1480,4 +1508,6 @@ static struct scx_sched *scx_prog_sched( {return rcu_dereference_all (scx_root); } + +static inline struct scx_sched *scx_parent (struct scx_sched *sch) {return NULL ; }#endif /* CONFIG_EXT_SUB_SCHED */
Greg Kroah-Hartman
maintainerPATCH 741/744 sched_ext: Preserve rq tracking across local DSQ dispatch
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andrea Righi <[email protected]>
[ Upstream commit 18d62044cda7a2b40f59d910659c0b0d6accad37 ]
dispatch_to_local_dsq() can run from scx_bpf_dsq_move_to_local() while ops.dispatch() has recorded the current rq. Moving a task to a local DSQ may switch to the source or destination rq before synchronously invoking ops.dequeue() through the following path:
SCX_CALL_OP(dispatch, rq)
ops.dispatch()
scx_bpf_dsq_move_to_local()
scx_flush_dispatch_buf()
finish_dispatch()
dispatch_to_local_dsq()
scx_dispatch_enqueue()
local_dsq_post_enq()
call_task_dequeue()
SCX_CALL_OP_TASK(dequeue, locked_rq, ...)The nested callback saves the recorded rq and restores it on return. If the rq tracking does not follow the lock switch, update_locked_rq() can trigger the following lockdep assertion while restoring an rq which is no longer held:
WARNING: kernel/sched/sched.h:1641 at call_task_dequeue+0x160/0x170
Call Trace:
scx_dispatch_enqueue+0x2b0/0x460
dispatch_to_local_dsq+0x138/0x230
scx_flush_dispatch_buf+0x1af/0x220
scx_bpf_dsq_move_to_local___v2+0xe2/0x1c0
bpf__sched_ext_ops_dispatch+0x4b/0xa7
do_pick_task_scx+0x3b6/0x910
__pick_next_task+0x105/0x1f0
__schedule+0x3e7/0x1980Introduce switch_rq_lock() to update the tracking state together with each rq lock handoff. Use it in dispatch_to_local_dsq(), move_remote_task_to_local_dsq() and the in-balance paths of scx_dsq_move(), ensuring that scx_locked_rq() consistently refers to the rq whose lock is actually held throughout the lock dance.
--- kernel/sched/ext.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-)
kernel/sched/ext.c +20 -16
@@ -438,6 +438,18 @@ static bool rq_is_open(struct rq *rq, u6*/ DEFINE_PER_CPU(struct rq *, scx_locked_rq_state); +static void switch_rq_lock (struct rq *from,struct rq *to) +{ +bool tracked =scx_locked_rq () == from; + +if (tracked) +update_locked_rq (NULL ); +raw_spin_rq_unlock (from); +raw_spin_rq_lock (to); +if (tracked) +update_locked_rq (to); +} +/* * SCX ops can recurse via scx_bpf_sub_dispatch() - the inner call must not * clobber the outer's scx_locked_rq_state. Save it on entry, restore on exit.
@@ -2262,8 +2274,7 @@ static void move_remote_task_to_local_dsdeactivate_task (src_rq, p,0 );set_task_cpu (p,cpu_of (dst_rq)); -raw_spin_rq_unlock (src_rq); -raw_spin_rq_lock (dst_rq); +switch_rq_lock (src_rq, dst_rq);/* * We want to pass scx-specific enq_flags but activate_task() will
@@ -2594,9 +2605,8 @@ static void dispatch_to_local_dsq(struct/* switch to @src_rq lock */ if (locked_rq != src_rq) { -raw_spin_rq_unlock (locked_rq); +switch_rq_lock (locked_rq, src_rq); locked_rq = src_rq; -raw_spin_rq_lock (src_rq); }/* task_rq couldn't have changed if we're still the holding cpu */
@@ -2624,10 +2634,8 @@ static void dispatch_to_local_dsq(struct }/* switch back to @rq lock */ -if (locked_rq != rq) { -raw_spin_rq_unlock (locked_rq); -raw_spin_rq_lock (rq); - } +if (locked_rq != rq) +switch_rq_lock (locked_rq, rq); }/**
@@ -8405,10 +8413,8 @@ static bool scx_dsq_move(struct bpf_iter in_balance = this_rq->scx.flags &SCX_RQ_IN_BALANCE ;if (in_balance) { -if (this_rq != src_rq) { -raw_spin_rq_unlock (this_rq); -raw_spin_rq_lock (src_rq); - } +if (this_rq != src_rq) +switch_rq_lock (this_rq, src_rq); }else {raw_spin_rq_lock (src_rq); }
@@ -8440,10 +8446,8 @@ static bool scx_dsq_move(struct bpf_iter dispatched = true; out:if (in_balance) { -if (this_rq != locked_rq) { -raw_spin_rq_unlock (locked_rq); -raw_spin_rq_lock (this_rq); - } +if (this_rq != locked_rq) +switch_rq_lock (locked_rq, this_rq); }else {raw_spin_rq_unlock_irqrestore (locked_rq, flags); }
Greg Kroah-Hartman
maintainerPATCH 742/744 selftests: drv-net: cope with slow env in so_txtime.py test
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Willem de Bruijn <[email protected]>
commit 543bdc1578cd380631558a884318551a0e9fdab2 upstream.
This test was converted from shell script to drv-net test.
The new version is flaky in dbg builds on the netdev.bots dashboard. The previous shell script had more protections to avoid these. Added in commit a7ee79b9c455 ("selftests: net: cope with slow env in so_txtime.sh test").
Add the same overall protection:
- Suppress so_txtime process failure if KSFT_MACHINE_SLOW
Also relax two timeouts to reduce the number of process failures themselves
- Increase SO_RCVTIMEO to 2 seconds
- Increase process start-up stabilization to 2 seconds
Delays were experimentally arrived at while running with vng built with kernel/configs/debug.config
--- tools/testing/selftests/drivers/net/so_txtime.c | 10 ++++++++-- tools/testing/selftests/drivers/net/so_txtime.py | 11 +++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-)
tools/testing/selftests/drivers/net/so_txtime.c +8 -2
@@ -38,6 +38,7 @@static int cfg_clockid =CLOCK_TAI ;static uint16_t cfg_port =8000 ;static int cfg_variance_us =4000 ; +static bool cfg_machine_slow;static uint64_t cfg_start_time_ns;static int cfg_mark;static bool cfg_rx;
@@ -142,7 +143,7 @@ static void do_recv_one(int fdr, structif (llabs (tstop - texpect) > cfg_variance_us) {fprintf (stderr,"exceeds variance (%d us)\n" , cfg_variance_us); -if (!getenv ("KSFT_MACHINE_SLOW" )) +if (!cfg_machine_slow) errors++; } }
@@ -263,7 +264,7 @@ static void start_time_wait(void) now =gettime_ns (CLOCK_REALTIME );if (cfg_start_time_ns < now) {fprintf (stderr,"FAIL: start time already passed\n" ); -if (!getenv ("KSFT_MACHINE_SLOW" )) +if (!cfg_machine_slow) errors++;return ; }
@@ -326,6 +327,9 @@ static int setup_rx(struct sockaddr *addif (bind (fd, addr, alen))error (1 , errno,"bind" ); +if (cfg_machine_slow) + tv.tv_sec =2 ; +if (setsockopt (fd,SOL_SOCKET ,SO_RCVTIMEO , &tv,sizeof (tv)))error (1 , errno,"setsockopt rcv timeout" );
@@ -512,6 +516,8 @@ static void parse_opts(int argc, char **setup_sockaddr (domain, saddr, &cfg_src_addr); cfg_num_pkt =parse_io (argv[optind], cfg_buf); + + cfg_machine_slow =getenv ("KSFT_MACHINE_SLOW" ); }int main (int argc,char **argv)
tools/testing/selftests/drivers/net/so_txtime.py +9 -2
@@ -6,6 +6,7 @@ Test delivery time in FQ and ETF qdiscs. """ +import os import time from lib.py import ksft_exit, ksft_run, ksft_variants
@@ -15,17 +16,23 @@ from lib.py import NetDrvEpEnv, bkg, cmd def test_so_txtime(cfg, clockid, ipver, args_tx, args_rx, expect_success): """Main function. Run so_txtime as sender and receiver.""" + slow_machine = os.environ.get('KSFT_MACHINE_SLOW') + bin_path = cfg.test_dir / "so_txtime" - tstart = time.time_ns() + 200_000_000 + tstart = time.time_ns() + (2000_000_000 if slow_machine else 200_000_000) cmd_addr = f"-S {cfg.addr_v[ipver]} -D {cfg.remote_addr_v[ipver]}" cmd_base = f"{bin_path} -{ipver} -c {clockid} -t {tstart} {cmd_addr}" cmd_rx = f"{cmd_base} {args_rx} -r" cmd_tx = f"{cmd_base} {args_tx}" + expect_fail = not expect_success + if slow_machine: + expect_success = False + with bkg(cmd_rx, host=cfg.remote, fail=expect_success, - expect_fail=(not expect_success), exit_wait=True): + expect_fail=expect_fail, exit_wait=True): cmd(cmd_tx)
Greg Kroah-Hartman
maintainerPATCH 743/744 selftests: drv-net: so_txtime: relax variance bounds
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Willem de Bruijn <[email protected]>
commit e38fec239d923de5bfb65f7fce15ca52c5a3aa7f upstream.
The net-next-hw spinners on netdev.bots.linux.dev observe failing so-txtime-py tests. A review of stdout shows most failures to be due to exceeding the 4ms grace period. All I saw were within 8ms. So increase to that.
Double the bounds from 4 to 8ms. This is still is small enough to differentiate the delays programmed by the test, 10 and 20ms.
--- tools/testing/selftests/drivers/net/so_txtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/drivers/net/so_txtime.c +1 -1
@@ -37,7 +37,7 @@static int cfg_clockid =CLOCK_TAI ;static uint16_t cfg_port =8000 ; -static int cfg_variance_us =4000 ; +static int cfg_variance_us =8000 ;static bool cfg_machine_slow;static uint64_t cfg_start_time_ns;static int cfg_mark;
Greg Kroah-Hartman
maintainerPATCH 744/744 KVM: SVM: Bump asid_generation on CPU online to avoid ASID collision after hotplug
In reply to Greg Kroah-Hartman7.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikunj A Dadhania <[email protected]>
commit 25f744ffa0c8e799e06250ce2e618367b166b0d4 upstream.
If a vCPU stays scheduled out (or blocked) while the last pCPU it ran on goes through a hotplug cycle (online->offline->online), and the vCPU then resumes execution on the same pCPU, then it is possible for it to run with an ASID that has now been assigned to a different vCPU, resulting in stale TLB translations being used.
svm_enable_virtualization_cpu() resets asid_generation to 1 and sets next_asid to max_asid + 1 on every CPU online event, including hotplug cycles. Because next_asid starts beyond the pool boundary, the first call to new_asid() after an online event always wraps the pool, incrementing asid_generation to 2 and assigning ASIDs starting from min_asid.
Consider two vCPUs from different VMs, vCPU-A pinned to CPU-X holding asid_generation=2 and ASID=N from before the hotplug event:
1. CPU-X goes offline and back online: asid_generation resets to 1, next_asid = max_asid + 1.
2. One or more vCPUs migrate to CPU-X and call new_asid(), wrapping the pool and consuming ASIDs starting from min_asid. Eventually vCPU-B from a different VM is assigned asid_generation=2, ASID=N — the same ASID that vCPU-A held before the hotplug.
3. vCPU-A enters pre_svm_run() on CPU-X: current_vmcb->cpu is unchanged so the migration branch is skipped. Its saved asid_generation=2 matches sd->asid_generation=2, so the generation check silently passes and vCPU-A continues running with ASID=N — the same ASID just freshly assigned to vCPU-B.
Both vCPUs from different VMs now run on CPU-X with the same ASID, causing them to share NPT TLB entries and producing stale translations.
The collision manifests as a KVM internal error (Suberror: 1, emulation failure). The NPT page fault reports a faulting GPA far outside the VM's physical memory range — a sign of stale TLB translations being used. KVM falls back to instruction emulation, which fails on FPU/XSave instructions (XRSTOR, STMXCSR) that the emulator does not implement.
Fix this by incrementing asid_generation instead of resetting it to 1 in svm_enable_virtualization_cpu(). On module load, asid_generation starts at 0 (memset) and the increment produces 1, identical to the old behaviour. On subsequent hotplug cycles the generation advances beyond any value a vCPU previously observed on this CPU, so the generation check in pre_svm_run() reliably forces new_asid() on every vCPU after every hotplug cycle.
Message-ID: <[email protected]>
--- arch/x86/kvm/svm/svm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
arch/x86/kvm/svm/svm.c +6 -1
@@ -566,7 +566,12 @@ static int svm_enable_virtualization_cpureturn r; sd =per_cpu_ptr (&svm_data, me); - sd->asid_generation =1 ; +/* +* Bump the current asid_generation value to ensure any vCPU that +* previously ran on this CPU sees a stale generation and is forced +* to acquire a new ASID, preventing a latent ASID collision. +*/ + sd->asid_generation++; sd->max_asid =cpuid_ebx (SVM_CPUID_FUNC ) -1 ; sd->next_asid = sd->max_asid +1 ; sd->min_asid = max_sev_asid +1 ;
Quoted 8 lines · On Thu, 30 Jul 2026 16:04:33 +0200 Greg Kroah-Hartman…
This is the start of the stable review cycle for the 7.1.6 release. There are 744 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 01 Aug 2026 14:13:38 +0000. Anything received after that time might be too late.
Boot-tested under QEMU for Rust x86_64, arm64 and riscv64; built-tested for loongarch64 and arm32:
Thanks!
Cheers,
Miguel
# Librecast Test Results
020/020 [ OK ] liblcrq
010/010 [ OK ] libmld
120/120 [ OK ] liblibrecast
CPU/kernel: Linux auntie 7.1.6-rc1-gecc0c68d2044 #1 SMP PREEMPT_DYNAMIC Thu Jul 30 20:03:55 -00 2026 x86_64 AMD Ryzen 9 9950X 16-Core Processor AuthenticAMD GNU/Linux
Am 30.07.2026 um 16:04 schrieb Greg Kroah-Hartman:
Quoted 4 lines
This is the start of the stable review cycle for the 7.1.6 release. There are 744 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Builds, boots and works on my 2-socket Ivy Bridge Xeon E5-2697 v2 server. No dmesg oddities or regressions found.
Beste Grüße,
Peter Schneider
Signature · 8 lines
Climb the mountain not to plant your flag, but to embrace the challenge, enjoy the air and behold the view. Climb it so you can see the world, not so the world can see you. -- David McCullough Jr. OpenPGP: 0xA3828BD796CCE11A8CADE8866E3A92C92C3FF244 Download: https://www.peters-netzplatz.de/download/pschneider1968_pub.asc https://keys.mailvelope.com/pks/lookup?op=get&[email protected] https://keys.mailvelope.com/pks/lookup?op=get&[email protected]
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.1.6 release. There are 744 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 01 Aug 2026 14:13:38 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 9 lines
https://www.kernel.org/pub/linux/kernel/v7.x/stable-review/patch-7.1.6-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-7.1.y
and the diffstat can be found below.thanks,
greg k-h
Compiled and booted on my test system. No dmesg regressions.
thanks,
-- Shuah
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.1.6 release. There are 744 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 01 Aug 2026 14:13:38 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v7.x/stable-review/patch-7.1.6-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-7.1.y
and the diffstat can be found below.thanks,
greg k-h
Tested rc1 against the Fedora build system (aarch64, ppc64le, s390x, x86_64), and boot tested x86_64. No regressions noted.
Hi!
Quoted 4 lines
This is the start of the stable review cycle for the 7.1.6 release. There are 744 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
CIP testing did not find any problems here:
https://gitlab.com/cip-project/cip-testing/linux-stable-rc-ci/-/tree/linux-7.1.y
Best regards,
Pavel
Hi Greg
Quoted 10 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.1.6 release. There are 744 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 01 Aug 2026 14:13:38 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 9 lines
https://www.kernel.org/pub/linux/kernel/v7.x/stable-review/patch-7.1.6-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-7.1.y
and the diffstat can be found below.thanks,
greg k-h
Linux version 7.1.6-rc1 tested.
Build successfully completed.
Boot successfully completed.
No dmesg regressions.
Video output normal.
Sound output normal.
Lenovo ThinkPad X1 Carbon Gen10(Intel i7-1260P(x86_64) arch linux)
[ 0.000000] Linux version 7.1.6-rc1rv-gecc0c68d2044
(takeshi@ThinkPadX1Gen10J0764) (gcc (GCC) 16.1.1 20260728, GNU ld (GNU Binutils) 2.47) #1 SMP PREEMPT_DYNAMIC Fri Jul 31 19:44:25 JST 2026
Thanks
Quoted 7 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.1.6 release. There are 744 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 01 Aug 2026 14:13:38 +0000. Anything received after that time might be too late.
Build and boot tested with qemu for x86_64, i386, arm64 and riscv and different configurations. No regressions observed.
Quoted 4 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.1.6 release. There are 744 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.1.6 release. There are 744 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 01 Aug 2026 14:13:38 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v7.x/stable-review/patch-7.1.6-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-7.1.y
and the diffstat can be found below.thanks,
greg k-h
On ARCH_BRCMSTB using 32-bit and 64-bit ARM kernels, build tested on BMIPS_GENERIC:
Signature · 1 line
Florian
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.1.6 release. There are 744 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 01 Aug 2026 14:13:38 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v7.x/stable-review/patch-7.1.6-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-7.1.y
and the diffstat can be found below.thanks,
greg k-h
Tested on 2 amd64 systems and an arm64 virtual machine. Working well, no regressions observed.
Signature · 1 line
-Barry K. Nathan <[email protected]>
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.1.6 release. There are 744 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 01 Aug 2026 14:13:38 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v7.x/stable-review/patch-7.1.6-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-7.1.y
and the diffstat can be found below.thanks,
greg k-h
Built and booted successfully on RISC-V RV64 (HiFive Unmatched).
hello,
Compiled and booted 7.1.6-rc1 (using qemu-system-amd64)
No new typical dmesg regressions .
--
software engineer
rajagiri school of engineering and technology