From: Sasha Levin Date: Tue, 10 Jan 2023 01:55:38 +0000 (-0500) Subject: Fixes for 4.19 X-Git-Tag: v5.15.87~41 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=475ea865f5c1c01069e1d2fa4572ef63a857fc57;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 4.19 Signed-off-by: Sasha Levin --- diff --git a/queue-4.19/asoc-intel-bytcr_rt5640-add-quirk-for-the-advantech-.patch b/queue-4.19/asoc-intel-bytcr_rt5640-add-quirk-for-the-advantech-.patch new file mode 100644 index 00000000000..dd731a61ebd --- /dev/null +++ b/queue-4.19/asoc-intel-bytcr_rt5640-add-quirk-for-the-advantech-.patch @@ -0,0 +1,59 @@ +From 94551df8a1ed817d40347cd7c25d83d99f4d0efc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Dec 2022 13:32:46 +0100 +Subject: ASoC: Intel: bytcr_rt5640: Add quirk for the Advantech MICA-071 + tablet + +From: Hans de Goede + +[ Upstream commit a1dec9d70b6ad97087b60b81d2492134a84208c6 ] + +The Advantech MICA-071 tablet deviates from the defaults for +a non CR Bay Trail based tablet in several ways: + +1. It uses an analog MIC on IN3 rather then using DMIC1 +2. It only has 1 speaker +3. It needs the OVCD current threshold to be set to 1500uA instead of + the default 2000uA to reliable differentiate between headphones vs + headsets + +Add a quirk with these settings for this tablet. + +Signed-off-by: Hans de Goede +Acked-by: Pierre-Louis Bossart +Link: https://lore.kernel.org/r/20221213123246.11226-1-hdegoede@redhat.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/intel/boards/bytcr_rt5640.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c +index c4d19b88d17d..2001bc774c64 100644 +--- a/sound/soc/intel/boards/bytcr_rt5640.c ++++ b/sound/soc/intel/boards/bytcr_rt5640.c +@@ -437,6 +437,21 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, ++ { ++ /* Advantech MICA-071 */ ++ .matches = { ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Advantech"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "MICA-071"), ++ }, ++ /* OVCD Th = 1500uA to reliable detect head-phones vs -set */ ++ .driver_data = (void *)(BYT_RT5640_IN3_MAP | ++ BYT_RT5640_JD_SRC_JD2_IN4N | ++ BYT_RT5640_OVCD_TH_1500UA | ++ BYT_RT5640_OVCD_SF_0P75 | ++ BYT_RT5640_MONO_SPEAKER | ++ BYT_RT5640_DIFF_MIC | ++ BYT_RT5640_MCLK_EN), ++ }, + { + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"), +-- +2.35.1 + diff --git a/queue-4.19/bpf-pull-before-calling-skb_postpull_rcsum.patch b/queue-4.19/bpf-pull-before-calling-skb_postpull_rcsum.patch new file mode 100644 index 00000000000..67ea20e9d12 --- /dev/null +++ b/queue-4.19/bpf-pull-before-calling-skb_postpull_rcsum.patch @@ -0,0 +1,61 @@ +From bde099d959e905a194a292d3d53661c248e47529 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Dec 2022 16:47:00 -0800 +Subject: bpf: pull before calling skb_postpull_rcsum() + +From: Jakub Kicinski + +[ Upstream commit 54c3f1a81421f85e60ae2eaae7be3727a09916ee ] + +Anand hit a BUG() when pulling off headers on egress to a SW tunnel. +We get to skb_checksum_help() with an invalid checksum offset +(commit d7ea0d9df2a6 ("net: remove two BUG() from skb_checksum_help()") +converted those BUGs to WARN_ONs()). +He points out oddness in how skb_postpull_rcsum() gets used. +Indeed looks like we should pull before "postpull", otherwise +the CHECKSUM_PARTIAL fixup from skb_postpull_rcsum() will not +be able to do its job: + + if (skb->ip_summed == CHECKSUM_PARTIAL && + skb_checksum_start_offset(skb) < 0) + skb->ip_summed = CHECKSUM_NONE; + +Reported-by: Anand Parthasarathy +Fixes: 6578171a7ff0 ("bpf: add bpf_skb_change_proto helper") +Signed-off-by: Jakub Kicinski +Acked-by: Stanislav Fomichev +Link: https://lore.kernel.org/r/20221220004701.402165-1-kuba@kernel.org +Signed-off-by: Martin KaFai Lau +Signed-off-by: Sasha Levin +--- + net/core/filter.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/net/core/filter.c b/net/core/filter.c +index aa2e7baa13c4..32d0b8f14aab 100644 +--- a/net/core/filter.c ++++ b/net/core/filter.c +@@ -2565,15 +2565,18 @@ static int bpf_skb_generic_push(struct sk_buff *skb, u32 off, u32 len) + + static int bpf_skb_generic_pop(struct sk_buff *skb, u32 off, u32 len) + { ++ void *old_data; ++ + /* skb_ensure_writable() is not needed here, as we're + * already working on an uncloned skb. + */ + if (unlikely(!pskb_may_pull(skb, off + len))) + return -ENOMEM; + +- skb_postpull_rcsum(skb, skb->data + off, len); +- memmove(skb->data + len, skb->data, off); ++ old_data = skb->data; + __skb_pull(skb, len); ++ skb_postpull_rcsum(skb, old_data + off, len); ++ memmove(skb->data, old_data, off); + + return 0; + } +-- +2.35.1 + diff --git a/queue-4.19/caif-fix-memory-leak-in-cfctrl_linkup_request.patch b/queue-4.19/caif-fix-memory-leak-in-cfctrl_linkup_request.patch new file mode 100644 index 00000000000..d667ae76c37 --- /dev/null +++ b/queue-4.19/caif-fix-memory-leak-in-cfctrl_linkup_request.patch @@ -0,0 +1,47 @@ +From edf56f9914f237065c78cff9bb7a962059ebf56e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Jan 2023 14:51:46 +0800 +Subject: caif: fix memory leak in cfctrl_linkup_request() + +From: Zhengchao Shao + +[ Upstream commit fe69230f05897b3de758427b574fc98025dfc907 ] + +When linktype is unknown or kzalloc failed in cfctrl_linkup_request(), +pkt is not released. Add release process to error path. + +Fixes: b482cd2053e3 ("net-caif: add CAIF core protocol stack") +Fixes: 8d545c8f958f ("caif: Disconnect without waiting for response") +Signed-off-by: Zhengchao Shao +Reviewed-by: Jiri Pirko +Link: https://lore.kernel.org/r/20230104065146.1153009-1-shaozhengchao@huawei.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/caif/cfctrl.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/caif/cfctrl.c b/net/caif/cfctrl.c +index a1e85f032108..330cb2b087bb 100644 +--- a/net/caif/cfctrl.c ++++ b/net/caif/cfctrl.c +@@ -269,11 +269,15 @@ int cfctrl_linkup_request(struct cflayer *layer, + default: + pr_warn("Request setup of bad link type = %d\n", + param->linktype); ++ cfpkt_destroy(pkt); + return -EINVAL; + } + req = kzalloc(sizeof(*req), GFP_KERNEL); +- if (!req) ++ if (!req) { ++ cfpkt_destroy(pkt); + return -ENOMEM; ++ } ++ + req->client_layer = user_layer; + req->cmd = CFCTRL_CMD_LINK_SETUP; + req->param = *param; +-- +2.35.1 + diff --git a/queue-4.19/dm-thin-resume-even-if-in-fail-mode.patch b/queue-4.19/dm-thin-resume-even-if-in-fail-mode.patch new file mode 100644 index 00000000000..19045c89571 --- /dev/null +++ b/queue-4.19/dm-thin-resume-even-if-in-fail-mode.patch @@ -0,0 +1,77 @@ +From a73aeed02ca2e67f6b7ed6662f664affd8fb3d82 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 30 Nov 2022 10:09:45 +0800 +Subject: dm thin: resume even if in FAIL mode + +From: Luo Meng + +[ Upstream commit 19eb1650afeb1aa86151f61900e9e5f1de5d8d02 ] + +If a thinpool set fail_io while suspending, resume will fail with: + device-mapper: resume ioctl on vg-thinpool failed: Invalid argument + +The thin-pool also can't be removed if an in-flight bio is in the +deferred list. + +This can be easily reproduced using: + + echo "offline" > /sys/block/sda/device/state + dd if=/dev/zero of=/dev/mapper/thin bs=4K count=1 + dmsetup suspend /dev/mapper/pool + mkfs.ext4 /dev/mapper/thin + dmsetup resume /dev/mapper/pool + +The root cause is maybe_resize_data_dev() will check fail_io and return +error before called dm_resume. + +Fix this by adding FAIL mode check at the end of pool_preresume(). + +Cc: stable@vger.kernel.org +Fixes: da105ed5fd7e ("dm thin metadata: introduce dm_pool_abort_metadata") +Signed-off-by: Luo Meng +Signed-off-by: Mike Snitzer +Signed-off-by: Sasha Levin +--- + drivers/md/dm-thin.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c +index 1916becc20e0..386cb3395378 100644 +--- a/drivers/md/dm-thin.c ++++ b/drivers/md/dm-thin.c +@@ -3549,20 +3549,28 @@ static int pool_preresume(struct dm_target *ti) + */ + r = bind_control_target(pool, ti); + if (r) +- return r; ++ goto out; + + r = maybe_resize_data_dev(ti, &need_commit1); + if (r) +- return r; ++ goto out; + + r = maybe_resize_metadata_dev(ti, &need_commit2); + if (r) +- return r; ++ goto out; + + if (need_commit1 || need_commit2) + (void) commit(pool); ++out: ++ /* ++ * When a thin-pool is PM_FAIL, it cannot be rebuilt if ++ * bio is in deferred list. Therefore need to return 0 ++ * to allow pool_resume() to flush IO. ++ */ ++ if (r && get_pool_mode(pool) == PM_FAIL) ++ r = 0; + +- return 0; ++ return r; + } + + static void pool_suspend_active_thins(struct pool *pool) +-- +2.35.1 + diff --git a/queue-4.19/driver-core-set-deferred_probe_timeout-to-a-longer-d.patch b/queue-4.19/driver-core-set-deferred_probe_timeout-to-a-longer-d.patch new file mode 100644 index 00000000000..4b41cb0a4cc --- /dev/null +++ b/queue-4.19/driver-core-set-deferred_probe_timeout-to-a-longer-d.patch @@ -0,0 +1,69 @@ +From b1a12d0dc447462f5e0cafa2c8fa8cc72939a5a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Feb 2020 05:08:24 +0000 +Subject: driver core: Set deferred_probe_timeout to a longer default if + CONFIG_MODULES is set + +From: John Stultz + +[ Upstream commit e2cec7d6853712295cef5377762165a489b2957f ] + +When using modules, its common for the modules not to be loaded +until quite late by userland. With the current code, +driver_deferred_probe_check_state() will stop returning +EPROBE_DEFER after late_initcall, which can cause module +dependency resolution to fail after that. + +So allow a longer window of 30 seconds (picked somewhat +arbitrarily, but influenced by the similar regulator core +timeout value) in the case where modules are enabled. + +Cc: linux-pm@vger.kernel.org +Cc: Greg Kroah-Hartman +Cc: Linus Walleij +Cc: Thierry Reding +Cc: Mark Brown +Cc: Liam Girdwood +Cc: Bjorn Andersson +Cc: Saravana Kannan +Cc: Todd Kjos +Cc: Len Brown +Cc: Pavel Machek +Cc: Ulf Hansson +Cc: Kevin Hilman +Cc: "Rafael J. Wysocki" +Cc: Rob Herring +Reviewed-by: Bjorn Andersson +Reviewed-by: Rafael J. Wysocki +Signed-off-by: John Stultz +Link: https://lore.kernel.org/r/20200225050828.56458-3-john.stultz@linaro.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/base/dd.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/base/dd.c b/drivers/base/dd.c +index 63390a416b44..529d324a0f20 100644 +--- a/drivers/base/dd.c ++++ b/drivers/base/dd.c +@@ -220,7 +220,16 @@ static int deferred_devs_show(struct seq_file *s, void *data) + } + DEFINE_SHOW_ATTRIBUTE(deferred_devs); + ++#ifdef CONFIG_MODULES ++/* ++ * In the case of modules, set the default probe timeout to ++ * 30 seconds to give userland some time to load needed modules ++ */ ++static int deferred_probe_timeout = 30; ++#else ++/* In the case of !modules, no probe timeout needed */ + static int deferred_probe_timeout = -1; ++#endif + static int __init deferred_probe_timeout_setup(char *str) + { + deferred_probe_timeout = simple_strtol(str, NULL, 10); +-- +2.35.1 + diff --git a/queue-4.19/ext4-correct-inconsistent-error-msg-in-nojournal-mod.patch b/queue-4.19/ext4-correct-inconsistent-error-msg-in-nojournal-mod.patch new file mode 100644 index 00000000000..272c52c0bc5 --- /dev/null +++ b/queue-4.19/ext4-correct-inconsistent-error-msg-in-nojournal-mod.patch @@ -0,0 +1,55 @@ +From c9e85056623690f9af667358882560a8056cbcf7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 9 Nov 2022 15:43:43 +0800 +Subject: ext4: correct inconsistent error msg in nojournal mode + +From: Baokun Li + +[ Upstream commit 89481b5fa8c0640e62ba84c6020cee895f7ac643 ] + +When we used the journal_async_commit mounting option in nojournal mode, +the kernel told me that "can't mount with journal_checksum", was very +confusing. I find that when we mount with journal_async_commit, both the +JOURNAL_ASYNC_COMMIT and EXPLICIT_JOURNAL_CHECKSUM flags are set. However, +in the error branch, CHECKSUM is checked before ASYNC_COMMIT. As a result, +the above inconsistency occurs, and the ASYNC_COMMIT branch becomes dead +code that cannot be executed. Therefore, we exchange the positions of the +two judgments to make the error msg more accurate. + +Signed-off-by: Baokun Li +Reviewed-by: Jan Kara +Link: https://lore.kernel.org/r/20221109074343.4184862-1-libaokun1@huawei.com +Signed-off-by: Theodore Ts'o +Cc: stable@kernel.org +Signed-off-by: Sasha Levin +--- + fs/ext4/super.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index 3198c276b434..e0d597719133 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -4305,14 +4305,15 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) + goto failed_mount3a; + } else { + /* Nojournal mode, all journal mount options are illegal */ +- if (test_opt2(sb, EXPLICIT_JOURNAL_CHECKSUM)) { ++ if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) { + ext4_msg(sb, KERN_ERR, "can't mount with " +- "journal_checksum, fs mounted w/o journal"); ++ "journal_async_commit, fs mounted w/o journal"); + goto failed_mount3a; + } +- if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) { ++ ++ if (test_opt2(sb, EXPLICIT_JOURNAL_CHECKSUM)) { + ext4_msg(sb, KERN_ERR, "can't mount with " +- "journal_async_commit, fs mounted w/o journal"); ++ "journal_checksum, fs mounted w/o journal"); + goto failed_mount3a; + } + if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) { +-- +2.35.1 + diff --git a/queue-4.19/ext4-fix-deadlock-due-to-mbcache-entry-corruption.patch b/queue-4.19/ext4-fix-deadlock-due-to-mbcache-entry-corruption.patch new file mode 100644 index 00000000000..9e26928a2a8 --- /dev/null +++ b/queue-4.19/ext4-fix-deadlock-due-to-mbcache-entry-corruption.patch @@ -0,0 +1,143 @@ +From 0440d482716e6e40af5ab20ce95600586caa82b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 23 Nov 2022 20:39:50 +0100 +Subject: ext4: fix deadlock due to mbcache entry corruption + +From: Jan Kara + +[ Upstream commit a44e84a9b7764c72896f7241a0ec9ac7e7ef38dd ] + +When manipulating xattr blocks, we can deadlock infinitely looping +inside ext4_xattr_block_set() where we constantly keep finding xattr +block for reuse in mbcache but we are unable to reuse it because its +reference count is too big. This happens because cache entry for the +xattr block is marked as reusable (e_reusable set) although its +reference count is too big. When this inconsistency happens, this +inconsistent state is kept indefinitely and so ext4_xattr_block_set() +keeps retrying indefinitely. + +The inconsistent state is caused by non-atomic update of e_reusable bit. +e_reusable is part of a bitfield and e_reusable update can race with +update of e_referenced bit in the same bitfield resulting in loss of one +of the updates. Fix the problem by using atomic bitops instead. + +This bug has been around for many years, but it became *much* easier +to hit after commit 65f8b80053a1 ("ext4: fix race when reusing xattr +blocks"). + +Cc: stable@vger.kernel.org +Fixes: 6048c64b2609 ("mbcache: add reusable flag to cache entries") +Fixes: 65f8b80053a1 ("ext4: fix race when reusing xattr blocks") +Reported-and-tested-by: Jeremi Piotrowski +Reported-by: Thilo Fromm +Link: https://lore.kernel.org/r/c77bf00f-4618-7149-56f1-b8d1664b9d07@linux.microsoft.com/ +Signed-off-by: Jan Kara +Reviewed-by: Andreas Dilger +Link: https://lore.kernel.org/r/20221123193950.16758-1-jack@suse.cz +Signed-off-by: Theodore Ts'o +Signed-off-by: Sasha Levin +--- + fs/ext4/xattr.c | 4 ++-- + fs/mbcache.c | 14 ++++++++------ + include/linux/mbcache.h | 9 +++++++-- + 3 files changed, 17 insertions(+), 10 deletions(-) + +diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c +index f759ab8c1a68..0772941bbe92 100644 +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -1297,7 +1297,7 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode, + ce = mb_cache_entry_get(ea_block_cache, hash, + bh->b_blocknr); + if (ce) { +- ce->e_reusable = 1; ++ set_bit(MBE_REUSABLE_B, &ce->e_flags); + mb_cache_entry_put(ea_block_cache, ce); + } + } +@@ -2058,7 +2058,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, + } + BHDR(new_bh)->h_refcount = cpu_to_le32(ref); + if (ref == EXT4_XATTR_REFCOUNT_MAX) +- ce->e_reusable = 0; ++ clear_bit(MBE_REUSABLE_B, &ce->e_flags); + ea_bdebug(new_bh, "reusing; refcount now=%d", + ref); + ext4_xattr_block_csum_set(inode, new_bh); +diff --git a/fs/mbcache.c b/fs/mbcache.c +index aa564e79891d..8e9e1888e448 100644 +--- a/fs/mbcache.c ++++ b/fs/mbcache.c +@@ -93,8 +93,9 @@ int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key, + atomic_set(&entry->e_refcnt, 1); + entry->e_key = key; + entry->e_value = value; +- entry->e_reusable = reusable; +- entry->e_referenced = 0; ++ entry->e_flags = 0; ++ if (reusable) ++ set_bit(MBE_REUSABLE_B, &entry->e_flags); + head = mb_cache_entry_head(cache, key); + hlist_bl_lock(head); + hlist_bl_for_each_entry(dup, dup_node, head, e_hash_list) { +@@ -161,7 +162,8 @@ static struct mb_cache_entry *__entry_find(struct mb_cache *cache, + while (node) { + entry = hlist_bl_entry(node, struct mb_cache_entry, + e_hash_list); +- if (entry->e_key == key && entry->e_reusable && ++ if (entry->e_key == key && ++ test_bit(MBE_REUSABLE_B, &entry->e_flags) && + atomic_inc_not_zero(&entry->e_refcnt)) + goto out; + node = node->next; +@@ -317,7 +319,7 @@ EXPORT_SYMBOL(mb_cache_entry_delete_or_get); + void mb_cache_entry_touch(struct mb_cache *cache, + struct mb_cache_entry *entry) + { +- entry->e_referenced = 1; ++ set_bit(MBE_REFERENCED_B, &entry->e_flags); + } + EXPORT_SYMBOL(mb_cache_entry_touch); + +@@ -342,9 +344,9 @@ static unsigned long mb_cache_shrink(struct mb_cache *cache, + entry = list_first_entry(&cache->c_list, + struct mb_cache_entry, e_list); + /* Drop initial hash reference if there is no user */ +- if (entry->e_referenced || ++ if (test_bit(MBE_REFERENCED_B, &entry->e_flags) || + atomic_cmpxchg(&entry->e_refcnt, 1, 0) != 1) { +- entry->e_referenced = 0; ++ clear_bit(MBE_REFERENCED_B, &entry->e_flags); + list_move_tail(&entry->e_list, &cache->c_list); + continue; + } +diff --git a/include/linux/mbcache.h b/include/linux/mbcache.h +index e9d5ece87794..591bc4cefe1d 100644 +--- a/include/linux/mbcache.h ++++ b/include/linux/mbcache.h +@@ -10,6 +10,12 @@ + + struct mb_cache; + ++/* Cache entry flags */ ++enum { ++ MBE_REFERENCED_B = 0, ++ MBE_REUSABLE_B ++}; ++ + struct mb_cache_entry { + /* List of entries in cache - protected by cache->c_list_lock */ + struct list_head e_list; +@@ -26,8 +32,7 @@ struct mb_cache_entry { + atomic_t e_refcnt; + /* Key in hash - stable during lifetime of the entry */ + u32 e_key; +- u32 e_referenced:1; +- u32 e_reusable:1; ++ unsigned long e_flags; + /* User provided value - stable during lifetime of the entry */ + u64 e_value; + }; +-- +2.35.1 + diff --git a/queue-4.19/ext4-fix-race-when-reusing-xattr-blocks.patch b/queue-4.19/ext4-fix-race-when-reusing-xattr-blocks.patch new file mode 100644 index 00000000000..ac18e9a19dd --- /dev/null +++ b/queue-4.19/ext4-fix-race-when-reusing-xattr-blocks.patch @@ -0,0 +1,180 @@ +From b45508d4ada679f38795f3dd0a16d07df565cbcd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 Jul 2022 12:54:24 +0200 +Subject: ext4: fix race when reusing xattr blocks + +From: Jan Kara + +[ Upstream commit 65f8b80053a1b2fd602daa6814e62d6fa90e5e9b ] + +When ext4_xattr_block_set() decides to remove xattr block the following +race can happen: + +CPU1 CPU2 +ext4_xattr_block_set() ext4_xattr_release_block() + new_bh = ext4_xattr_block_cache_find() + + lock_buffer(bh); + ref = le32_to_cpu(BHDR(bh)->h_refcount); + if (ref == 1) { + ... + mb_cache_entry_delete(); + unlock_buffer(bh); + ext4_free_blocks(); + ... + ext4_forget(..., bh, ...); + jbd2_journal_revoke(..., bh); + + ext4_journal_get_write_access(..., new_bh, ...) + do_get_write_access() + jbd2_journal_cancel_revoke(..., new_bh); + +Later the code in ext4_xattr_block_set() finds out the block got freed +and cancels reusal of the block but the revoke stays canceled and so in +case of block reuse and journal replay the filesystem can get corrupted. +If the race works out slightly differently, we can also hit assertions +in the jbd2 code. + +Fix the problem by making sure that once matching mbcache entry is +found, code dropping the last xattr block reference (or trying to modify +xattr block in place) waits until the mbcache entry reference is +dropped. This way code trying to reuse xattr block is protected from +someone trying to drop the last reference to xattr block. + +Reported-and-tested-by: Ritesh Harjani +CC: stable@vger.kernel.org +Fixes: 82939d7999df ("ext4: convert to mbcache2") +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/20220712105436.32204-5-jack@suse.cz +Signed-off-by: Theodore Ts'o +Stable-dep-of: a44e84a9b776 ("ext4: fix deadlock due to mbcache entry corruption") +Signed-off-by: Sasha Levin +--- + fs/ext4/xattr.c | 67 +++++++++++++++++++++++++++++++++---------------- + 1 file changed, 45 insertions(+), 22 deletions(-) + +diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c +index c23d7d68d7a1..f759ab8c1a68 100644 +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -437,9 +437,16 @@ static int ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino, + /* Remove entry from mbcache when EA inode is getting evicted */ + void ext4_evict_ea_inode(struct inode *inode) + { +- if (EA_INODE_CACHE(inode)) +- mb_cache_entry_delete(EA_INODE_CACHE(inode), +- ext4_xattr_inode_get_hash(inode), inode->i_ino); ++ struct mb_cache_entry *oe; ++ ++ if (!EA_INODE_CACHE(inode)) ++ return; ++ /* Wait for entry to get unused so that we can remove it */ ++ while ((oe = mb_cache_entry_delete_or_get(EA_INODE_CACHE(inode), ++ ext4_xattr_inode_get_hash(inode), inode->i_ino))) { ++ mb_cache_entry_wait_unused(oe); ++ mb_cache_entry_put(EA_INODE_CACHE(inode), oe); ++ } + } + + static int +@@ -1245,6 +1252,7 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode, + if (error) + goto out; + ++retry_ref: + lock_buffer(bh); + hash = le32_to_cpu(BHDR(bh)->h_hash); + ref = le32_to_cpu(BHDR(bh)->h_refcount); +@@ -1254,9 +1262,18 @@ ext4_xattr_release_block(handle_t *handle, struct inode *inode, + * This must happen under buffer lock for + * ext4_xattr_block_set() to reliably detect freed block + */ +- if (ea_block_cache) +- mb_cache_entry_delete(ea_block_cache, hash, +- bh->b_blocknr); ++ if (ea_block_cache) { ++ struct mb_cache_entry *oe; ++ ++ oe = mb_cache_entry_delete_or_get(ea_block_cache, hash, ++ bh->b_blocknr); ++ if (oe) { ++ unlock_buffer(bh); ++ mb_cache_entry_wait_unused(oe); ++ mb_cache_entry_put(ea_block_cache, oe); ++ goto retry_ref; ++ } ++ } + get_bh(bh); + unlock_buffer(bh); + +@@ -1883,9 +1900,20 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, + * ext4_xattr_block_set() to reliably detect modified + * block + */ +- if (ea_block_cache) +- mb_cache_entry_delete(ea_block_cache, hash, +- bs->bh->b_blocknr); ++ if (ea_block_cache) { ++ struct mb_cache_entry *oe; ++ ++ oe = mb_cache_entry_delete_or_get(ea_block_cache, ++ hash, bs->bh->b_blocknr); ++ if (oe) { ++ /* ++ * Xattr block is getting reused. Leave ++ * it alone. ++ */ ++ mb_cache_entry_put(ea_block_cache, oe); ++ goto clone_block; ++ } ++ } + ea_bdebug(bs->bh, "modifying in-place"); + error = ext4_xattr_set_entry(i, s, handle, inode, + true /* is_block */); +@@ -1901,6 +1929,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, + goto cleanup; + goto inserted; + } ++clone_block: + unlock_buffer(bs->bh); + ea_bdebug(bs->bh, "cloning"); + s->base = kmemdup(BHDR(bs->bh), bs->bh->b_size, GFP_NOFS); +@@ -2006,18 +2035,13 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, + lock_buffer(new_bh); + /* + * We have to be careful about races with +- * freeing, rehashing or adding references to +- * xattr block. Once we hold buffer lock xattr +- * block's state is stable so we can check +- * whether the block got freed / rehashed or +- * not. Since we unhash mbcache entry under +- * buffer lock when freeing / rehashing xattr +- * block, checking whether entry is still +- * hashed is reliable. Same rules hold for +- * e_reusable handling. ++ * adding references to xattr block. Once we ++ * hold buffer lock xattr block's state is ++ * stable so we can check the additional ++ * reference fits. + */ +- if (hlist_bl_unhashed(&ce->e_hash_list) || +- !ce->e_reusable) { ++ ref = le32_to_cpu(BHDR(new_bh)->h_refcount) + 1; ++ if (ref > EXT4_XATTR_REFCOUNT_MAX) { + /* + * Undo everything and check mbcache + * again. +@@ -2032,9 +2056,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, + new_bh = NULL; + goto inserted; + } +- ref = le32_to_cpu(BHDR(new_bh)->h_refcount) + 1; + BHDR(new_bh)->h_refcount = cpu_to_le32(ref); +- if (ref >= EXT4_XATTR_REFCOUNT_MAX) ++ if (ref == EXT4_XATTR_REFCOUNT_MAX) + ce->e_reusable = 0; + ea_bdebug(new_bh, "reusing; refcount now=%d", + ref); +-- +2.35.1 + diff --git a/queue-4.19/ext4-goto-right-label-failed_mount3a.patch b/queue-4.19/ext4-goto-right-label-failed_mount3a.patch new file mode 100644 index 00000000000..7e06a5d9da4 --- /dev/null +++ b/queue-4.19/ext4-goto-right-label-failed_mount3a.patch @@ -0,0 +1,69 @@ +From bef45f166bc13af29c9626bab997e80295f2c475 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Sep 2022 22:15:12 +0800 +Subject: ext4: goto right label 'failed_mount3a' + +From: Jason Yan + +[ Upstream commit 43bd6f1b49b61f43de4d4e33661b8dbe8c911f14 ] + +Before these two branches neither loaded the journal nor created the +xattr cache. So the right label to goto is 'failed_mount3a'. Although +this did not cause any issues because the error handler validated if the +pointer is null. However this still made me confused when reading +the code. So it's still worth to modify to goto the right label. + +Signed-off-by: Jason Yan +Reviewed-by: Jan Kara +Reviewed-by: Ritesh Harjani (IBM) +Link: https://lore.kernel.org/r/20220916141527.1012715-2-yanaijie@huawei.com +Signed-off-by: Theodore Ts'o +Stable-dep-of: 89481b5fa8c0 ("ext4: correct inconsistent error msg in nojournal mode") +Signed-off-by: Sasha Levin +--- + fs/ext4/super.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index 796588dc531b..3198c276b434 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -4302,30 +4302,30 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) + ext4_has_feature_journal_needs_recovery(sb)) { + ext4_msg(sb, KERN_ERR, "required journal recovery " + "suppressed and not mounted read-only"); +- goto failed_mount_wq; ++ goto failed_mount3a; + } else { + /* Nojournal mode, all journal mount options are illegal */ + if (test_opt2(sb, EXPLICIT_JOURNAL_CHECKSUM)) { + ext4_msg(sb, KERN_ERR, "can't mount with " + "journal_checksum, fs mounted w/o journal"); +- goto failed_mount_wq; ++ goto failed_mount3a; + } + if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) { + ext4_msg(sb, KERN_ERR, "can't mount with " + "journal_async_commit, fs mounted w/o journal"); +- goto failed_mount_wq; ++ goto failed_mount3a; + } + if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) { + ext4_msg(sb, KERN_ERR, "can't mount with " + "commit=%lu, fs mounted w/o journal", + sbi->s_commit_interval / HZ); +- goto failed_mount_wq; ++ goto failed_mount3a; + } + if (EXT4_MOUNT_DATA_FLAGS & + (sbi->s_mount_opt ^ sbi->s_def_mount_opt)) { + ext4_msg(sb, KERN_ERR, "can't mount with " + "data=, fs mounted w/o journal"); +- goto failed_mount_wq; ++ goto failed_mount3a; + } + sbi->s_def_mount_opt &= ~EXT4_MOUNT_JOURNAL_CHECKSUM; + clear_opt(sb, JOURNAL_CHECKSUM); +-- +2.35.1 + diff --git a/queue-4.19/ext4-remove-ea-inode-entry-from-mbcache-on-inode-evi.patch b/queue-4.19/ext4-remove-ea-inode-entry-from-mbcache-on-inode-evi.patch new file mode 100644 index 00000000000..3b28d2a08bb --- /dev/null +++ b/queue-4.19/ext4-remove-ea-inode-entry-from-mbcache-on-inode-evi.patch @@ -0,0 +1,117 @@ +From 6dc5dfb9380c5b00d83acbb68b31c2dab15184bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 Jul 2022 12:54:22 +0200 +Subject: ext4: remove EA inode entry from mbcache on inode eviction + +From: Jan Kara + +[ Upstream commit 6bc0d63dad7f9f54d381925ee855b402f652fa39 ] + +Currently we remove EA inode from mbcache as soon as its xattr refcount +drops to zero. However there can be pending attempts to reuse the inode +and thus refcount handling code has to handle the situation when +refcount increases from zero anyway. So save some work and just keep EA +inode in mbcache until it is getting evicted. At that moment we are sure +following iget() of EA inode will fail anyway (or wait for eviction to +finish and load things from the disk again) and so removing mbcache +entry at that moment is fine and simplifies the code a bit. + +CC: stable@vger.kernel.org +Fixes: 82939d7999df ("ext4: convert to mbcache2") +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/20220712105436.32204-3-jack@suse.cz +Signed-off-by: Theodore Ts'o +Stable-dep-of: a44e84a9b776 ("ext4: fix deadlock due to mbcache entry corruption") +Signed-off-by: Sasha Levin +--- + fs/ext4/inode.c | 2 ++ + fs/ext4/xattr.c | 24 ++++++++---------------- + fs/ext4/xattr.h | 1 + + 3 files changed, 11 insertions(+), 16 deletions(-) + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 2ad0a9540481..b322658ceff1 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -207,6 +207,8 @@ void ext4_evict_inode(struct inode *inode) + + trace_ext4_evict_inode(inode); + ++ if (EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL) ++ ext4_evict_ea_inode(inode); + if (inode->i_nlink) { + /* + * When journalling data dirty buffers are tracked only in the +diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c +index 959fc3328c3a..648368b02c79 100644 +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -434,6 +434,14 @@ static int ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino, + return err; + } + ++/* Remove entry from mbcache when EA inode is getting evicted */ ++void ext4_evict_ea_inode(struct inode *inode) ++{ ++ if (EA_INODE_CACHE(inode)) ++ mb_cache_entry_delete(EA_INODE_CACHE(inode), ++ ext4_xattr_inode_get_hash(inode), inode->i_ino); ++} ++ + static int + ext4_xattr_inode_verify_hashes(struct inode *ea_inode, + struct ext4_xattr_entry *entry, void *buffer, +@@ -1019,10 +1027,8 @@ static int ext4_xattr_ensure_credits(handle_t *handle, struct inode *inode, + static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode, + int ref_change) + { +- struct mb_cache *ea_inode_cache = EA_INODE_CACHE(ea_inode); + struct ext4_iloc iloc; + s64 ref_count; +- u32 hash; + int ret; + + inode_lock(ea_inode); +@@ -1047,14 +1053,6 @@ static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode, + + set_nlink(ea_inode, 1); + ext4_orphan_del(handle, ea_inode); +- +- if (ea_inode_cache) { +- hash = ext4_xattr_inode_get_hash(ea_inode); +- mb_cache_entry_create(ea_inode_cache, +- GFP_NOFS, hash, +- ea_inode->i_ino, +- true /* reusable */); +- } + } + } else { + WARN_ONCE(ref_count < 0, "EA inode %lu ref_count=%lld", +@@ -1067,12 +1065,6 @@ static int ext4_xattr_inode_update_ref(handle_t *handle, struct inode *ea_inode, + + clear_nlink(ea_inode); + ext4_orphan_add(handle, ea_inode); +- +- if (ea_inode_cache) { +- hash = ext4_xattr_inode_get_hash(ea_inode); +- mb_cache_entry_delete(ea_inode_cache, hash, +- ea_inode->i_ino); +- } + } + } + +diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h +index 990084e00374..231ef308d10c 100644 +--- a/fs/ext4/xattr.h ++++ b/fs/ext4/xattr.h +@@ -190,6 +190,7 @@ extern void ext4_xattr_inode_array_free(struct ext4_xattr_inode_array *array); + + extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, + struct ext4_inode *raw_inode, handle_t *handle); ++extern void ext4_evict_ea_inode(struct inode *inode); + + extern const struct xattr_handler *ext4_xattr_handlers[]; + +-- +2.35.1 + diff --git a/queue-4.19/ext4-unindent-codeblock-in-ext4_xattr_block_set.patch b/queue-4.19/ext4-unindent-codeblock-in-ext4_xattr_block_set.patch new file mode 100644 index 00000000000..96bdab953fc --- /dev/null +++ b/queue-4.19/ext4-unindent-codeblock-in-ext4_xattr_block_set.patch @@ -0,0 +1,126 @@ +From fca1e436800300c4d9b959ba41635593db5fd689 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 Jul 2022 12:54:23 +0200 +Subject: ext4: unindent codeblock in ext4_xattr_block_set() + +From: Jan Kara + +[ Upstream commit fd48e9acdf26d0cbd80051de07d4a735d05d29b2 ] + +Remove unnecessary else (and thus indentation level) from a code block +in ext4_xattr_block_set(). It will also make following code changes +easier. No functional changes. + +CC: stable@vger.kernel.org +Fixes: 82939d7999df ("ext4: convert to mbcache2") +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/20220712105436.32204-4-jack@suse.cz +Signed-off-by: Theodore Ts'o +Stable-dep-of: a44e84a9b776 ("ext4: fix deadlock due to mbcache entry corruption") +Signed-off-by: Sasha Levin +--- + fs/ext4/xattr.c | 77 ++++++++++++++++++++++++------------------------- + 1 file changed, 38 insertions(+), 39 deletions(-) + +diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c +index 648368b02c79..c23d7d68d7a1 100644 +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -1867,6 +1867,8 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, + #define header(x) ((struct ext4_xattr_header *)(x)) + + if (s->base) { ++ int offset = (char *)s->here - bs->bh->b_data; ++ + BUFFER_TRACE(bs->bh, "get_write_access"); + error = ext4_journal_get_write_access(handle, bs->bh); + if (error) +@@ -1898,49 +1900,46 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, + if (error) + goto cleanup; + goto inserted; +- } else { +- int offset = (char *)s->here - bs->bh->b_data; ++ } ++ unlock_buffer(bs->bh); ++ ea_bdebug(bs->bh, "cloning"); ++ s->base = kmemdup(BHDR(bs->bh), bs->bh->b_size, GFP_NOFS); ++ error = -ENOMEM; ++ if (s->base == NULL) ++ goto cleanup; ++ s->first = ENTRY(header(s->base)+1); ++ header(s->base)->h_refcount = cpu_to_le32(1); ++ s->here = ENTRY(s->base + offset); ++ s->end = s->base + bs->bh->b_size; + +- unlock_buffer(bs->bh); +- ea_bdebug(bs->bh, "cloning"); +- s->base = kmemdup(BHDR(bs->bh), bs->bh->b_size, GFP_NOFS); +- error = -ENOMEM; +- if (s->base == NULL) ++ /* ++ * If existing entry points to an xattr inode, we need ++ * to prevent ext4_xattr_set_entry() from decrementing ++ * ref count on it because the reference belongs to the ++ * original block. In this case, make the entry look ++ * like it has an empty value. ++ */ ++ if (!s->not_found && s->here->e_value_inum) { ++ ea_ino = le32_to_cpu(s->here->e_value_inum); ++ error = ext4_xattr_inode_iget(inode, ea_ino, ++ le32_to_cpu(s->here->e_hash), ++ &tmp_inode); ++ if (error) + goto cleanup; +- s->first = ENTRY(header(s->base)+1); +- header(s->base)->h_refcount = cpu_to_le32(1); +- s->here = ENTRY(s->base + offset); +- s->end = s->base + bs->bh->b_size; + +- /* +- * If existing entry points to an xattr inode, we need +- * to prevent ext4_xattr_set_entry() from decrementing +- * ref count on it because the reference belongs to the +- * original block. In this case, make the entry look +- * like it has an empty value. +- */ +- if (!s->not_found && s->here->e_value_inum) { +- ea_ino = le32_to_cpu(s->here->e_value_inum); +- error = ext4_xattr_inode_iget(inode, ea_ino, +- le32_to_cpu(s->here->e_hash), +- &tmp_inode); +- if (error) +- goto cleanup; +- +- if (!ext4_test_inode_state(tmp_inode, +- EXT4_STATE_LUSTRE_EA_INODE)) { +- /* +- * Defer quota free call for previous +- * inode until success is guaranteed. +- */ +- old_ea_inode_quota = le32_to_cpu( +- s->here->e_value_size); +- } +- iput(tmp_inode); +- +- s->here->e_value_inum = 0; +- s->here->e_value_size = 0; ++ if (!ext4_test_inode_state(tmp_inode, ++ EXT4_STATE_LUSTRE_EA_INODE)) { ++ /* ++ * Defer quota free call for previous ++ * inode until success is guaranteed. ++ */ ++ old_ea_inode_quota = le32_to_cpu( ++ s->here->e_value_size); + } ++ iput(tmp_inode); ++ ++ s->here->e_value_inum = 0; ++ s->here->e_value_size = 0; + } + } else { + /* Allocate a buffer where we construct the new block. */ +-- +2.35.1 + diff --git a/queue-4.19/ext4-use-kmemdup-to-replace-kmalloc-memcpy.patch b/queue-4.19/ext4-use-kmemdup-to-replace-kmalloc-memcpy.patch new file mode 100644 index 00000000000..2383ff00b22 --- /dev/null +++ b/queue-4.19/ext4-use-kmemdup-to-replace-kmalloc-memcpy.patch @@ -0,0 +1,41 @@ +From 9cac30ee5a4959e6ae031feaae25067c8d24b31a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 May 2022 11:01:20 +0800 +Subject: ext4: use kmemdup() to replace kmalloc + memcpy + +From: Shuqi Zhang + +[ Upstream commit 4efd9f0d120c55b08852ee5605dbb02a77089a5d ] + +Replace kmalloc + memcpy with kmemdup() + +Signed-off-by: Shuqi Zhang +Reviewed-by: Ritesh Harjani +Link: https://lore.kernel.org/r/20220525030120.803330-1-zhangshuqi3@huawei.com +Signed-off-by: Theodore Ts'o +Stable-dep-of: a44e84a9b776 ("ext4: fix deadlock due to mbcache entry corruption") +Signed-off-by: Sasha Levin +--- + fs/ext4/xattr.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c +index 7195a7ff65a6..959fc3328c3a 100644 +--- a/fs/ext4/xattr.c ++++ b/fs/ext4/xattr.c +@@ -1911,11 +1911,10 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, + + unlock_buffer(bs->bh); + ea_bdebug(bs->bh, "cloning"); +- s->base = kmalloc(bs->bh->b_size, GFP_NOFS); ++ s->base = kmemdup(BHDR(bs->bh), bs->bh->b_size, GFP_NOFS); + error = -ENOMEM; + if (s->base == NULL) + goto cleanup; +- memcpy(s->base, BHDR(bs->bh), bs->bh->b_size); + s->first = ENTRY(header(s->base)+1); + header(s->base)->h_refcount = cpu_to_le32(1); + s->here = ENTRY(s->base + offset); +-- +2.35.1 + diff --git a/queue-4.19/mbcache-add-functions-to-delete-entry-if-unused.patch b/queue-4.19/mbcache-add-functions-to-delete-entry-if-unused.patch new file mode 100644 index 00000000000..a407b96d7ea --- /dev/null +++ b/queue-4.19/mbcache-add-functions-to-delete-entry-if-unused.patch @@ -0,0 +1,156 @@ +From 5597b9d1616c53e0617c3a9b97b933096ab162ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 Jul 2022 12:54:21 +0200 +Subject: mbcache: add functions to delete entry if unused + +From: Jan Kara + +[ Upstream commit 3dc96bba65f53daa217f0a8f43edad145286a8f5 ] + +Add function mb_cache_entry_delete_or_get() to delete mbcache entry if +it is unused and also add a function to wait for entry to become unused +- mb_cache_entry_wait_unused(). We do not share code between the two +deleting function as one of them will go away soon. + +CC: stable@vger.kernel.org +Fixes: 82939d7999df ("ext4: convert to mbcache2") +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/20220712105436.32204-2-jack@suse.cz +Signed-off-by: Theodore Ts'o +Stable-dep-of: a44e84a9b776 ("ext4: fix deadlock due to mbcache entry corruption") +Signed-off-by: Sasha Levin +--- + fs/mbcache.c | 66 +++++++++++++++++++++++++++++++++++++++-- + include/linux/mbcache.h | 10 ++++++- + 2 files changed, 73 insertions(+), 3 deletions(-) + +diff --git a/fs/mbcache.c b/fs/mbcache.c +index 12203e5a91e7..c76030e20d92 100644 +--- a/fs/mbcache.c ++++ b/fs/mbcache.c +@@ -10,7 +10,7 @@ + /* + * Mbcache is a simple key-value store. Keys need not be unique, however + * key-value pairs are expected to be unique (we use this fact in +- * mb_cache_entry_delete()). ++ * mb_cache_entry_delete_or_get()). + * + * Ext2 and ext4 use this cache for deduplication of extended attribute blocks. + * Ext4 also uses it for deduplication of xattr values stored in inodes. +@@ -124,6 +124,19 @@ void __mb_cache_entry_free(struct mb_cache_entry *entry) + } + EXPORT_SYMBOL(__mb_cache_entry_free); + ++/* ++ * mb_cache_entry_wait_unused - wait to be the last user of the entry ++ * ++ * @entry - entry to work on ++ * ++ * Wait to be the last user of the entry. ++ */ ++void mb_cache_entry_wait_unused(struct mb_cache_entry *entry) ++{ ++ wait_var_event(&entry->e_refcnt, atomic_read(&entry->e_refcnt) <= 3); ++} ++EXPORT_SYMBOL(mb_cache_entry_wait_unused); ++ + static struct mb_cache_entry *__entry_find(struct mb_cache *cache, + struct mb_cache_entry *entry, + u32 key) +@@ -216,7 +229,7 @@ struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *cache, u32 key, + } + EXPORT_SYMBOL(mb_cache_entry_get); + +-/* mb_cache_entry_delete - remove a cache entry ++/* mb_cache_entry_delete - try to remove a cache entry + * @cache - cache we work with + * @key - key + * @value - value +@@ -253,6 +266,55 @@ void mb_cache_entry_delete(struct mb_cache *cache, u32 key, u64 value) + } + EXPORT_SYMBOL(mb_cache_entry_delete); + ++/* mb_cache_entry_delete_or_get - remove a cache entry if it has no users ++ * @cache - cache we work with ++ * @key - key ++ * @value - value ++ * ++ * Remove entry from cache @cache with key @key and value @value. The removal ++ * happens only if the entry is unused. The function returns NULL in case the ++ * entry was successfully removed or there's no entry in cache. Otherwise the ++ * function grabs reference of the entry that we failed to delete because it ++ * still has users and return it. ++ */ ++struct mb_cache_entry *mb_cache_entry_delete_or_get(struct mb_cache *cache, ++ u32 key, u64 value) ++{ ++ struct hlist_bl_node *node; ++ struct hlist_bl_head *head; ++ struct mb_cache_entry *entry; ++ ++ head = mb_cache_entry_head(cache, key); ++ hlist_bl_lock(head); ++ hlist_bl_for_each_entry(entry, node, head, e_hash_list) { ++ if (entry->e_key == key && entry->e_value == value) { ++ if (atomic_read(&entry->e_refcnt) > 2) { ++ atomic_inc(&entry->e_refcnt); ++ hlist_bl_unlock(head); ++ return entry; ++ } ++ /* We keep hash list reference to keep entry alive */ ++ hlist_bl_del_init(&entry->e_hash_list); ++ hlist_bl_unlock(head); ++ spin_lock(&cache->c_list_lock); ++ if (!list_empty(&entry->e_list)) { ++ list_del_init(&entry->e_list); ++ if (!WARN_ONCE(cache->c_entry_count == 0, ++ "mbcache: attempt to decrement c_entry_count past zero")) ++ cache->c_entry_count--; ++ atomic_dec(&entry->e_refcnt); ++ } ++ spin_unlock(&cache->c_list_lock); ++ mb_cache_entry_put(cache, entry); ++ return NULL; ++ } ++ } ++ hlist_bl_unlock(head); ++ ++ return NULL; ++} ++EXPORT_SYMBOL(mb_cache_entry_delete_or_get); ++ + /* mb_cache_entry_touch - cache entry got used + * @cache - cache the entry belongs to + * @entry - entry that got used +diff --git a/include/linux/mbcache.h b/include/linux/mbcache.h +index 20f1e3ff6013..8eca7f25c432 100644 +--- a/include/linux/mbcache.h ++++ b/include/linux/mbcache.h +@@ -30,15 +30,23 @@ void mb_cache_destroy(struct mb_cache *cache); + int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key, + u64 value, bool reusable); + void __mb_cache_entry_free(struct mb_cache_entry *entry); ++void mb_cache_entry_wait_unused(struct mb_cache_entry *entry); + static inline int mb_cache_entry_put(struct mb_cache *cache, + struct mb_cache_entry *entry) + { +- if (!atomic_dec_and_test(&entry->e_refcnt)) ++ unsigned int cnt = atomic_dec_return(&entry->e_refcnt); ++ ++ if (cnt > 0) { ++ if (cnt <= 3) ++ wake_up_var(&entry->e_refcnt); + return 0; ++ } + __mb_cache_entry_free(entry); + return 1; + } + ++struct mb_cache_entry *mb_cache_entry_delete_or_get(struct mb_cache *cache, ++ u32 key, u64 value); + void mb_cache_entry_delete(struct mb_cache *cache, u32 key, u64 value); + struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *cache, u32 key, + u64 value); +-- +2.35.1 + diff --git a/queue-4.19/mbcache-automatically-delete-entries-from-cache-on-f.patch b/queue-4.19/mbcache-automatically-delete-entries-from-cache-on-f.patch new file mode 100644 index 00000000000..db90924eae0 --- /dev/null +++ b/queue-4.19/mbcache-automatically-delete-entries-from-cache-on-f.patch @@ -0,0 +1,274 @@ +From 76d07f5ac8d1bb41a0502fa01498cbc014404c74 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 Jul 2022 12:54:29 +0200 +Subject: mbcache: automatically delete entries from cache on freeing + +From: Jan Kara + +[ Upstream commit 307af6c879377c1c63e71cbdd978201f9c7ee8df ] + +Use the fact that entries with elevated refcount are not removed from +the hash and just move removal of the entry from the hash to the entry +freeing time. When doing this we also change the generic code to hold +one reference to the cache entry, not two of them, which makes code +somewhat more obvious. + +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/20220712105436.32204-10-jack@suse.cz +Signed-off-by: Theodore Ts'o +Stable-dep-of: a44e84a9b776 ("ext4: fix deadlock due to mbcache entry corruption") +Signed-off-by: Sasha Levin +--- + fs/mbcache.c | 108 +++++++++++++++------------------------- + include/linux/mbcache.h | 24 ++++++--- + 2 files changed, 55 insertions(+), 77 deletions(-) + +diff --git a/fs/mbcache.c b/fs/mbcache.c +index c76030e20d92..aa564e79891d 100644 +--- a/fs/mbcache.c ++++ b/fs/mbcache.c +@@ -89,7 +89,7 @@ int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key, + return -ENOMEM; + + INIT_LIST_HEAD(&entry->e_list); +- /* One ref for hash, one ref returned */ ++ /* Initial hash reference */ + atomic_set(&entry->e_refcnt, 1); + entry->e_key = key; + entry->e_value = value; +@@ -105,21 +105,28 @@ int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key, + } + } + hlist_bl_add_head(&entry->e_hash_list, head); +- hlist_bl_unlock(head); +- ++ /* ++ * Add entry to LRU list before it can be found by ++ * mb_cache_entry_delete() to avoid races ++ */ + spin_lock(&cache->c_list_lock); + list_add_tail(&entry->e_list, &cache->c_list); +- /* Grab ref for LRU list */ +- atomic_inc(&entry->e_refcnt); + cache->c_entry_count++; + spin_unlock(&cache->c_list_lock); ++ hlist_bl_unlock(head); + + return 0; + } + EXPORT_SYMBOL(mb_cache_entry_create); + +-void __mb_cache_entry_free(struct mb_cache_entry *entry) ++void __mb_cache_entry_free(struct mb_cache *cache, struct mb_cache_entry *entry) + { ++ struct hlist_bl_head *head; ++ ++ head = mb_cache_entry_head(cache, entry->e_key); ++ hlist_bl_lock(head); ++ hlist_bl_del(&entry->e_hash_list); ++ hlist_bl_unlock(head); + kmem_cache_free(mb_entry_cache, entry); + } + EXPORT_SYMBOL(__mb_cache_entry_free); +@@ -133,7 +140,7 @@ EXPORT_SYMBOL(__mb_cache_entry_free); + */ + void mb_cache_entry_wait_unused(struct mb_cache_entry *entry) + { +- wait_var_event(&entry->e_refcnt, atomic_read(&entry->e_refcnt) <= 3); ++ wait_var_event(&entry->e_refcnt, atomic_read(&entry->e_refcnt) <= 2); + } + EXPORT_SYMBOL(mb_cache_entry_wait_unused); + +@@ -154,10 +161,9 @@ static struct mb_cache_entry *__entry_find(struct mb_cache *cache, + while (node) { + entry = hlist_bl_entry(node, struct mb_cache_entry, + e_hash_list); +- if (entry->e_key == key && entry->e_reusable) { +- atomic_inc(&entry->e_refcnt); ++ if (entry->e_key == key && entry->e_reusable && ++ atomic_inc_not_zero(&entry->e_refcnt)) + goto out; +- } + node = node->next; + } + entry = NULL; +@@ -217,10 +223,9 @@ struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *cache, u32 key, + head = mb_cache_entry_head(cache, key); + hlist_bl_lock(head); + hlist_bl_for_each_entry(entry, node, head, e_hash_list) { +- if (entry->e_key == key && entry->e_value == value) { +- atomic_inc(&entry->e_refcnt); ++ if (entry->e_key == key && entry->e_value == value && ++ atomic_inc_not_zero(&entry->e_refcnt)) + goto out; +- } + } + entry = NULL; + out: +@@ -280,37 +285,25 @@ EXPORT_SYMBOL(mb_cache_entry_delete); + struct mb_cache_entry *mb_cache_entry_delete_or_get(struct mb_cache *cache, + u32 key, u64 value) + { +- struct hlist_bl_node *node; +- struct hlist_bl_head *head; + struct mb_cache_entry *entry; + +- head = mb_cache_entry_head(cache, key); +- hlist_bl_lock(head); +- hlist_bl_for_each_entry(entry, node, head, e_hash_list) { +- if (entry->e_key == key && entry->e_value == value) { +- if (atomic_read(&entry->e_refcnt) > 2) { +- atomic_inc(&entry->e_refcnt); +- hlist_bl_unlock(head); +- return entry; +- } +- /* We keep hash list reference to keep entry alive */ +- hlist_bl_del_init(&entry->e_hash_list); +- hlist_bl_unlock(head); +- spin_lock(&cache->c_list_lock); +- if (!list_empty(&entry->e_list)) { +- list_del_init(&entry->e_list); +- if (!WARN_ONCE(cache->c_entry_count == 0, +- "mbcache: attempt to decrement c_entry_count past zero")) +- cache->c_entry_count--; +- atomic_dec(&entry->e_refcnt); +- } +- spin_unlock(&cache->c_list_lock); +- mb_cache_entry_put(cache, entry); +- return NULL; +- } +- } +- hlist_bl_unlock(head); ++ entry = mb_cache_entry_get(cache, key, value); ++ if (!entry) ++ return NULL; + ++ /* ++ * Drop the ref we got from mb_cache_entry_get() and the initial hash ++ * ref if we are the last user ++ */ ++ if (atomic_cmpxchg(&entry->e_refcnt, 2, 0) != 2) ++ return entry; ++ ++ spin_lock(&cache->c_list_lock); ++ if (!list_empty(&entry->e_list)) ++ list_del_init(&entry->e_list); ++ cache->c_entry_count--; ++ spin_unlock(&cache->c_list_lock); ++ __mb_cache_entry_free(cache, entry); + return NULL; + } + EXPORT_SYMBOL(mb_cache_entry_delete_or_get); +@@ -342,42 +335,24 @@ static unsigned long mb_cache_shrink(struct mb_cache *cache, + unsigned long nr_to_scan) + { + struct mb_cache_entry *entry; +- struct hlist_bl_head *head; + unsigned long shrunk = 0; + + spin_lock(&cache->c_list_lock); + while (nr_to_scan-- && !list_empty(&cache->c_list)) { + entry = list_first_entry(&cache->c_list, + struct mb_cache_entry, e_list); +- if (entry->e_referenced || atomic_read(&entry->e_refcnt) > 2) { ++ /* Drop initial hash reference if there is no user */ ++ if (entry->e_referenced || ++ atomic_cmpxchg(&entry->e_refcnt, 1, 0) != 1) { + entry->e_referenced = 0; + list_move_tail(&entry->e_list, &cache->c_list); + continue; + } + list_del_init(&entry->e_list); + cache->c_entry_count--; +- /* +- * We keep LRU list reference so that entry doesn't go away +- * from under us. +- */ + spin_unlock(&cache->c_list_lock); +- head = mb_cache_entry_head(cache, entry->e_key); +- hlist_bl_lock(head); +- /* Now a reliable check if the entry didn't get used... */ +- if (atomic_read(&entry->e_refcnt) > 2) { +- hlist_bl_unlock(head); +- spin_lock(&cache->c_list_lock); +- list_add_tail(&entry->e_list, &cache->c_list); +- cache->c_entry_count++; +- continue; +- } +- if (!hlist_bl_unhashed(&entry->e_hash_list)) { +- hlist_bl_del_init(&entry->e_hash_list); +- atomic_dec(&entry->e_refcnt); +- } +- hlist_bl_unlock(head); +- if (mb_cache_entry_put(cache, entry)) +- shrunk++; ++ __mb_cache_entry_free(cache, entry); ++ shrunk++; + cond_resched(); + spin_lock(&cache->c_list_lock); + } +@@ -469,11 +444,6 @@ void mb_cache_destroy(struct mb_cache *cache) + * point. + */ + list_for_each_entry_safe(entry, next, &cache->c_list, e_list) { +- if (!hlist_bl_unhashed(&entry->e_hash_list)) { +- hlist_bl_del_init(&entry->e_hash_list); +- atomic_dec(&entry->e_refcnt); +- } else +- WARN_ON(1); + list_del(&entry->e_list); + WARN_ON(atomic_read(&entry->e_refcnt) != 1); + mb_cache_entry_put(cache, entry); +diff --git a/include/linux/mbcache.h b/include/linux/mbcache.h +index 8eca7f25c432..e9d5ece87794 100644 +--- a/include/linux/mbcache.h ++++ b/include/linux/mbcache.h +@@ -13,8 +13,16 @@ struct mb_cache; + struct mb_cache_entry { + /* List of entries in cache - protected by cache->c_list_lock */ + struct list_head e_list; +- /* Hash table list - protected by hash chain bitlock */ ++ /* ++ * Hash table list - protected by hash chain bitlock. The entry is ++ * guaranteed to be hashed while e_refcnt > 0. ++ */ + struct hlist_bl_node e_hash_list; ++ /* ++ * Entry refcount. Once it reaches zero, entry is unhashed and freed. ++ * While refcount > 0, the entry is guaranteed to stay in the hash and ++ * e.g. mb_cache_entry_try_delete() will fail. ++ */ + atomic_t e_refcnt; + /* Key in hash - stable during lifetime of the entry */ + u32 e_key; +@@ -29,20 +37,20 @@ void mb_cache_destroy(struct mb_cache *cache); + + int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key, + u64 value, bool reusable); +-void __mb_cache_entry_free(struct mb_cache_entry *entry); ++void __mb_cache_entry_free(struct mb_cache *cache, ++ struct mb_cache_entry *entry); + void mb_cache_entry_wait_unused(struct mb_cache_entry *entry); +-static inline int mb_cache_entry_put(struct mb_cache *cache, +- struct mb_cache_entry *entry) ++static inline void mb_cache_entry_put(struct mb_cache *cache, ++ struct mb_cache_entry *entry) + { + unsigned int cnt = atomic_dec_return(&entry->e_refcnt); + + if (cnt > 0) { +- if (cnt <= 3) ++ if (cnt <= 2) + wake_up_var(&entry->e_refcnt); +- return 0; ++ return; + } +- __mb_cache_entry_free(entry); +- return 1; ++ __mb_cache_entry_free(cache, entry); + } + + struct mb_cache_entry *mb_cache_entry_delete_or_get(struct mb_cache *cache, +-- +2.35.1 + diff --git a/queue-4.19/mbcache-don-t-reclaim-used-entries.patch b/queue-4.19/mbcache-don-t-reclaim-used-entries.patch new file mode 100644 index 00000000000..b645d8e5bdd --- /dev/null +++ b/queue-4.19/mbcache-don-t-reclaim-used-entries.patch @@ -0,0 +1,56 @@ +From 94987d5de838fa00998363f2252e9a577b32fea5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 Jul 2022 12:54:20 +0200 +Subject: mbcache: don't reclaim used entries + +From: Jan Kara + +[ Upstream commit 58318914186c157477b978b1739dfe2f1b9dc0fe ] + +Do not reclaim entries that are currently used by somebody from a +shrinker. Firstly, these entries are likely useful. Secondly, we will +need to keep such entries to protect pending increment of xattr block +refcount. + +CC: stable@vger.kernel.org +Fixes: 82939d7999df ("ext4: convert to mbcache2") +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/20220712105436.32204-1-jack@suse.cz +Signed-off-by: Theodore Ts'o +Stable-dep-of: a44e84a9b776 ("ext4: fix deadlock due to mbcache entry corruption") +Signed-off-by: Sasha Levin +--- + fs/mbcache.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/fs/mbcache.c b/fs/mbcache.c +index 081ccf0caee3..12203e5a91e7 100644 +--- a/fs/mbcache.c ++++ b/fs/mbcache.c +@@ -287,7 +287,7 @@ static unsigned long mb_cache_shrink(struct mb_cache *cache, + while (nr_to_scan-- && !list_empty(&cache->c_list)) { + entry = list_first_entry(&cache->c_list, + struct mb_cache_entry, e_list); +- if (entry->e_referenced) { ++ if (entry->e_referenced || atomic_read(&entry->e_refcnt) > 2) { + entry->e_referenced = 0; + list_move_tail(&entry->e_list, &cache->c_list); + continue; +@@ -301,6 +301,14 @@ static unsigned long mb_cache_shrink(struct mb_cache *cache, + spin_unlock(&cache->c_list_lock); + head = mb_cache_entry_head(cache, entry->e_key); + hlist_bl_lock(head); ++ /* Now a reliable check if the entry didn't get used... */ ++ if (atomic_read(&entry->e_refcnt) > 2) { ++ hlist_bl_unlock(head); ++ spin_lock(&cache->c_list_lock); ++ list_add_tail(&entry->e_list, &cache->c_list); ++ cache->c_entry_count++; ++ continue; ++ } + if (!hlist_bl_unhashed(&entry->e_hash_list)) { + hlist_bl_del_init(&entry->e_hash_list); + atomic_dec(&entry->e_refcnt); +-- +2.35.1 + diff --git a/queue-4.19/net-amd-xgbe-add-missed-tasklet_kill.patch b/queue-4.19/net-amd-xgbe-add-missed-tasklet_kill.patch new file mode 100644 index 00000000000..6ba099690ce --- /dev/null +++ b/queue-4.19/net-amd-xgbe-add-missed-tasklet_kill.patch @@ -0,0 +1,71 @@ +From 827f49139b1fb861793f6714567e645e3637fd2c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Dec 2022 16:14:47 +0800 +Subject: net: amd-xgbe: add missed tasklet_kill + +From: Jiguang Xiao + +[ Upstream commit d530ece70f16f912e1d1bfeea694246ab78b0a4b ] + +The driver does not call tasklet_kill in several places. +Add the calls to fix it. + +Fixes: 85b85c853401 ("amd-xgbe: Re-issue interrupt if interrupt status not cleared") +Signed-off-by: Jiguang Xiao +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/amd/xgbe/xgbe-drv.c | 3 +++ + drivers/net/ethernet/amd/xgbe/xgbe-i2c.c | 4 +++- + drivers/net/ethernet/amd/xgbe/xgbe-mdio.c | 4 +++- + 3 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +index 35659f0dbe74..c1fb1e62557c 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +@@ -1140,6 +1140,9 @@ static void xgbe_free_irqs(struct xgbe_prv_data *pdata) + + devm_free_irq(pdata->dev, pdata->dev_irq, pdata); + ++ tasklet_kill(&pdata->tasklet_dev); ++ tasklet_kill(&pdata->tasklet_ecc); ++ + if (pdata->vdata->ecc_support && (pdata->dev_irq != pdata->ecc_irq)) + devm_free_irq(pdata->dev, pdata->ecc_irq, pdata); + +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c b/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c +index 4d9062d35930..530043742a07 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-i2c.c +@@ -447,8 +447,10 @@ static void xgbe_i2c_stop(struct xgbe_prv_data *pdata) + xgbe_i2c_disable(pdata); + xgbe_i2c_clear_all_interrupts(pdata); + +- if (pdata->dev_irq != pdata->i2c_irq) ++ if (pdata->dev_irq != pdata->i2c_irq) { + devm_free_irq(pdata->dev, pdata->i2c_irq, pdata); ++ tasklet_kill(&pdata->tasklet_i2c); ++ } + } + + static int xgbe_i2c_start(struct xgbe_prv_data *pdata) +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +index 156a0bc8ab01..97167fc9bebe 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c +@@ -1390,8 +1390,10 @@ static void xgbe_phy_stop(struct xgbe_prv_data *pdata) + /* Disable auto-negotiation */ + xgbe_an_disable_all(pdata); + +- if (pdata->dev_irq != pdata->an_irq) ++ if (pdata->dev_irq != pdata->an_irq) { + devm_free_irq(pdata->dev, pdata->an_irq, pdata); ++ tasklet_kill(&pdata->tasklet_an); ++ } + + pdata->phy_if.phy_impl.stop(pdata); + +-- +2.35.1 + diff --git a/queue-4.19/net-phy-xgmiitorgmii-fix-refcount-leak-in-xgmiitorgm.patch b/queue-4.19/net-phy-xgmiitorgmii-fix-refcount-leak-in-xgmiitorgm.patch new file mode 100644 index 00000000000..e477e215fd4 --- /dev/null +++ b/queue-4.19/net-phy-xgmiitorgmii-fix-refcount-leak-in-xgmiitorgm.patch @@ -0,0 +1,35 @@ +From 00f32d127b01efd2b60110f5d0216e834cd96b2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Dec 2022 10:29:25 +0400 +Subject: net: phy: xgmiitorgmii: Fix refcount leak in xgmiitorgmii_probe + +From: Miaoqian Lin + +[ Upstream commit d039535850ee47079d59527e96be18d8e0daa84b ] + +of_phy_find_device() return device node with refcount incremented. +Call put_device() to relese it when not needed anymore. + +Fixes: ab4e6ee578e8 ("net: phy: xgmiitorgmii: Check phy_driver ready before accessing") +Signed-off-by: Miaoqian Lin +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/phy/xilinx_gmii2rgmii.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/phy/xilinx_gmii2rgmii.c b/drivers/net/phy/xilinx_gmii2rgmii.c +index bd6084e315de..f44dc80ed3e6 100644 +--- a/drivers/net/phy/xilinx_gmii2rgmii.c ++++ b/drivers/net/phy/xilinx_gmii2rgmii.c +@@ -91,6 +91,7 @@ static int xgmiitorgmii_probe(struct mdio_device *mdiodev) + + if (!priv->phy_dev->drv) { + dev_info(dev, "Attached phy not ready\n"); ++ put_device(&priv->phy_dev->mdio.dev); + return -EPROBE_DEFER; + } + +-- +2.35.1 + diff --git a/queue-4.19/net-sched-atm-dont-intepret-cls-results-when-asked-t.patch b/queue-4.19/net-sched-atm-dont-intepret-cls-results-when-asked-t.patch new file mode 100644 index 00000000000..03c6e77a797 --- /dev/null +++ b/queue-4.19/net-sched-atm-dont-intepret-cls-results-when-asked-t.patch @@ -0,0 +1,42 @@ +From c2b8bfafcd315259417594a5dd3279e469bc6682 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 1 Jan 2023 16:57:43 -0500 +Subject: net: sched: atm: dont intepret cls results when asked to drop + +From: Jamal Hadi Salim + +[ Upstream commit a2965c7be0522eaa18808684b7b82b248515511b ] + +If asked to drop a packet via TC_ACT_SHOT it is unsafe to assume +res.class contains a valid pointer +Fixes: b0188d4dbe5f ("[NET_SCHED]: sch_atm: Lindent") + +Signed-off-by: Jamal Hadi Salim +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/sched/sch_atm.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c +index 9a1bfa13a6cd..ff825f40ea04 100644 +--- a/net/sched/sch_atm.c ++++ b/net/sched/sch_atm.c +@@ -394,10 +394,13 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch, + result = tcf_classify(skb, fl, &res, true); + if (result < 0) + continue; ++ if (result == TC_ACT_SHOT) ++ goto done; ++ + flow = (struct atm_flow_data *)res.class; + if (!flow) + flow = lookup_flow(sch, res.classid); +- goto done; ++ goto drop; + } + } + flow = NULL; +-- +2.35.1 + diff --git a/queue-4.19/nfc-fix-potential-resource-leaks.patch b/queue-4.19/nfc-fix-potential-resource-leaks.patch new file mode 100644 index 00000000000..08415aa015b --- /dev/null +++ b/queue-4.19/nfc-fix-potential-resource-leaks.patch @@ -0,0 +1,127 @@ +From cb541bb566e5ed8fa73d2ecd272a93475d5715a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Dec 2022 11:37:18 +0400 +Subject: nfc: Fix potential resource leaks + +From: Miaoqian Lin + +[ Upstream commit df49908f3c52d211aea5e2a14a93bbe67a2cb3af ] + +nfc_get_device() take reference for the device, add missing +nfc_put_device() to release it when not need anymore. +Also fix the style warnning by use error EOPNOTSUPP instead of +ENOTSUPP. + +Fixes: 5ce3f32b5264 ("NFC: netlink: SE API implementation") +Fixes: 29e76924cf08 ("nfc: netlink: Add capability to reply to vendor_cmd with data") +Signed-off-by: Miaoqian Lin +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/nfc/netlink.c | 52 ++++++++++++++++++++++++++++++++++------------- + 1 file changed, 38 insertions(+), 14 deletions(-) + +diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c +index 39fb01ee9222..8953b03d5a52 100644 +--- a/net/nfc/netlink.c ++++ b/net/nfc/netlink.c +@@ -1515,6 +1515,7 @@ static int nfc_genl_se_io(struct sk_buff *skb, struct genl_info *info) + u32 dev_idx, se_idx; + u8 *apdu; + size_t apdu_len; ++ int rc; + + if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || + !info->attrs[NFC_ATTR_SE_INDEX] || +@@ -1528,25 +1529,37 @@ static int nfc_genl_se_io(struct sk_buff *skb, struct genl_info *info) + if (!dev) + return -ENODEV; + +- if (!dev->ops || !dev->ops->se_io) +- return -ENOTSUPP; ++ if (!dev->ops || !dev->ops->se_io) { ++ rc = -EOPNOTSUPP; ++ goto put_dev; ++ } + + apdu_len = nla_len(info->attrs[NFC_ATTR_SE_APDU]); +- if (apdu_len == 0) +- return -EINVAL; ++ if (apdu_len == 0) { ++ rc = -EINVAL; ++ goto put_dev; ++ } + + apdu = nla_data(info->attrs[NFC_ATTR_SE_APDU]); +- if (!apdu) +- return -EINVAL; ++ if (!apdu) { ++ rc = -EINVAL; ++ goto put_dev; ++ } + + ctx = kzalloc(sizeof(struct se_io_ctx), GFP_KERNEL); +- if (!ctx) +- return -ENOMEM; ++ if (!ctx) { ++ rc = -ENOMEM; ++ goto put_dev; ++ } + + ctx->dev_idx = dev_idx; + ctx->se_idx = se_idx; + +- return nfc_se_io(dev, se_idx, apdu, apdu_len, se_io_cb, ctx); ++ rc = nfc_se_io(dev, se_idx, apdu, apdu_len, se_io_cb, ctx); ++ ++put_dev: ++ nfc_put_device(dev); ++ return rc; + } + + static int nfc_genl_vendor_cmd(struct sk_buff *skb, +@@ -1569,14 +1582,21 @@ static int nfc_genl_vendor_cmd(struct sk_buff *skb, + subcmd = nla_get_u32(info->attrs[NFC_ATTR_VENDOR_SUBCMD]); + + dev = nfc_get_device(dev_idx); +- if (!dev || !dev->vendor_cmds || !dev->n_vendor_cmds) ++ if (!dev) + return -ENODEV; + ++ if (!dev->vendor_cmds || !dev->n_vendor_cmds) { ++ err = -ENODEV; ++ goto put_dev; ++ } ++ + if (info->attrs[NFC_ATTR_VENDOR_DATA]) { + data = nla_data(info->attrs[NFC_ATTR_VENDOR_DATA]); + data_len = nla_len(info->attrs[NFC_ATTR_VENDOR_DATA]); +- if (data_len == 0) +- return -EINVAL; ++ if (data_len == 0) { ++ err = -EINVAL; ++ goto put_dev; ++ } + } else { + data = NULL; + data_len = 0; +@@ -1591,10 +1611,14 @@ static int nfc_genl_vendor_cmd(struct sk_buff *skb, + dev->cur_cmd_info = info; + err = cmd->doit(dev, data, data_len); + dev->cur_cmd_info = NULL; +- return err; ++ goto put_dev; + } + +- return -EOPNOTSUPP; ++ err = -EOPNOTSUPP; ++ ++put_dev: ++ nfc_put_device(dev); ++ return err; + } + + /* message building helper */ +-- +2.35.1 + diff --git a/queue-4.19/perf-probe-fix-to-get-the-dw_at_decl_file-and-dw_at_.patch b/queue-4.19/perf-probe-fix-to-get-the-dw_at_decl_file-and-dw_at_.patch new file mode 100644 index 00000000000..f6b0c1c614e --- /dev/null +++ b/queue-4.19/perf-probe-fix-to-get-the-dw_at_decl_file-and-dw_at_.patch @@ -0,0 +1,92 @@ +From 84de40bf3602ddd00c4dc6f785b891adc087abb2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 5 Nov 2022 12:01:14 +0900 +Subject: perf probe: Fix to get the DW_AT_decl_file and DW_AT_call_file as + unsinged data + +From: Masami Hiramatsu (Google) + +[ Upstream commit a9dfc46c67b52ad43b8e335e28f4cf8002c67793 ] + +DWARF version 5 standard Sec 2.14 says that + + Any debugging information entry representing the declaration of an object, + module, subprogram or type may have DW_AT_decl_file, DW_AT_decl_line and + DW_AT_decl_column attributes, each of whose value is an unsigned integer + constant. + +So it should be an unsigned integer data. Also, even though the standard +doesn't clearly say the DW_AT_call_file is signed or unsigned, the +elfutils (eu-readelf) interprets it as unsigned integer data and it is +natural to handle it as unsigned integer data as same as DW_AT_decl_file. +This changes the DW_AT_call_file as unsigned integer data too. + +Fixes: 3f4460a28fb2f73d ("perf probe: Filter out redundant inline-instances") +Signed-off-by: Masami Hiramatsu +Acked-by: Namhyung Kim +Cc: Alexander Shishkin +Cc: Ingo Molnar +Cc: Jiri Olsa +Cc: Mark Rutland +Cc: Masami Hiramatsu +Cc: Peter Zijlstra +Cc: stable@vger.kernel.org +Cc: Steven Rostedt (VMware) +Link: https://lore.kernel.org/r/166761727445.480106.3738447577082071942.stgit@devnote3 +Signed-off-by: Arnaldo Carvalho de Melo +Signed-off-by: Sasha Levin +--- + tools/perf/util/dwarf-aux.c | 21 ++++----------------- + 1 file changed, 4 insertions(+), 17 deletions(-) + +diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c +index 3b7386527794..6de57d9ee7cc 100644 +--- a/tools/perf/util/dwarf-aux.c ++++ b/tools/perf/util/dwarf-aux.c +@@ -274,19 +274,6 @@ static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name, + return 0; + } + +-/* Get attribute and translate it as a sdata */ +-static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name, +- Dwarf_Sword *result) +-{ +- Dwarf_Attribute attr; +- +- if (dwarf_attr_integrate(tp_die, attr_name, &attr) == NULL || +- dwarf_formsdata(&attr, result) != 0) +- return -ENOENT; +- +- return 0; +-} +- + /** + * die_is_signed_type - Check whether a type DIE is signed or not + * @tp_die: a DIE of a type +@@ -410,9 +397,9 @@ int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs) + /* Get the call file index number in CU DIE */ + static int die_get_call_fileno(Dwarf_Die *in_die) + { +- Dwarf_Sword idx; ++ Dwarf_Word idx; + +- if (die_get_attr_sdata(in_die, DW_AT_call_file, &idx) == 0) ++ if (die_get_attr_udata(in_die, DW_AT_call_file, &idx) == 0) + return (int)idx; + else + return -ENOENT; +@@ -421,9 +408,9 @@ static int die_get_call_fileno(Dwarf_Die *in_die) + /* Get the declared file index number in CU DIE */ + static int die_get_decl_fileno(Dwarf_Die *pdie) + { +- Dwarf_Sword idx; ++ Dwarf_Word idx; + +- if (die_get_attr_sdata(pdie, DW_AT_decl_file, &idx) == 0) ++ if (die_get_attr_udata(pdie, DW_AT_decl_file, &idx) == 0) + return (int)idx; + else + return -ENOENT; +-- +2.35.1 + diff --git a/queue-4.19/perf-probe-use-dwarf_attr_integrate-as-generic-dwarf.patch b/queue-4.19/perf-probe-use-dwarf_attr_integrate-as-generic-dwarf.patch new file mode 100644 index 00000000000..f4afa67d8fe --- /dev/null +++ b/queue-4.19/perf-probe-use-dwarf_attr_integrate-as-generic-dwarf.patch @@ -0,0 +1,54 @@ +From f1950d4660bd829816ab733a9e364337a32b1cb1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 1 Nov 2022 22:48:39 +0900 +Subject: perf probe: Use dwarf_attr_integrate as generic DWARF attr accessor + +From: Masami Hiramatsu (Google) + +[ Upstream commit f828929ab7f0dc3353e4a617f94f297fa8f3dec3 ] + +Use dwarf_attr_integrate() instead of dwarf_attr() for generic attribute +acccessor functions, so that it can find the specified attribute from +abstact origin DIE etc. + +Signed-off-by: Masami Hiramatsu +Acked-by: Namhyung Kim +Cc: Alexander Shishkin +Cc: Ingo Molnar +Cc: Jiri Olsa +Cc: Mark Rutland +Cc: Peter Zijlstra +Cc: Steven Rostedt (VMware) +Link: https://lore.kernel.org/r/166731051988.2100653.13595339994343449770.stgit@devnote3 +Signed-off-by: Arnaldo Carvalho de Melo +Stable-dep-of: a9dfc46c67b5 ("perf probe: Fix to get the DW_AT_decl_file and DW_AT_call_file as unsinged data") +Signed-off-by: Sasha Levin +--- + tools/perf/util/dwarf-aux.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c +index 230e94bf7775..3b7386527794 100644 +--- a/tools/perf/util/dwarf-aux.c ++++ b/tools/perf/util/dwarf-aux.c +@@ -267,7 +267,7 @@ static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name, + { + Dwarf_Attribute attr; + +- if (dwarf_attr(tp_die, attr_name, &attr) == NULL || ++ if (dwarf_attr_integrate(tp_die, attr_name, &attr) == NULL || + dwarf_formudata(&attr, result) != 0) + return -ENOENT; + +@@ -280,7 +280,7 @@ static int die_get_attr_sdata(Dwarf_Die *tp_die, unsigned int attr_name, + { + Dwarf_Attribute attr; + +- if (dwarf_attr(tp_die, attr_name, &attr) == NULL || ++ if (dwarf_attr_integrate(tp_die, attr_name, &attr) == NULL || + dwarf_formsdata(&attr, result) != 0) + return -ENOENT; + +-- +2.35.1 + diff --git a/queue-4.19/qlcnic-prevent-dcb-use-after-free-on-qlcnic_dcb_enab.patch b/queue-4.19/qlcnic-prevent-dcb-use-after-free-on-qlcnic_dcb_enab.patch new file mode 100644 index 00000000000..59eac7acdee --- /dev/null +++ b/queue-4.19/qlcnic-prevent-dcb-use-after-free-on-qlcnic_dcb_enab.patch @@ -0,0 +1,103 @@ +From be10d9dbbec173d5e3d0a094a537c017061d9374 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Dec 2022 14:52:28 +0300 +Subject: qlcnic: prevent ->dcb use-after-free on qlcnic_dcb_enable() failure + +From: Daniil Tatianin + +[ Upstream commit 13a7c8964afcd8ca43c0b6001ebb0127baa95362 ] + +adapter->dcb would get silently freed inside qlcnic_dcb_enable() in +case qlcnic_dcb_attach() would return an error, which always happens +under OOM conditions. This would lead to use-after-free because both +of the existing callers invoke qlcnic_dcb_get_info() on the obtained +pointer, which is potentially freed at that point. + +Propagate errors from qlcnic_dcb_enable(), and instead free the dcb +pointer at callsite using qlcnic_dcb_free(). This also removes the now +unused qlcnic_clear_dcb_ops() helper, which was a simple wrapper around +kfree() also causing memory leaks for partially initialized dcb. + +Found by Linux Verification Center (linuxtesting.org) with the SVACE +static analysis tool. + +Fixes: 3c44bba1d270 ("qlcnic: Disable DCB operations from SR-IOV VFs") +Reviewed-by: Michal Swiatkowski +Signed-off-by: Daniil Tatianin +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 8 +++++++- + drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h | 10 ++-------- + drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 8 +++++++- + 3 files changed, 16 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +index 10286215092f..85419b8258b5 100644 +--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c ++++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +@@ -2525,7 +2525,13 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) + goto disable_mbx_intr; + + qlcnic_83xx_clear_function_resources(adapter); +- qlcnic_dcb_enable(adapter->dcb); ++ ++ err = qlcnic_dcb_enable(adapter->dcb); ++ if (err) { ++ qlcnic_dcb_free(adapter->dcb); ++ goto disable_mbx_intr; ++ } ++ + qlcnic_83xx_initialize_nic(adapter, 1); + qlcnic_dcb_get_info(adapter->dcb); + +diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h +index 0a9d24e86715..eb8000d9b6d0 100644 +--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h ++++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.h +@@ -42,11 +42,6 @@ struct qlcnic_dcb { + unsigned long state; + }; + +-static inline void qlcnic_clear_dcb_ops(struct qlcnic_dcb *dcb) +-{ +- kfree(dcb); +-} +- + static inline int qlcnic_dcb_get_hw_capability(struct qlcnic_dcb *dcb) + { + if (dcb && dcb->ops->get_hw_capability) +@@ -113,9 +108,8 @@ static inline void qlcnic_dcb_init_dcbnl_ops(struct qlcnic_dcb *dcb) + dcb->ops->init_dcbnl_ops(dcb); + } + +-static inline void qlcnic_dcb_enable(struct qlcnic_dcb *dcb) ++static inline int qlcnic_dcb_enable(struct qlcnic_dcb *dcb) + { +- if (dcb && qlcnic_dcb_attach(dcb)) +- qlcnic_clear_dcb_ops(dcb); ++ return dcb ? qlcnic_dcb_attach(dcb) : 0; + } + #endif +diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +index 43920374beae..a0c427f3b180 100644 +--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c ++++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +@@ -2638,7 +2638,13 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) + "Device does not support MSI interrupts\n"); + + if (qlcnic_82xx_check(adapter)) { +- qlcnic_dcb_enable(adapter->dcb); ++ err = qlcnic_dcb_enable(adapter->dcb); ++ if (err) { ++ qlcnic_dcb_free(adapter->dcb); ++ dev_err(&pdev->dev, "Failed to enable DCB\n"); ++ goto err_out_free_hw; ++ } ++ + qlcnic_dcb_get_info(adapter->dcb); + err = qlcnic_setup_intr(adapter); + +-- +2.35.1 + diff --git a/queue-4.19/ravb-fix-failed-to-switch-device-to-config-mode-mess.patch b/queue-4.19/ravb-fix-failed-to-switch-device-to-config-mode-mess.patch new file mode 100644 index 00000000000..72629b6286e --- /dev/null +++ b/queue-4.19/ravb-fix-failed-to-switch-device-to-config-mode-mess.patch @@ -0,0 +1,68 @@ +From 9472dc55baeed2163760a6baee606b91394cd0c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Dec 2022 10:51:18 +0000 +Subject: ravb: Fix "failed to switch device to config mode" message during + unbind + +From: Biju Das + +[ Upstream commit c72a7e42592b2e18d862cf120876070947000d7a ] + +This patch fixes the error "ravb 11c20000.ethernet eth0: failed to switch +device to config mode" during unbind. + +We are doing register access after pm_runtime_put_sync(). + +We usually do cleanup in reverse order of init. Currently in +remove(), the "pm_runtime_put_sync" is not in reverse order. + +Probe + reset_control_deassert(rstc); + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + +remove + pm_runtime_put_sync(&pdev->dev); + unregister_netdev(ndev); + .. + ravb_mdio_release(priv); + pm_runtime_disable(&pdev->dev); + +Consider the call to unregister_netdev() +unregister_netdev->unregister_netdevice_queue->rollback_registered_many +that calls the below functions which access the registers after +pm_runtime_put_sync() + 1) ravb_get_stats + 2) ravb_close + +Fixes: c156633f1353 ("Renesas Ethernet AVB driver proper") +Cc: stable@vger.kernel.org +Signed-off-by: Biju Das +Reviewed-by: Leon Romanovsky +Link: https://lore.kernel.org/r/20221214105118.2495313-1-biju.das.jz@bp.renesas.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/renesas/ravb_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c +index 9077014f6f40..ff374d0d80a7 100644 +--- a/drivers/net/ethernet/renesas/ravb_main.c ++++ b/drivers/net/ethernet/renesas/ravb_main.c +@@ -2199,11 +2199,11 @@ static int ravb_remove(struct platform_device *pdev) + priv->desc_bat_dma); + /* Set reset mode */ + ravb_write(ndev, CCC_OPC_RESET, CCC); +- pm_runtime_put_sync(&pdev->dev); + unregister_netdev(ndev); + netif_napi_del(&priv->napi[RAVB_NC]); + netif_napi_del(&priv->napi[RAVB_BE]); + ravb_mdio_release(priv); ++ pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + free_netdev(ndev); + platform_set_drvdata(pdev, NULL); +-- +2.35.1 + diff --git a/queue-4.19/rdma-mlx5-fix-validation-of-max_rd_atomic-caps-for-d.patch b/queue-4.19/rdma-mlx5-fix-validation-of-max_rd_atomic-caps-for-d.patch new file mode 100644 index 00000000000..32f73b13ced --- /dev/null +++ b/queue-4.19/rdma-mlx5-fix-validation-of-max_rd_atomic-caps-for-d.patch @@ -0,0 +1,95 @@ +From 7210d3e68b898423c7c81bba0a1191ab9099767c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Dec 2022 14:56:10 +0200 +Subject: RDMA/mlx5: Fix validation of max_rd_atomic caps for DC + +From: Maor Gottlieb + +[ Upstream commit 8de8482fe5732fbef4f5af82bc0c0362c804cd1f ] + +Currently, when modifying DC, we validate max_rd_atomic user attribute +against the RC cap, validate against DC. RC and DC QP types have different +device limitations. + +This can cause userspace created DC QPs to malfunction. + +Fixes: c32a4f296e1d ("IB/mlx5: Add support for DC Initiator QP") +Link: https://lore.kernel.org/r/0c5aee72cea188c3bb770f4207cce7abc9b6fc74.1672231736.git.leonro@nvidia.com +Signed-off-by: Maor Gottlieb +Signed-off-by: Leon Romanovsky +Signed-off-by: Sasha Levin +--- + drivers/infiniband/hw/mlx5/qp.c | 49 +++++++++++++++++++++++---------- + 1 file changed, 35 insertions(+), 14 deletions(-) + +diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c +index 361b1b859782..1520a3098f7d 100644 +--- a/drivers/infiniband/hw/mlx5/qp.c ++++ b/drivers/infiniband/hw/mlx5/qp.c +@@ -3411,6 +3411,40 @@ static int mlx5_ib_modify_dct(struct ib_qp *ibqp, struct ib_qp_attr *attr, + return err; + } + ++static int validate_rd_atomic(struct mlx5_ib_dev *dev, struct ib_qp_attr *attr, ++ int attr_mask, enum ib_qp_type qp_type) ++{ ++ int log_max_ra_res; ++ int log_max_ra_req; ++ ++ if (qp_type == MLX5_IB_QPT_DCI) { ++ log_max_ra_res = 1 << MLX5_CAP_GEN(dev->mdev, ++ log_max_ra_res_dc); ++ log_max_ra_req = 1 << MLX5_CAP_GEN(dev->mdev, ++ log_max_ra_req_dc); ++ } else { ++ log_max_ra_res = 1 << MLX5_CAP_GEN(dev->mdev, ++ log_max_ra_res_qp); ++ log_max_ra_req = 1 << MLX5_CAP_GEN(dev->mdev, ++ log_max_ra_req_qp); ++ } ++ ++ if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && ++ attr->max_rd_atomic > log_max_ra_res) { ++ mlx5_ib_dbg(dev, "invalid max_rd_atomic value %d\n", ++ attr->max_rd_atomic); ++ return false; ++ } ++ ++ if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && ++ attr->max_dest_rd_atomic > log_max_ra_req) { ++ mlx5_ib_dbg(dev, "invalid max_dest_rd_atomic value %d\n", ++ attr->max_dest_rd_atomic); ++ return false; ++ } ++ return true; ++} ++ + int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask, struct ib_udata *udata) + { +@@ -3508,21 +3542,8 @@ int mlx5_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + } + } + +- if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && +- attr->max_rd_atomic > +- (1 << MLX5_CAP_GEN(dev->mdev, log_max_ra_res_qp))) { +- mlx5_ib_dbg(dev, "invalid max_rd_atomic value %d\n", +- attr->max_rd_atomic); +- goto out; +- } +- +- if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && +- attr->max_dest_rd_atomic > +- (1 << MLX5_CAP_GEN(dev->mdev, log_max_ra_req_qp))) { +- mlx5_ib_dbg(dev, "invalid max_dest_rd_atomic value %d\n", +- attr->max_dest_rd_atomic); ++ if (!validate_rd_atomic(dev, attr, attr_mask, qp_type)) + goto out; +- } + + if (cur_state == new_state && cur_state == IB_QPS_RESET) { + err = 0; +-- +2.35.1 + diff --git a/queue-4.19/riscv-remove-unreachable-have_function_graph_ret_add.patch b/queue-4.19/riscv-remove-unreachable-have_function_graph_ret_add.patch new file mode 100644 index 00000000000..3c1944f4136 --- /dev/null +++ b/queue-4.19/riscv-remove-unreachable-have_function_graph_ret_add.patch @@ -0,0 +1,39 @@ +From 8bc6d6af4c47438cd8ac86927f6072797bed3786 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Apr 2019 11:14:39 +0200 +Subject: riscv: remove unreachable !HAVE_FUNCTION_GRAPH_RET_ADDR_PTR code + +From: Christoph Hellwig + +[ Upstream commit 877425424d6c853b804e6b6a6045a5b4ea97c510 ] + +HAVE_FUNCTION_GRAPH_RET_ADDR_PTR is always defined for RISC-V. + +Signed-off-by: Christoph Hellwig +Signed-off-by: Palmer Dabbelt +Stable-dep-of: 5c3022e4a616 ("riscv: stacktrace: Fixup ftrace_graph_ret_addr retp argument") +Signed-off-by: Sasha Levin +--- + arch/riscv/kernel/stacktrace.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c +index 74b2168d7298..39cd3cf9f06b 100644 +--- a/arch/riscv/kernel/stacktrace.c ++++ b/arch/riscv/kernel/stacktrace.c +@@ -64,12 +64,8 @@ static void notrace walk_stackframe(struct task_struct *task, + frame = (struct stackframe *)fp - 1; + sp = fp; + fp = frame->fp; +-#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR + pc = ftrace_graph_ret_addr(current, NULL, frame->ra, + (unsigned long *)(fp - 8)); +-#else +- pc = frame->ra - 0x4; +-#endif + } + } + +-- +2.35.1 + diff --git a/queue-4.19/riscv-stacktrace-fix-stack-output-without-ra-on-the-.patch b/queue-4.19/riscv-stacktrace-fix-stack-output-without-ra-on-the-.patch new file mode 100644 index 00000000000..20041f65562 --- /dev/null +++ b/queue-4.19/riscv-stacktrace-fix-stack-output-without-ra-on-the-.patch @@ -0,0 +1,72 @@ +From 25e0560ab7e86c2b9ddd753f22b26fdb0f928ccf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 Jan 2021 20:40:14 +0800 +Subject: riscv/stacktrace: Fix stack output without ra on the stack top + +From: Chen Huang + +[ Upstream commit f766f77a74f5784d8d4d3c36b1900731f97d08d0 ] + +When a function doesn't have a callee, then it will not +push ra into the stack, such as lkdtm_BUG() function, + +addi sp,sp,-16 +sd s0,8(sp) +addi s0,sp,16 +ebreak + +The struct stackframe use {fp,ra} to get information from +stack, if walk_stackframe() with pr_regs, we will obtain +wrong value and bad stacktrace, + +[] lkdtm_BUG+0x6/0x8 +---[ end trace 18da3fbdf08e25d5 ]--- + +Correct the next fp and pc, after that, full stacktrace +shown as expects, + +[] lkdtm_BUG+0x6/0x8 +[] lkdtm_do_action+0x14/0x1c +[] direct_entry+0xc0/0x10a +[] full_proxy_write+0x42/0x6a +[] vfs_write+0x7e/0x214 +[] ksys_write+0x98/0xc0 +[] sys_write+0xe/0x16 +[] ret_from_syscall+0x0/0x2 +---[ end trace 61917f3d9a9fadcd ]--- + +Signed-off-by: Chen Huang +Signed-off-by: Kefeng Wang +Signed-off-by: Palmer Dabbelt +Stable-dep-of: 5c3022e4a616 ("riscv: stacktrace: Fixup ftrace_graph_ret_addr retp argument") +Signed-off-by: Sasha Levin +--- + arch/riscv/kernel/stacktrace.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c +index 39cd3cf9f06b..3d1e184e39e9 100644 +--- a/arch/riscv/kernel/stacktrace.c ++++ b/arch/riscv/kernel/stacktrace.c +@@ -63,9 +63,15 @@ static void notrace walk_stackframe(struct task_struct *task, + /* Unwind stack frame */ + frame = (struct stackframe *)fp - 1; + sp = fp; +- fp = frame->fp; +- pc = ftrace_graph_ret_addr(current, NULL, frame->ra, +- (unsigned long *)(fp - 8)); ++ if (regs && (regs->epc == pc) && (frame->fp & 0x7)) { ++ fp = frame->ra; ++ pc = regs->ra; ++ } else { ++ fp = frame->fp; ++ pc = ftrace_graph_ret_addr(current, NULL, frame->ra, ++ (unsigned long *)(fp - 8)); ++ } ++ + } + } + +-- +2.35.1 + diff --git a/queue-4.19/riscv-stacktrace-fixup-ftrace_graph_ret_addr-retp-ar.patch b/queue-4.19/riscv-stacktrace-fixup-ftrace_graph_ret_addr-retp-ar.patch new file mode 100644 index 00000000000..12152b1dc47 --- /dev/null +++ b/queue-4.19/riscv-stacktrace-fixup-ftrace_graph_ret_addr-retp-ar.patch @@ -0,0 +1,41 @@ +From 72dea6c020220e8f4916d698293730b8f3dc8b27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 9 Nov 2022 01:49:36 -0500 +Subject: riscv: stacktrace: Fixup ftrace_graph_ret_addr retp argument + +From: Guo Ren + +[ Upstream commit 5c3022e4a616d800cf5f4c3a981d7992179e44a1 ] + +The 'retp' is a pointer to the return address on the stack, so we +must pass the current return address pointer as the 'retp' +argument to ftrace_push_return_trace(). Not parent function's +return address on the stack. + +Fixes: b785ec129bd9 ("riscv/ftrace: Add HAVE_FUNCTION_GRAPH_RET_ADDR_PTR support") +Signed-off-by: Guo Ren +Signed-off-by: Guo Ren +Link: https://lore.kernel.org/r/20221109064937.3643993-2-guoren@kernel.org +Cc: stable@vger.kernel.org +Signed-off-by: Palmer Dabbelt +Signed-off-by: Sasha Levin +--- + arch/riscv/kernel/stacktrace.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c +index 3d1e184e39e9..75ed5b5b1f9b 100644 +--- a/arch/riscv/kernel/stacktrace.c ++++ b/arch/riscv/kernel/stacktrace.c +@@ -69,7 +69,7 @@ static void notrace walk_stackframe(struct task_struct *task, + } else { + fp = frame->fp; + pc = ftrace_graph_ret_addr(current, NULL, frame->ra, +- (unsigned long *)(fp - 8)); ++ &frame->ra); + } + + } +-- +2.35.1 + diff --git a/queue-4.19/series b/queue-4.19/series index 00592d24c13..b85c1edf2dd 100644 --- a/queue-4.19/series +++ b/queue-4.19/series @@ -423,3 +423,33 @@ btrfs-replace-strncpy-with-strscpy.patch media-s5p-mfc-fix-to-handle-reference-queue-during-f.patch media-s5p-mfc-clear-workbit-to-handle-error-conditio.patch media-s5p-mfc-fix-in-register-read-and-write-for-h26.patch +dm-thin-resume-even-if-in-fail-mode.patch +perf-probe-use-dwarf_attr_integrate-as-generic-dwarf.patch +perf-probe-fix-to-get-the-dw_at_decl_file-and-dw_at_.patch +ravb-fix-failed-to-switch-device-to-config-mode-mess.patch +riscv-remove-unreachable-have_function_graph_ret_add.patch +riscv-stacktrace-fix-stack-output-without-ra-on-the-.patch +riscv-stacktrace-fixup-ftrace_graph_ret_addr-retp-ar.patch +driver-core-set-deferred_probe_timeout-to-a-longer-d.patch +ext4-goto-right-label-failed_mount3a.patch +ext4-correct-inconsistent-error-msg-in-nojournal-mod.patch +ext4-use-kmemdup-to-replace-kmalloc-memcpy.patch +mbcache-don-t-reclaim-used-entries.patch +mbcache-add-functions-to-delete-entry-if-unused.patch +ext4-remove-ea-inode-entry-from-mbcache-on-inode-evi.patch +ext4-unindent-codeblock-in-ext4_xattr_block_set.patch +ext4-fix-race-when-reusing-xattr-blocks.patch +mbcache-automatically-delete-entries-from-cache-on-f.patch +ext4-fix-deadlock-due-to-mbcache-entry-corruption.patch +sunrpc-ensure-the-matching-upcall-is-in-flight-upon-.patch +bpf-pull-before-calling-skb_postpull_rcsum.patch +qlcnic-prevent-dcb-use-after-free-on-qlcnic_dcb_enab.patch +nfc-fix-potential-resource-leaks.patch +net-amd-xgbe-add-missed-tasklet_kill.patch +net-phy-xgmiitorgmii-fix-refcount-leak-in-xgmiitorgm.patch +rdma-mlx5-fix-validation-of-max_rd_atomic-caps-for-d.patch +net-sched-atm-dont-intepret-cls-results-when-asked-t.patch +usb-rndis_host-secure-rndis_query-check-against-int-.patch +caif-fix-memory-leak-in-cfctrl_linkup_request.patch +udf-fix-extension-of-the-last-extent-in-the-file.patch +asoc-intel-bytcr_rt5640-add-quirk-for-the-advantech-.patch diff --git a/queue-4.19/sunrpc-ensure-the-matching-upcall-is-in-flight-upon-.patch b/queue-4.19/sunrpc-ensure-the-matching-upcall-is-in-flight-upon-.patch new file mode 100644 index 00000000000..3df8bd8635c --- /dev/null +++ b/queue-4.19/sunrpc-ensure-the-matching-upcall-is-in-flight-upon-.patch @@ -0,0 +1,133 @@ +From 2dd149c938913e7c12d2cbc69d0e50e5b3f0d756 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Dec 2022 13:14:31 +0900 +Subject: SUNRPC: ensure the matching upcall is in-flight upon downcall + +From: minoura makoto + +[ Upstream commit b18cba09e374637a0a3759d856a6bca94c133952 ] + +Commit 9130b8dbc6ac ("SUNRPC: allow for upcalls for the same uid +but different gss service") introduced `auth` argument to +__gss_find_upcall(), but in gss_pipe_downcall() it was left as NULL +since it (and auth->service) was not (yet) determined. + +When multiple upcalls with the same uid and different service are +ongoing, it could happen that __gss_find_upcall(), which returns the +first match found in the pipe->in_downcall list, could not find the +correct gss_msg corresponding to the downcall we are looking for. +Moreover, it might return a msg which is not sent to rpc.gssd yet. + +We could see mount.nfs process hung in D state with multiple mount.nfs +are executed in parallel. The call trace below is of CentOS 7.9 +kernel-3.10.0-1160.24.1.el7.x86_64 but we observed the same hang w/ +elrepo kernel-ml-6.0.7-1.el7. + +PID: 71258 TASK: ffff91ebd4be0000 CPU: 36 COMMAND: "mount.nfs" + #0 [ffff9203ca3234f8] __schedule at ffffffffa3b8899f + #1 [ffff9203ca323580] schedule at ffffffffa3b88eb9 + #2 [ffff9203ca323590] gss_cred_init at ffffffffc0355818 [auth_rpcgss] + #3 [ffff9203ca323658] rpcauth_lookup_credcache at ffffffffc0421ebc +[sunrpc] + #4 [ffff9203ca3236d8] gss_lookup_cred at ffffffffc0353633 [auth_rpcgss] + #5 [ffff9203ca3236e8] rpcauth_lookupcred at ffffffffc0421581 [sunrpc] + #6 [ffff9203ca323740] rpcauth_refreshcred at ffffffffc04223d3 [sunrpc] + #7 [ffff9203ca3237a0] call_refresh at ffffffffc04103dc [sunrpc] + #8 [ffff9203ca3237b8] __rpc_execute at ffffffffc041e1c9 [sunrpc] + #9 [ffff9203ca323820] rpc_execute at ffffffffc0420a48 [sunrpc] + +The scenario is like this. Let's say there are two upcalls for +services A and B, A -> B in pipe->in_downcall, B -> A in pipe->pipe. + +When rpc.gssd reads pipe to get the upcall msg corresponding to +service B from pipe->pipe and then writes the response, in +gss_pipe_downcall the msg corresponding to service A will be picked +because only uid is used to find the msg and it is before the one for +B in pipe->in_downcall. And the process waiting for the msg +corresponding to service A will be woken up. + +Actual scheduing of that process might be after rpc.gssd processes the +next msg. In rpc_pipe_generic_upcall it clears msg->errno (for A). +The process is scheduled to see gss_msg->ctx == NULL and +gss_msg->msg.errno == 0, therefore it cannot break the loop in +gss_create_upcall and is never woken up after that. + +This patch adds a simple check to ensure that a msg which is not +sent to rpc.gssd yet is not chosen as the matching upcall upon +receiving a downcall. + +Signed-off-by: minoura makoto +Signed-off-by: Hiroshi Shimamoto +Tested-by: Hiroshi Shimamoto +Cc: Trond Myklebust +Fixes: 9130b8dbc6ac ("SUNRPC: allow for upcalls for same uid but different gss service") +Signed-off-by: Trond Myklebust +Signed-off-by: Sasha Levin +--- + include/linux/sunrpc/rpc_pipe_fs.h | 5 +++++ + net/sunrpc/auth_gss/auth_gss.c | 19 +++++++++++++++++-- + 2 files changed, 22 insertions(+), 2 deletions(-) + +diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h +index e90b9bd99ded..396de2ef8767 100644 +--- a/include/linux/sunrpc/rpc_pipe_fs.h ++++ b/include/linux/sunrpc/rpc_pipe_fs.h +@@ -94,6 +94,11 @@ extern ssize_t rpc_pipe_generic_upcall(struct file *, struct rpc_pipe_msg *, + char __user *, size_t); + extern int rpc_queue_upcall(struct rpc_pipe *, struct rpc_pipe_msg *); + ++/* returns true if the msg is in-flight, i.e., already eaten by the peer */ ++static inline bool rpc_msg_is_inflight(const struct rpc_pipe_msg *msg) { ++ return (msg->copied != 0 && list_empty(&msg->list)); ++} ++ + struct rpc_clnt; + extern struct dentry *rpc_create_client_dir(struct dentry *, const char *, struct rpc_clnt *); + extern int rpc_remove_client_dir(struct rpc_clnt *); +diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c +index e61c48c1b37d..c11e68539602 100644 +--- a/net/sunrpc/auth_gss/auth_gss.c ++++ b/net/sunrpc/auth_gss/auth_gss.c +@@ -323,7 +323,7 @@ __gss_find_upcall(struct rpc_pipe *pipe, kuid_t uid, const struct gss_auth *auth + list_for_each_entry(pos, &pipe->in_downcall, list) { + if (!uid_eq(pos->uid, uid)) + continue; +- if (auth && pos->auth->service != auth->service) ++ if (pos->auth->service != auth->service) + continue; + refcount_inc(&pos->count); + dprintk("RPC: %s found msg %p\n", __func__, pos); +@@ -677,6 +677,21 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) + return err; + } + ++static struct gss_upcall_msg * ++gss_find_downcall(struct rpc_pipe *pipe, kuid_t uid) ++{ ++ struct gss_upcall_msg *pos; ++ list_for_each_entry(pos, &pipe->in_downcall, list) { ++ if (!uid_eq(pos->uid, uid)) ++ continue; ++ if (!rpc_msg_is_inflight(&pos->msg)) ++ continue; ++ refcount_inc(&pos->count); ++ return pos; ++ } ++ return NULL; ++} ++ + #define MSG_BUF_MAXSIZE 1024 + + static ssize_t +@@ -723,7 +738,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen) + err = -ENOENT; + /* Find a matching upcall */ + spin_lock(&pipe->lock); +- gss_msg = __gss_find_upcall(pipe, uid, NULL); ++ gss_msg = gss_find_downcall(pipe, uid); + if (gss_msg == NULL) { + spin_unlock(&pipe->lock); + goto err_put_ctx; +-- +2.35.1 + diff --git a/queue-4.19/udf-fix-extension-of-the-last-extent-in-the-file.patch b/queue-4.19/udf-fix-extension-of-the-last-extent-in-the-file.patch new file mode 100644 index 00000000000..af43eb99e7b --- /dev/null +++ b/queue-4.19/udf-fix-extension-of-the-last-extent-in-the-file.patch @@ -0,0 +1,37 @@ +From 38f877f49a704493a6b5d51ec63f77d23bfdfb16 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Dec 2022 17:45:51 +0100 +Subject: udf: Fix extension of the last extent in the file + +From: Jan Kara + +[ Upstream commit 83c7423d1eb6806d13c521d1002cc1a012111719 ] + +When extending the last extent in the file within the last block, we +wrongly computed the length of the last extent. This is mostly a +cosmetical problem since the extent does not contain any data and the +length will be fixed up by following operations but still. + +Fixes: 1f3868f06855 ("udf: Fix extending file within last block") +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/udf/inode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/udf/inode.c b/fs/udf/inode.c +index 8ff8cd0d2801..55a86120e756 100644 +--- a/fs/udf/inode.c ++++ b/fs/udf/inode.c +@@ -595,7 +595,7 @@ static void udf_do_extend_final_block(struct inode *inode, + */ + if (new_elen <= (last_ext->extLength & UDF_EXTENT_LENGTH_MASK)) + return; +- added_bytes = (last_ext->extLength & UDF_EXTENT_LENGTH_MASK) - new_elen; ++ added_bytes = new_elen - (last_ext->extLength & UDF_EXTENT_LENGTH_MASK); + last_ext->extLength += added_bytes; + UDF_I(inode)->i_lenExtents += added_bytes; + +-- +2.35.1 + diff --git a/queue-4.19/usb-rndis_host-secure-rndis_query-check-against-int-.patch b/queue-4.19/usb-rndis_host-secure-rndis_query-check-against-int-.patch new file mode 100644 index 00000000000..67c4946ad84 --- /dev/null +++ b/queue-4.19/usb-rndis_host-secure-rndis_query-check-against-int-.patch @@ -0,0 +1,43 @@ +From 222ef43d7b1aa8025766444d3cdefd14761c0a87 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Jan 2023 10:17:09 +0100 +Subject: usb: rndis_host: Secure rndis_query check against int overflow + +From: Szymon Heidrich + +[ Upstream commit c7dd13805f8b8fc1ce3b6d40f6aff47e66b72ad2 ] + +Variables off and len typed as uint32 in rndis_query function +are controlled by incoming RNDIS response message thus their +value may be manipulated. Setting off to a unexpectetly large +value will cause the sum with len and 8 to overflow and pass +the implemented validation step. Consequently the response +pointer will be referring to a location past the expected +buffer boundaries allowing information leakage e.g. via +RNDIS_OID_802_3_PERMANENT_ADDRESS OID. + +Fixes: ddda08624013 ("USB: rndis_host, various cleanups") +Signed-off-by: Szymon Heidrich +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/usb/rndis_host.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c +index ab41a63aa4aa..497d6bcdc276 100644 +--- a/drivers/net/usb/rndis_host.c ++++ b/drivers/net/usb/rndis_host.c +@@ -267,7 +267,8 @@ static int rndis_query(struct usbnet *dev, struct usb_interface *intf, + + off = le32_to_cpu(u.get_c->offset); + len = le32_to_cpu(u.get_c->len); +- if (unlikely((8 + off + len) > CONTROL_BUFFER_SIZE)) ++ if (unlikely((off > CONTROL_BUFFER_SIZE - 8) || ++ (len > CONTROL_BUFFER_SIZE - 8 - off))) + goto response_error; + + if (*reply_len != -1 && len != *reply_len) +-- +2.35.1 +