From: Sasha Levin Date: Sun, 27 Nov 2022 19:07:02 +0000 (-0500) Subject: Fixes for 5.10 X-Git-Tag: v5.10.157~94 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=43ae932e3946e93b1aad58d06516215627d686f9;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for 5.10 Signed-off-by: Sasha Levin --- diff --git a/queue-5.10/9p-fd-fix-issue-of-list_del-corruption-in-p9_fd_canc.patch b/queue-5.10/9p-fd-fix-issue-of-list_del-corruption-in-p9_fd_canc.patch new file mode 100644 index 00000000000..9e22fbc3eff --- /dev/null +++ b/queue-5.10/9p-fd-fix-issue-of-list_del-corruption-in-p9_fd_canc.patch @@ -0,0 +1,75 @@ +From ffb459b056275ba2a3377e2cd7f348cb5843556c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 10 Nov 2022 20:26:06 +0800 +Subject: 9p/fd: fix issue of list_del corruption in p9_fd_cancel() + +From: Zhengchao Shao + +[ Upstream commit 11c10956515b8ec44cf4f2a7b9d8bf8b9dc05ec4 ] + +Syz reported the following issue: +kernel BUG at lib/list_debug.c:53! +invalid opcode: 0000 [#1] PREEMPT SMP KASAN +RIP: 0010:__list_del_entry_valid.cold+0x5c/0x72 +Call Trace: + +p9_fd_cancel+0xb1/0x270 +p9_client_rpc+0x8ea/0xba0 +p9_client_create+0x9c0/0xed0 +v9fs_session_init+0x1e0/0x1620 +v9fs_mount+0xba/0xb80 +legacy_get_tree+0x103/0x200 +vfs_get_tree+0x89/0x2d0 +path_mount+0x4c0/0x1ac0 +__x64_sys_mount+0x33b/0x430 +do_syscall_64+0x35/0x80 +entry_SYSCALL_64_after_hwframe+0x46/0xb0 + + +The process is as follows: +Thread A: Thread B: +p9_poll_workfn() p9_client_create() +... ... + p9_conn_cancel() p9_fd_cancel() + list_del() ... + ... list_del() //list_del + corruption +There is no lock protection when deleting list in p9_conn_cancel(). After +deleting list in Thread A, thread B will delete the same list again. It +will cause issue of list_del corruption. + +Setting req->status to REQ_STATUS_ERROR under lock prevents other +cleanup paths from trying to manipulate req_list. +The other thread can safely check req->status because it still holds a +reference to req at this point. + +Link: https://lkml.kernel.org/r/20221110122606.383352-1-shaozhengchao@huawei.com +Fixes: 52f1c45dde91 ("9p: trans_fd/p9_conn_cancel: drop client lock earlier") +Reported-by: syzbot+9b69b8d10ab4a7d88056@syzkaller.appspotmail.com +Signed-off-by: Zhengchao Shao +[Dominique: add description of the fix in commit message] +Signed-off-by: Dominique Martinet +Signed-off-by: Sasha Levin +--- + net/9p/trans_fd.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c +index fec6c800c898..400219801e63 100644 +--- a/net/9p/trans_fd.c ++++ b/net/9p/trans_fd.c +@@ -200,9 +200,11 @@ static void p9_conn_cancel(struct p9_conn *m, int err) + + list_for_each_entry_safe(req, rtmp, &m->req_list, req_list) { + list_move(&req->req_list, &cancel_list); ++ req->status = REQ_STATUS_ERROR; + } + list_for_each_entry_safe(req, rtmp, &m->unsent_req_list, req_list) { + list_move(&req->req_list, &cancel_list); ++ req->status = REQ_STATUS_ERROR; + } + + spin_unlock(&m->client->lock); +-- +2.35.1 + diff --git a/queue-5.10/af_key-fix-send_acquire-race-with-pfkey_register.patch b/queue-5.10/af_key-fix-send_acquire-race-with-pfkey_register.patch new file mode 100644 index 00000000000..cd828e2f581 --- /dev/null +++ b/queue-5.10/af_key-fix-send_acquire-race-with-pfkey_register.patch @@ -0,0 +1,147 @@ +From cb62db4976d827457027f31b1030129cea8ec7f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Oct 2022 14:06:48 +0800 +Subject: af_key: Fix send_acquire race with pfkey_register + +From: Herbert Xu + +[ Upstream commit 7f57f8165cb6d2c206e2b9ada53b9e2d6d8af42f ] + +The function pfkey_send_acquire may race with pfkey_register +(which could even be in a different name space). This may result +in a buffer overrun. + +Allocating the maximum amount of memory that could be used prevents +this. + +Reported-by: syzbot+1e9af9185d8850e2c2fa@syzkaller.appspotmail.com +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Herbert Xu +Reviewed-by: Sabrina Dubroca +Reviewed-by: Eric Dumazet +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/key/af_key.c | 32 ++++++++++++++++++++++---------- + 1 file changed, 22 insertions(+), 10 deletions(-) + +diff --git a/net/key/af_key.c b/net/key/af_key.c +index 05e271098888..8bc7d399987b 100644 +--- a/net/key/af_key.c ++++ b/net/key/af_key.c +@@ -2909,7 +2909,7 @@ static int count_ah_combs(const struct xfrm_tmpl *t) + break; + if (!aalg->pfkey_supported) + continue; +- if (aalg_tmpl_set(t, aalg) && aalg->available) ++ if (aalg_tmpl_set(t, aalg)) + sz += sizeof(struct sadb_comb); + } + return sz + sizeof(struct sadb_prop); +@@ -2927,7 +2927,7 @@ static int count_esp_combs(const struct xfrm_tmpl *t) + if (!ealg->pfkey_supported) + continue; + +- if (!(ealg_tmpl_set(t, ealg) && ealg->available)) ++ if (!(ealg_tmpl_set(t, ealg))) + continue; + + for (k = 1; ; k++) { +@@ -2938,16 +2938,17 @@ static int count_esp_combs(const struct xfrm_tmpl *t) + if (!aalg->pfkey_supported) + continue; + +- if (aalg_tmpl_set(t, aalg) && aalg->available) ++ if (aalg_tmpl_set(t, aalg)) + sz += sizeof(struct sadb_comb); + } + } + return sz + sizeof(struct sadb_prop); + } + +-static void dump_ah_combs(struct sk_buff *skb, const struct xfrm_tmpl *t) ++static int dump_ah_combs(struct sk_buff *skb, const struct xfrm_tmpl *t) + { + struct sadb_prop *p; ++ int sz = 0; + int i; + + p = skb_put(skb, sizeof(struct sadb_prop)); +@@ -2975,13 +2976,17 @@ static void dump_ah_combs(struct sk_buff *skb, const struct xfrm_tmpl *t) + c->sadb_comb_soft_addtime = 20*60*60; + c->sadb_comb_hard_usetime = 8*60*60; + c->sadb_comb_soft_usetime = 7*60*60; ++ sz += sizeof(*c); + } + } ++ ++ return sz + sizeof(*p); + } + +-static void dump_esp_combs(struct sk_buff *skb, const struct xfrm_tmpl *t) ++static int dump_esp_combs(struct sk_buff *skb, const struct xfrm_tmpl *t) + { + struct sadb_prop *p; ++ int sz = 0; + int i, k; + + p = skb_put(skb, sizeof(struct sadb_prop)); +@@ -3023,8 +3028,11 @@ static void dump_esp_combs(struct sk_buff *skb, const struct xfrm_tmpl *t) + c->sadb_comb_soft_addtime = 20*60*60; + c->sadb_comb_hard_usetime = 8*60*60; + c->sadb_comb_soft_usetime = 7*60*60; ++ sz += sizeof(*c); + } + } ++ ++ return sz + sizeof(*p); + } + + static int key_notify_policy_expire(struct xfrm_policy *xp, const struct km_event *c) +@@ -3154,6 +3162,7 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct + struct sadb_x_sec_ctx *sec_ctx; + struct xfrm_sec_ctx *xfrm_ctx; + int ctx_size = 0; ++ int alg_size = 0; + + sockaddr_size = pfkey_sockaddr_size(x->props.family); + if (!sockaddr_size) +@@ -3165,16 +3174,16 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct + sizeof(struct sadb_x_policy); + + if (x->id.proto == IPPROTO_AH) +- size += count_ah_combs(t); ++ alg_size = count_ah_combs(t); + else if (x->id.proto == IPPROTO_ESP) +- size += count_esp_combs(t); ++ alg_size = count_esp_combs(t); + + if ((xfrm_ctx = x->security)) { + ctx_size = PFKEY_ALIGN8(xfrm_ctx->ctx_len); + size += sizeof(struct sadb_x_sec_ctx) + ctx_size; + } + +- skb = alloc_skb(size + 16, GFP_ATOMIC); ++ skb = alloc_skb(size + alg_size + 16, GFP_ATOMIC); + if (skb == NULL) + return -ENOMEM; + +@@ -3228,10 +3237,13 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct + pol->sadb_x_policy_priority = xp->priority; + + /* Set sadb_comb's. */ ++ alg_size = 0; + if (x->id.proto == IPPROTO_AH) +- dump_ah_combs(skb, t); ++ alg_size = dump_ah_combs(skb, t); + else if (x->id.proto == IPPROTO_ESP) +- dump_esp_combs(skb, t); ++ alg_size = dump_esp_combs(skb, t); ++ ++ hdr->sadb_msg_len += alg_size / 8; + + /* security context */ + if (xfrm_ctx) { +-- +2.35.1 + diff --git a/queue-5.10/arcnet-fix-potential-memory-leak-in-com20020_probe.patch b/queue-5.10/arcnet-fix-potential-memory-leak-in-com20020_probe.patch new file mode 100644 index 00000000000..f9f2f2f351e --- /dev/null +++ b/queue-5.10/arcnet-fix-potential-memory-leak-in-com20020_probe.patch @@ -0,0 +1,61 @@ +From 19c7090462884d1780b220635078a464053a53ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 20 Nov 2022 14:24:38 +0800 +Subject: arcnet: fix potential memory leak in com20020_probe() + +From: Wang Hai + +[ Upstream commit 1c40cde6b5171d9c8dfc69be00464fd1c75e210b ] + +In com20020_probe(), if com20020_config() fails, dev and info +will not be freed, which will lead to a memory leak. + +This patch adds freeing dev and info after com20020_config() +fails to fix this bug. + +Compile tested only. + +Fixes: 15b99ac17295 ("[PATCH] pcmcia: add return value to _config() functions") +Signed-off-by: Wang Hai +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/arcnet/com20020_cs.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/arcnet/com20020_cs.c b/drivers/net/arcnet/com20020_cs.c +index 9cc5eb6a8e90..e0c7720bd5da 100644 +--- a/drivers/net/arcnet/com20020_cs.c ++++ b/drivers/net/arcnet/com20020_cs.c +@@ -113,6 +113,7 @@ static int com20020_probe(struct pcmcia_device *p_dev) + struct com20020_dev *info; + struct net_device *dev; + struct arcnet_local *lp; ++ int ret = -ENOMEM; + + dev_dbg(&p_dev->dev, "com20020_attach()\n"); + +@@ -142,12 +143,18 @@ static int com20020_probe(struct pcmcia_device *p_dev) + info->dev = dev; + p_dev->priv = info; + +- return com20020_config(p_dev); ++ ret = com20020_config(p_dev); ++ if (ret) ++ goto fail_config; ++ ++ return 0; + ++fail_config: ++ free_arcdev(dev); + fail_alloc_dev: + kfree(info); + fail_alloc_info: +- return -ENOMEM; ++ return ret; + } /* com20020_attach */ + + static void com20020_detach(struct pcmcia_device *link) +-- +2.35.1 + diff --git a/queue-5.10/arm-dts-am335x-pcm-953-define-fixed-regulators-in-ro.patch b/queue-5.10/arm-dts-am335x-pcm-953-define-fixed-regulators-in-ro.patch new file mode 100644 index 00000000000..d7ad4818a61 --- /dev/null +++ b/queue-5.10/arm-dts-am335x-pcm-953-define-fixed-regulators-in-ro.patch @@ -0,0 +1,66 @@ +From f045a1e5b7f1b0d627199a55e8638b9a2f37dabd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 11 Oct 2022 16:31:15 +0200 +Subject: ARM: dts: am335x-pcm-953: Define fixed regulators in root node + +From: Dominik Haller + +[ Upstream commit 8950f345a67d8046d2472dd6ea81fa18ef5b4844 ] + +Remove the regulators node and define fixed regulators in the root node. +Prevents the sdhci-omap driver from waiting in probe deferral forever +because of the missing vmmc-supply and keeps am335x-pcm-953 consistent with +the other Phytec AM335 boards. + +Fixes: bb07a829ec38 ("ARM: dts: Add support for phyCORE-AM335x PCM-953 carrier board") +Signed-off-by: Dominik Haller +Message-Id: <20221011143115.248003-1-d.haller@phytec.de> +Signed-off-by: Tony Lindgren +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/am335x-pcm-953.dtsi | 28 +++++++++++++-------------- + 1 file changed, 13 insertions(+), 15 deletions(-) + +diff --git a/arch/arm/boot/dts/am335x-pcm-953.dtsi b/arch/arm/boot/dts/am335x-pcm-953.dtsi +index 6c547c83e5dd..fc465f0d7e18 100644 +--- a/arch/arm/boot/dts/am335x-pcm-953.dtsi ++++ b/arch/arm/boot/dts/am335x-pcm-953.dtsi +@@ -12,22 +12,20 @@ / { + compatible = "phytec,am335x-pcm-953", "phytec,am335x-phycore-som", "ti,am33xx"; + + /* Power */ +- regulators { +- vcc3v3: fixedregulator@1 { +- compatible = "regulator-fixed"; +- regulator-name = "vcc3v3"; +- regulator-min-microvolt = <3300000>; +- regulator-max-microvolt = <3300000>; +- regulator-boot-on; +- }; ++ vcc3v3: fixedregulator1 { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc3v3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ }; + +- vcc1v8: fixedregulator@2 { +- compatible = "regulator-fixed"; +- regulator-name = "vcc1v8"; +- regulator-min-microvolt = <1800000>; +- regulator-max-microvolt = <1800000>; +- regulator-boot-on; +- }; ++ vcc1v8: fixedregulator2 { ++ compatible = "regulator-fixed"; ++ regulator-name = "vcc1v8"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; + }; + + /* User IO */ +-- +2.35.1 + diff --git a/queue-5.10/arm-dts-at91-sam9g20ek-enable-udc-vbus-gpio-pinctrl.patch b/queue-5.10/arm-dts-at91-sam9g20ek-enable-udc-vbus-gpio-pinctrl.patch new file mode 100644 index 00000000000..b4560f6f10f --- /dev/null +++ b/queue-5.10/arm-dts-at91-sam9g20ek-enable-udc-vbus-gpio-pinctrl.patch @@ -0,0 +1,57 @@ +From 654fde17b0ee109e024043eb07afe9f367ca7d28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 14 Nov 2022 19:59:23 +0100 +Subject: ARM: dts: at91: sam9g20ek: enable udc vbus gpio pinctrl + +From: Michael Grzeschik + +[ Upstream commit 40a2226e8bfacb79dd154dea68febeead9d847e9 ] + +We set the PIOC to GPIO mode. This way the pin becomes an +input signal will be usable by the controller. Without +this change the udc on the 9g20ek does not work. + +Cc: nicolas.ferre@microchip.com +Cc: ludovic.desroches@microchip.com +Cc: alexandre.belloni@bootlin.com +Cc: linux-arm-kernel@lists.infradead.org +Cc: kernel@pengutronix.de +Fixes: 5cb4e73575e3 ("ARM: at91: add at91sam9g20ek boards dt support") +Signed-off-by: Michael Grzeschik +Signed-off-by: Claudiu Beznea +Link: https://lore.kernel.org/r/20221114185923.1023249-3-m.grzeschik@pengutronix.de +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/at91sam9g20ek_common.dtsi | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi +index ca03685f0f08..4783e657b4cb 100644 +--- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi ++++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi +@@ -39,6 +39,13 @@ pinctrl_pck0_as_mck: pck0_as_mck { + + }; + ++ usb1 { ++ pinctrl_usb1_vbus_gpio: usb1_vbus_gpio { ++ atmel,pins = ++ ; /* PC5 GPIO */ ++ }; ++ }; ++ + mmc0_slot1 { + pinctrl_board_mmc0_slot1: mmc0_slot1-board { + atmel,pins = +@@ -84,6 +91,8 @@ macb0: ethernet@fffc4000 { + }; + + usb1: gadget@fffa4000 { ++ pinctrl-0 = <&pinctrl_usb1_vbus_gpio>; ++ pinctrl-names = "default"; + atmel,vbus-gpio = <&pioC 5 GPIO_ACTIVE_HIGH>; + status = "okay"; + }; +-- +2.35.1 + diff --git a/queue-5.10/arm-dts-imx6q-prti6q-fix-ref-tcxo-clock-frequency-pr.patch b/queue-5.10/arm-dts-imx6q-prti6q-fix-ref-tcxo-clock-frequency-pr.patch new file mode 100644 index 00000000000..c7399da9625 --- /dev/null +++ b/queue-5.10/arm-dts-imx6q-prti6q-fix-ref-tcxo-clock-frequency-pr.patch @@ -0,0 +1,43 @@ +From 533713aab3863a07a11396e3669ce3340dd78d74 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 18 Nov 2022 10:41:02 -0300 +Subject: ARM: dts: imx6q-prti6q: Fix ref/tcxo-clock-frequency properties + +From: Fabio Estevam + +[ Upstream commit e68be7b39f21d8a9291a5a3019787cd3ca999dd7 ] + +make dtbs_check gives the following errors: + +ref-clock-frequency: size (9) error for type uint32 +tcxo-clock-frequency: size (9) error for type uint32 + +Fix it by passing the frequencies inside < > as documented in +Documentation/devicetree/bindings/net/wireless/ti,wlcore.yaml. + +Signed-off-by: Fabio Estevam +Fixes: 0d446a505592 ("ARM: dts: add Protonic PRTI6Q board") +Signed-off-by: Shawn Guo +Signed-off-by: Sasha Levin +--- + arch/arm/boot/dts/imx6q-prti6q.dts | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/arch/arm/boot/dts/imx6q-prti6q.dts b/arch/arm/boot/dts/imx6q-prti6q.dts +index b4605edfd2ab..d8fa83effd63 100644 +--- a/arch/arm/boot/dts/imx6q-prti6q.dts ++++ b/arch/arm/boot/dts/imx6q-prti6q.dts +@@ -364,8 +364,8 @@ wifi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wifi>; + interrupts-extended = <&gpio1 30 IRQ_TYPE_LEVEL_HIGH>; +- ref-clock-frequency = "38400000"; +- tcxo-clock-frequency = "19200000"; ++ ref-clock-frequency = <38400000>; ++ tcxo-clock-frequency = <19200000>; + }; + }; + +-- +2.35.1 + diff --git a/queue-5.10/arm-mxs-fix-memory-leak-in-mxs_machine_init.patch b/queue-5.10/arm-mxs-fix-memory-leak-in-mxs_machine_init.patch new file mode 100644 index 00000000000..592657c1f09 --- /dev/null +++ b/queue-5.10/arm-mxs-fix-memory-leak-in-mxs_machine_init.patch @@ -0,0 +1,40 @@ +From 50d022c8fe90424319ebf8f9b826a543ac9eaad0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Nov 2022 06:20:11 +0000 +Subject: ARM: mxs: fix memory leak in mxs_machine_init() + +From: Zheng Yongjun + +[ Upstream commit f31e3c204d1844b8680a442a48868af5ac3d5481 ] + +If of_property_read_string() failed, 'soc_dev_attr' should be +freed before return. Otherwise there is a memory leak. + +Fixes: 2046338dcbc6 ("ARM: mxs: Use soc bus infrastructure") +Signed-off-by: Zheng Yongjun +Reviewed-by: Marco Felsch +Signed-off-by: Shawn Guo +Signed-off-by: Sasha Levin +--- + arch/arm/mach-mxs/mach-mxs.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/arch/arm/mach-mxs/mach-mxs.c b/arch/arm/mach-mxs/mach-mxs.c +index c109f47e9cbc..a687e83ad604 100644 +--- a/arch/arm/mach-mxs/mach-mxs.c ++++ b/arch/arm/mach-mxs/mach-mxs.c +@@ -387,8 +387,10 @@ static void __init mxs_machine_init(void) + + root = of_find_node_by_path("/"); + ret = of_property_read_string(root, "model", &soc_dev_attr->machine); +- if (ret) ++ if (ret) { ++ kfree(soc_dev_attr); + return; ++ } + + soc_dev_attr->family = "Freescale MXS Family"; + soc_dev_attr->soc_id = mxs_get_soc_id(); +-- +2.35.1 + diff --git a/queue-5.10/asoc-hdac_hda-fix-hda-pcm-buffer-overflow-issue.patch b/queue-5.10/asoc-hdac_hda-fix-hda-pcm-buffer-overflow-issue.patch new file mode 100644 index 00000000000..3bc96970d17 --- /dev/null +++ b/queue-5.10/asoc-hdac_hda-fix-hda-pcm-buffer-overflow-issue.patch @@ -0,0 +1,66 @@ +From 46358f732a6009a112944ed566e7765ac1a979f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 10 Nov 2022 07:40:23 +0800 +Subject: ASoC: hdac_hda: fix hda pcm buffer overflow issue + +From: Junxiao Chang + +[ Upstream commit 37882100cd0629d830db430a8cee0b724fe1fea3 ] + +When KASAN is enabled, below log might be dumped with Intel EHL hardware: +[ 48.583597] ================================================================== +[ 48.585921] BUG: KASAN: slab-out-of-bounds in hdac_hda_dai_hw_params+0x20a/0x22b [snd_soc_hdac_hda] +[ 48.587995] Write of size 4 at addr ffff888103489708 by task pulseaudio/759 + +[ 48.589237] CPU: 2 PID: 759 Comm: pulseaudio Tainted: G U E 5.15.71-intel-ese-standard-lts #9 +[ 48.591272] Hardware name: Intel Corporation Elkhart Lake Embedded Platform/ElkhartLake LPDDR4x T3 CRB, BIOS EHLSFWI1.R00.4251.A01.2206130432 06/13/2022 +[ 48.593010] Call Trace: +[ 48.593648] +[ 48.593852] dump_stack_lvl+0x34/0x48 +[ 48.594404] print_address_description.constprop.0+0x1f/0x140 +[ 48.595174] ? hdac_hda_dai_hw_params+0x20a/0x22b [snd_soc_hdac_hda] +[ 48.595868] ? hdac_hda_dai_hw_params+0x20a/0x22b [snd_soc_hdac_hda] +[ 48.596519] kasan_report.cold+0x7f/0x11b +[ 48.597003] ? hdac_hda_dai_hw_params+0x20a/0x22b [snd_soc_hdac_hda] +[ 48.597885] hdac_hda_dai_hw_params+0x20a/0x22b [snd_soc_hdac_hda] + +HDAC_LAST_DAI_ID is last index id, pcm buffer array size should +be +1 to avoid out of bound access. + +Fixes: 608b8c36c371 ("ASoC: hdac_hda: add support for HDMI/DP as a HDA codec") +Reviewed-by: Kai Vehmanen +Reviewed-by: Pierre-Louis Bossart +Signed-off-by: Junxiao Chang +Signed-off-by: Furong Zhou +Link: https://lore.kernel.org/r/20221109234023.3111035-1-junxiao.chang@intel.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/hdac_hda.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sound/soc/codecs/hdac_hda.h b/sound/soc/codecs/hdac_hda.h +index d0efc5e254ae..da0ed74758b0 100644 +--- a/sound/soc/codecs/hdac_hda.h ++++ b/sound/soc/codecs/hdac_hda.h +@@ -14,7 +14,7 @@ enum { + HDAC_HDMI_1_DAI_ID, + HDAC_HDMI_2_DAI_ID, + HDAC_HDMI_3_DAI_ID, +- HDAC_LAST_DAI_ID = HDAC_HDMI_3_DAI_ID, ++ HDAC_DAI_ID_NUM + }; + + struct hdac_hda_pcm { +@@ -24,7 +24,7 @@ struct hdac_hda_pcm { + + struct hdac_hda_priv { + struct hda_codec codec; +- struct hdac_hda_pcm pcm[HDAC_LAST_DAI_ID]; ++ struct hdac_hda_pcm pcm[HDAC_DAI_ID_NUM]; + bool need_display_power; + }; + +-- +2.35.1 + diff --git a/queue-5.10/asoc-sgtl5000-reset-the-chip_clk_ctrl-reg-on-remove.patch b/queue-5.10/asoc-sgtl5000-reset-the-chip_clk_ctrl-reg-on-remove.patch new file mode 100644 index 00000000000..f4b086577d8 --- /dev/null +++ b/queue-5.10/asoc-sgtl5000-reset-the-chip_clk_ctrl-reg-on-remove.patch @@ -0,0 +1,48 @@ +From 8eda46507de818845495c525acabe5ccce4186f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 10 Nov 2022 14:06:12 -0500 +Subject: ASoC: sgtl5000: Reset the CHIP_CLK_CTRL reg on remove + +From: Detlev Casanova + +[ Upstream commit 0bb8e9b36b5b7f2e77892981ff6c27ee831d8026 ] + +Since commit bf2aebccddef ("ASoC: sgtl5000: Fix noise on shutdown/remove"), +the device power control registers are reset when the driver is +removed/shutdown. + +This is an issue when the device is configured to use the PLL clock. The +device will stop responding if it is still configured to use the PLL +clock but the PLL clock is powered down. + +When rebooting linux, the probe function will show: +sgtl5000 0-000a: Error reading chip id -11 + +Make sure that the CHIP_CLK_CTRL is reset to its default value before +powering down the device. + +Fixes: bf2aebccddef ("ASoC: sgtl5000: Fix noise on shutdown/remove") +Signed-off-by: Detlev Casanova +Reviewed-by: Fabio Estevam +Link: https://lore.kernel.org/r/20221110190612.1341469-1-detlev.casanova@collabora.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/codecs/sgtl5000.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c +index f066e016a874..edde0323799a 100644 +--- a/sound/soc/codecs/sgtl5000.c ++++ b/sound/soc/codecs/sgtl5000.c +@@ -1797,6 +1797,7 @@ static int sgtl5000_i2c_remove(struct i2c_client *client) + { + struct sgtl5000_priv *sgtl5000 = i2c_get_clientdata(client); + ++ regmap_write(sgtl5000->regmap, SGTL5000_CHIP_CLK_CTRL, SGTL5000_CHIP_CLK_CTRL_DEFAULT); + regmap_write(sgtl5000->regmap, SGTL5000_CHIP_DIG_POWER, SGTL5000_DIG_POWER_DEFAULT); + regmap_write(sgtl5000->regmap, SGTL5000_CHIP_ANA_POWER, SGTL5000_ANA_POWER_DEFAULT); + +-- +2.35.1 + diff --git a/queue-5.10/asoc-soc-pcm-don-t-zero-tdm-masks-in-__soc_pcm_open.patch b/queue-5.10/asoc-soc-pcm-don-t-zero-tdm-masks-in-__soc_pcm_open.patch new file mode 100644 index 00000000000..8005e2d3ee3 --- /dev/null +++ b/queue-5.10/asoc-soc-pcm-don-t-zero-tdm-masks-in-__soc_pcm_open.patch @@ -0,0 +1,47 @@ +From 76f1306613c55a43b88703ffb53d6c0a557d0e05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 4 Nov 2022 13:22:13 +0000 +Subject: ASoC: soc-pcm: Don't zero TDM masks in __soc_pcm_open() + +From: Richard Fitzgerald + +[ Upstream commit 39bd801d6908900e9ab0cdc2655150f95ddd4f1a ] + +The DAI tx_mask and rx_mask are set by snd_soc_dai_set_tdm_slot() +and used by later code that depends on the TDM settings. So +__soc_pcm_open() should not be obliterating those mask values. + +The code in __soc_pcm_hw_params() uses these masks to calculate the +active channels so that only the AIF_IN/AIF_OUT widgets for the +active TDM slots are enabled. The zeroing of the masks in +__soc_pcm_open() disables this functionality so all AIF widgets +were enabled even for channels that are not assigned to a TDM slot. + +Signed-off-by: Richard Fitzgerald +Fixes: 2e5894d73789 ("ASoC: pcm: Add support for DAI multicodec") +Link: https://lore.kernel.org/r/20221104132213.121847-1-rf@opensource.cirrus.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/soc-pcm.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index 8b8a9aca2912..0e2261ee07b6 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -723,11 +723,6 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) + ret = snd_soc_dai_startup(dai, substream); + if (ret < 0) + goto err; +- +- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) +- dai->tx_mask = 0; +- else +- dai->rx_mask = 0; + } + + /* Dynamic PCM DAI links compat checks use dynamic capabilities */ +-- +2.35.1 + diff --git a/queue-5.10/bnx2x-fix-pci-device-refcount-leak-in-bnx2x_vf_is_pc.patch b/queue-5.10/bnx2x-fix-pci-device-refcount-leak-in-bnx2x_vf_is_pc.patch new file mode 100644 index 00000000000..640c31f67b3 --- /dev/null +++ b/queue-5.10/bnx2x-fix-pci-device-refcount-leak-in-bnx2x_vf_is_pc.patch @@ -0,0 +1,58 @@ +From 056fef03be31d1e5cdba858ef50799ebe5a0cbc1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 19 Nov 2022 15:02:02 +0800 +Subject: bnx2x: fix pci device refcount leak in bnx2x_vf_is_pcie_pending() + +From: Yang Yingliang + +[ Upstream commit 3637a29ccbb6461b7268c5c5db525935d510afc6 ] + +As comment of pci_get_domain_bus_and_slot() says, it returns +a pci device with refcount increment, when finish using it, +the caller must decrement the reference count by calling +pci_dev_put(). Call pci_dev_put() before returning from +bnx2x_vf_is_pcie_pending() to avoid refcount leak. + +Fixes: b56e9670ffa4 ("bnx2x: Prepare device and initialize VF database") +Suggested-by: Jakub Kicinski +Signed-off-by: Yang Yingliang +Reviewed-by: Leon Romanovsky +Link: https://lore.kernel.org/r/20221119070202.1407648-1-yangyingliang@huawei.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +index 08437eaacbb9..ac327839eed9 100644 +--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c ++++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +@@ -795,16 +795,20 @@ static void bnx2x_vf_enable_traffic(struct bnx2x *bp, struct bnx2x_virtf *vf) + + static u8 bnx2x_vf_is_pcie_pending(struct bnx2x *bp, u8 abs_vfid) + { +- struct pci_dev *dev; + struct bnx2x_virtf *vf = bnx2x_vf_by_abs_fid(bp, abs_vfid); ++ struct pci_dev *dev; ++ bool pending; + + if (!vf) + return false; + + dev = pci_get_domain_bus_and_slot(vf->domain, vf->bus, vf->devfn); +- if (dev) +- return bnx2x_is_pcie_pending(dev); +- return false; ++ if (!dev) ++ return false; ++ pending = bnx2x_is_pcie_pending(dev); ++ pci_dev_put(dev); ++ ++ return pending; + } + + int bnx2x_vf_flr_clnup_epilog(struct bnx2x *bp, u8 abs_vfid) +-- +2.35.1 + diff --git a/queue-5.10/bus-sunxi-rsb-support-atomic-transfers.patch b/queue-5.10/bus-sunxi-rsb-support-atomic-transfers.patch new file mode 100644 index 00000000000..f1465d10c0f --- /dev/null +++ b/queue-5.10/bus-sunxi-rsb-support-atomic-transfers.patch @@ -0,0 +1,92 @@ +From 29786f87a29ffdebd18692d56b7d512cd04b5b1e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 13 Nov 2022 19:57:48 -0600 +Subject: bus: sunxi-rsb: Support atomic transfers + +From: Samuel Holland + +[ Upstream commit 077686da0e2162c4ea5ae0df205849c2a7a84479 ] + +When communicating with a PMIC during system poweroff (pm_power_off()), +IRQs are disabled and we are in a RCU read-side critical section, so we +cannot use wait_for_completion_io_timeout(). Instead, poll the status +register for transfer completion. + +Fixes: d787dcdb9c8f ("bus: sunxi-rsb: Add driver for Allwinner Reduced Serial Bus") +Signed-off-by: Samuel Holland +Reviewed-by: Jernej Skrabec +Link: https://lore.kernel.org/r/20221114015749.28490-3-samuel@sholland.org +Signed-off-by: Jernej Skrabec +Signed-off-by: Sasha Levin +--- + drivers/bus/sunxi-rsb.c | 29 +++++++++++++++++++++-------- + 1 file changed, 21 insertions(+), 8 deletions(-) + +diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c +index 9b1a5e62417c..f8c29b888e6b 100644 +--- a/drivers/bus/sunxi-rsb.c ++++ b/drivers/bus/sunxi-rsb.c +@@ -268,6 +268,9 @@ EXPORT_SYMBOL_GPL(sunxi_rsb_driver_register); + /* common code that starts a transfer */ + static int _sunxi_rsb_run_xfer(struct sunxi_rsb *rsb) + { ++ u32 int_mask, status; ++ bool timeout; ++ + if (readl(rsb->regs + RSB_CTRL) & RSB_CTRL_START_TRANS) { + dev_dbg(rsb->dev, "RSB transfer still in progress\n"); + return -EBUSY; +@@ -275,13 +278,23 @@ static int _sunxi_rsb_run_xfer(struct sunxi_rsb *rsb) + + reinit_completion(&rsb->complete); + +- writel(RSB_INTS_LOAD_BSY | RSB_INTS_TRANS_ERR | RSB_INTS_TRANS_OVER, +- rsb->regs + RSB_INTE); ++ int_mask = RSB_INTS_LOAD_BSY | RSB_INTS_TRANS_ERR | RSB_INTS_TRANS_OVER; ++ writel(int_mask, rsb->regs + RSB_INTE); + writel(RSB_CTRL_START_TRANS | RSB_CTRL_GLOBAL_INT_ENB, + rsb->regs + RSB_CTRL); + +- if (!wait_for_completion_io_timeout(&rsb->complete, +- msecs_to_jiffies(100))) { ++ if (irqs_disabled()) { ++ timeout = readl_poll_timeout_atomic(rsb->regs + RSB_INTS, ++ status, (status & int_mask), ++ 10, 100000); ++ writel(status, rsb->regs + RSB_INTS); ++ } else { ++ timeout = !wait_for_completion_io_timeout(&rsb->complete, ++ msecs_to_jiffies(100)); ++ status = rsb->status; ++ } ++ ++ if (timeout) { + dev_dbg(rsb->dev, "RSB timeout\n"); + + /* abort the transfer */ +@@ -293,18 +306,18 @@ static int _sunxi_rsb_run_xfer(struct sunxi_rsb *rsb) + return -ETIMEDOUT; + } + +- if (rsb->status & RSB_INTS_LOAD_BSY) { ++ if (status & RSB_INTS_LOAD_BSY) { + dev_dbg(rsb->dev, "RSB busy\n"); + return -EBUSY; + } + +- if (rsb->status & RSB_INTS_TRANS_ERR) { +- if (rsb->status & RSB_INTS_TRANS_ERR_ACK) { ++ if (status & RSB_INTS_TRANS_ERR) { ++ if (status & RSB_INTS_TRANS_ERR_ACK) { + dev_dbg(rsb->dev, "RSB slave nack\n"); + return -EINVAL; + } + +- if (rsb->status & RSB_INTS_TRANS_ERR_DATA) { ++ if (status & RSB_INTS_TRANS_ERR_DATA) { + dev_dbg(rsb->dev, "RSB transfer data error\n"); + return -EIO; + } +-- +2.35.1 + diff --git a/queue-5.10/dccp-tcp-reset-saddr-on-failure-after-inet6-_hash_co.patch b/queue-5.10/dccp-tcp-reset-saddr-on-failure-after-inet6-_hash_co.patch new file mode 100644 index 00000000000..046e78f4552 --- /dev/null +++ b/queue-5.10/dccp-tcp-reset-saddr-on-failure-after-inet6-_hash_co.patch @@ -0,0 +1,113 @@ +From 571d30360eaa05a98e53a2833fa4144facb197bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 18 Nov 2022 17:49:11 -0800 +Subject: dccp/tcp: Reset saddr on failure after inet6?_hash_connect(). + +From: Kuniyuki Iwashima + +[ Upstream commit 77934dc6db0d2b111a8f2759e9ad2fb67f5cffa5 ] + +When connect() is called on a socket bound to the wildcard address, +we change the socket's saddr to a local address. If the socket +fails to connect() to the destination, we have to reset the saddr. + +However, when an error occurs after inet_hash6?_connect() in +(dccp|tcp)_v[46]_conect(), we forget to reset saddr and leave +the socket bound to the address. + +From the user's point of view, whether saddr is reset or not varies +with errno. Let's fix this inconsistent behaviour. + +Note that after this patch, the repro [0] will trigger the WARN_ON() +in inet_csk_get_port() again, but this patch is not buggy and rather +fixes a bug papering over the bhash2's bug for which we need another +fix. + +For the record, the repro causes -EADDRNOTAVAIL in inet_hash6_connect() +by this sequence: + + s1 = socket() + s1.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) + s1.bind(('127.0.0.1', 10000)) + s1.sendto(b'hello', MSG_FASTOPEN, (('127.0.0.1', 10000))) + # or s1.connect(('127.0.0.1', 10000)) + + s2 = socket() + s2.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) + s2.bind(('0.0.0.0', 10000)) + s2.connect(('127.0.0.1', 10000)) # -EADDRNOTAVAIL + + s2.listen(32) # WARN_ON(inet_csk(sk)->icsk_bind2_hash != tb2); + +[0]: https://syzkaller.appspot.com/bug?extid=015d756bbd1f8b5c8f09 + +Fixes: 3df80d9320bc ("[DCCP]: Introduce DCCPv6") +Fixes: 7c657876b63c ("[DCCP]: Initial implementation") +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Kuniyuki Iwashima +Acked-by: Joanne Koong +Reviewed-by: Eric Dumazet +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/dccp/ipv4.c | 2 ++ + net/dccp/ipv6.c | 2 ++ + net/ipv4/tcp_ipv4.c | 2 ++ + net/ipv6/tcp_ipv6.c | 2 ++ + 4 files changed, 8 insertions(+) + +diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c +index 2455b0c0e486..a2a8b952b3c5 100644 +--- a/net/dccp/ipv4.c ++++ b/net/dccp/ipv4.c +@@ -130,6 +130,8 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) + * This unhashes the socket and releases the local port, if necessary. + */ + dccp_set_state(sk, DCCP_CLOSED); ++ if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) ++ inet_reset_saddr(sk); + ip_rt_put(rt); + sk->sk_route_caps = 0; + inet->inet_dport = 0; +diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c +index 2be5c69824f9..21c61a9c3b15 100644 +--- a/net/dccp/ipv6.c ++++ b/net/dccp/ipv6.c +@@ -957,6 +957,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, + + late_failure: + dccp_set_state(sk, DCCP_CLOSED); ++ if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) ++ inet_reset_saddr(sk); + __sk_dst_reset(sk); + failure: + inet->inet_dport = 0; +diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c +index 31a8009f74ee..8bd7b1ec3b6a 100644 +--- a/net/ipv4/tcp_ipv4.c ++++ b/net/ipv4/tcp_ipv4.c +@@ -322,6 +322,8 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) + * if necessary. + */ + tcp_set_state(sk, TCP_CLOSE); ++ if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) ++ inet_reset_saddr(sk); + ip_rt_put(rt); + sk->sk_route_caps = 0; + inet->inet_dport = 0; +diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c +index a558dd9d177b..c599e14be414 100644 +--- a/net/ipv6/tcp_ipv6.c ++++ b/net/ipv6/tcp_ipv6.c +@@ -339,6 +339,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, + + late_failure: + tcp_set_state(sk, TCP_CLOSE); ++ if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) ++ inet_reset_saddr(sk); + failure: + inet->inet_dport = 0; + sk->sk_route_caps = 0; +-- +2.35.1 + diff --git a/queue-5.10/dma-buf-fix-racing-conflict-of-dma_heap_add.patch b/queue-5.10/dma-buf-fix-racing-conflict-of-dma_heap_add.patch new file mode 100644 index 00000000000..85e026dc52d --- /dev/null +++ b/queue-5.10/dma-buf-fix-racing-conflict-of-dma_heap_add.patch @@ -0,0 +1,94 @@ +From 64bd8b8fadf3510a769c7bbedd6570e4a8bb63b5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 5 Nov 2022 00:05:36 +0800 +Subject: dma-buf: fix racing conflict of dma_heap_add() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Dawei Li + +[ Upstream commit 432e25902b9651622578c6248e549297d03caf66 ] + +Racing conflict could be: +task A task B +list_for_each_entry +strcmp(h->name)) + list_for_each_entry + strcmp(h->name) +kzalloc kzalloc +...... ..... +device_create device_create +list_add + list_add + +The root cause is that task B has no idea about the fact someone +else(A) has inserted heap with same name when it calls list_add, +so a potential collision occurs. + +Fixes: c02a81fba74f ("dma-buf: Add dma-buf heaps framework") +Signed-off-by: Dawei Li +Acked-by: Andrew Davis +Acked-by: Christian König +Signed-off-by: Sumit Semwal +Link: https://patchwork.freedesktop.org/patch/msgid/TYCP286MB2323873BBDF88020781FB986CA3B9@TYCP286MB2323.JPNP286.PROD.OUTLOOK.COM +Signed-off-by: Sasha Levin +--- + drivers/dma-buf/dma-heap.c | 28 +++++++++++++++------------- + 1 file changed, 15 insertions(+), 13 deletions(-) + +diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c +index 798f86fcd50f..dcbb023acc45 100644 +--- a/drivers/dma-buf/dma-heap.c ++++ b/drivers/dma-buf/dma-heap.c +@@ -209,18 +209,6 @@ struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info) + return ERR_PTR(-EINVAL); + } + +- /* check the name is unique */ +- mutex_lock(&heap_list_lock); +- list_for_each_entry(h, &heap_list, list) { +- if (!strcmp(h->name, exp_info->name)) { +- mutex_unlock(&heap_list_lock); +- pr_err("dma_heap: Already registered heap named %s\n", +- exp_info->name); +- return ERR_PTR(-EINVAL); +- } +- } +- mutex_unlock(&heap_list_lock); +- + heap = kzalloc(sizeof(*heap), GFP_KERNEL); + if (!heap) + return ERR_PTR(-ENOMEM); +@@ -259,13 +247,27 @@ struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info) + err_ret = ERR_CAST(dev_ret); + goto err2; + } +- /* Add heap to the list */ ++ + mutex_lock(&heap_list_lock); ++ /* check the name is unique */ ++ list_for_each_entry(h, &heap_list, list) { ++ if (!strcmp(h->name, exp_info->name)) { ++ mutex_unlock(&heap_list_lock); ++ pr_err("dma_heap: Already registered heap named %s\n", ++ exp_info->name); ++ err_ret = ERR_PTR(-EINVAL); ++ goto err3; ++ } ++ } ++ ++ /* Add heap to the list */ + list_add(&heap->list, &heap_list); + mutex_unlock(&heap_list_lock); + + return heap; + ++err3: ++ device_destroy(dma_heap_class, heap->heap_devt); + err2: + cdev_del(&heap->heap_cdev); + err1: +-- +2.35.1 + diff --git a/queue-5.10/drivers-hv-vmbus-fix-double-free-in-the-error-path-o.patch b/queue-5.10/drivers-hv-vmbus-fix-double-free-in-the-error-path-o.patch new file mode 100644 index 00000000000..572ccfc5a12 --- /dev/null +++ b/queue-5.10/drivers-hv-vmbus-fix-double-free-in-the-error-path-o.patch @@ -0,0 +1,53 @@ +From 6025421ca85abab7f2086cea90628aeafc70e1a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 19 Nov 2022 16:11:34 +0800 +Subject: Drivers: hv: vmbus: fix double free in the error path of + vmbus_add_channel_work() + +From: Yang Yingliang + +[ Upstream commit f92a4b50f0bd7fd52391dc4bb9a309085d278f91 ] + +In the error path of vmbus_device_register(), device_unregister() +is called, which calls vmbus_device_release(). The latter frees +the struct hv_device that was passed in to vmbus_device_register(). +So remove the kfree() in vmbus_add_channel_work() to avoid a double +free. + +Fixes: c2e5df616e1a ("vmbus: add per-channel sysfs info") +Suggested-by: Michael Kelley +Signed-off-by: Yang Yingliang +Reviewed-by: Michael Kelley +Link: https://lore.kernel.org/r/20221119081135.1564691-2-yangyingliang@huawei.com +Signed-off-by: Wei Liu +Signed-off-by: Sasha Levin +--- + drivers/hv/channel_mgmt.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c +index 10188b1a6a08..5b902adb0d1b 100644 +--- a/drivers/hv/channel_mgmt.c ++++ b/drivers/hv/channel_mgmt.c +@@ -501,13 +501,17 @@ static void vmbus_add_channel_work(struct work_struct *work) + * Add the new device to the bus. This will kick off device-driver + * binding which eventually invokes the device driver's AddDevice() + * method. ++ * ++ * If vmbus_device_register() fails, the 'device_obj' is freed in ++ * vmbus_device_release() as called by device_unregister() in the ++ * error path of vmbus_device_register(). In the outside error ++ * path, there's no need to free it. + */ + ret = vmbus_device_register(newchannel->device_obj); + + if (ret != 0) { + pr_err("unable to add child device object (relid %d)\n", + newchannel->offermsg.child_relid); +- kfree(newchannel->device_obj); + goto err_deq_chan; + } + +-- +2.35.1 + diff --git a/queue-5.10/drivers-hv-vmbus-fix-possible-memory-leak-in-vmbus_d.patch b/queue-5.10/drivers-hv-vmbus-fix-possible-memory-leak-in-vmbus_d.patch new file mode 100644 index 00000000000..84ca9276fbb --- /dev/null +++ b/queue-5.10/drivers-hv-vmbus-fix-possible-memory-leak-in-vmbus_d.patch @@ -0,0 +1,41 @@ +From 03d5a04b5544eed8451c718779c50b7fcae8d3b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 19 Nov 2022 16:11:35 +0800 +Subject: Drivers: hv: vmbus: fix possible memory leak in + vmbus_device_register() + +From: Yang Yingliang + +[ Upstream commit 25c94b051592c010abe92c85b0485f1faedc83f3 ] + +If device_register() returns error in vmbus_device_register(), +the name allocated by dev_set_name() must be freed. As comment +of device_register() says, it should use put_device() to give +up the reference in the error path. So fix this by calling +put_device(), then the name can be freed in kobject_cleanup(). + +Fixes: 09d50ff8a233 ("Staging: hv: make the Hyper-V virtual bus code build") +Signed-off-by: Yang Yingliang +Reviewed-by: Michael Kelley +Link: https://lore.kernel.org/r/20221119081135.1564691-3-yangyingliang@huawei.com +Signed-off-by: Wei Liu +Signed-off-by: Sasha Levin +--- + drivers/hv/vmbus_drv.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c +index 514279dac7cb..e99400f3ae1d 100644 +--- a/drivers/hv/vmbus_drv.c ++++ b/drivers/hv/vmbus_drv.c +@@ -2020,6 +2020,7 @@ int vmbus_device_register(struct hv_device *child_device_obj) + ret = device_register(&child_device_obj->device); + if (ret) { + pr_err("Unable to register child device\n"); ++ put_device(&child_device_obj->device); + return ret; + } + +-- +2.35.1 + diff --git a/queue-5.10/ipv4-fix-error-return-code-in-fib_table_insert.patch b/queue-5.10/ipv4-fix-error-return-code-in-fib_table_insert.patch new file mode 100644 index 00000000000..0e7d5148df7 --- /dev/null +++ b/queue-5.10/ipv4-fix-error-return-code-in-fib_table_insert.patch @@ -0,0 +1,40 @@ +From 47620873c09233dc021f8cf8b5754592bbbdf182 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 20 Nov 2022 15:28:38 +0800 +Subject: ipv4: Fix error return code in fib_table_insert() + +From: Ziyang Xuan + +[ Upstream commit 568fe84940ac0e4e0b2cd7751b8b4911f7b9c215 ] + +In fib_table_insert(), if the alias was already inserted, but node not +exist, the error code should be set before return from error handling path. + +Fixes: a6c76c17df02 ("ipv4: Notify route after insertion to the routing table") +Signed-off-by: Ziyang Xuan +Link: https://lore.kernel.org/r/20221120072838.2167047-1-william.xuanziyang@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/ipv4/fib_trie.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c +index a28f525e2c47..d11fb16234a6 100644 +--- a/net/ipv4/fib_trie.c ++++ b/net/ipv4/fib_trie.c +@@ -1331,8 +1331,10 @@ int fib_table_insert(struct net *net, struct fib_table *tb, + + /* The alias was already inserted, so the node must exist. */ + l = l ? l : fib_find_node(t, &tp, key); +- if (WARN_ON_ONCE(!l)) ++ if (WARN_ON_ONCE(!l)) { ++ err = -ENOENT; + goto out_free_new_fa; ++ } + + if (fib_find_alias(&l->leaf, new_fa->fa_slen, 0, 0, tb->tb_id, true) == + new_fa) { +-- +2.35.1 + diff --git a/queue-5.10/macsec-fix-invalid-error-code-set.patch b/queue-5.10/macsec-fix-invalid-error-code-set.patch new file mode 100644 index 00000000000..a40b66c5067 --- /dev/null +++ b/queue-5.10/macsec-fix-invalid-error-code-set.patch @@ -0,0 +1,38 @@ +From aa374db2847c666b99dc80ce82d25779414f4686 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 18 Nov 2022 09:12:49 +0800 +Subject: macsec: Fix invalid error code set + +From: YueHaibing + +[ Upstream commit 7cef6b73fba96abef731a53501924fc3c4a0f947 ] + +'ret' is defined twice in macsec_changelink(), when it is set in macsec_is_offloaded +case, it will be invalid before return. + +Fixes: 3cf3227a21d1 ("net: macsec: hardware offloading infrastructure") +Signed-off-by: YueHaibing +Reviewed-by: Saeed Mahameed +Reviewed-by: Antoine Tenart +Link: https://lore.kernel.org/r/20221118011249.48112-1-yuehaibing@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/macsec.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c +index c20ebf44acfe..3e564158c401 100644 +--- a/drivers/net/macsec.c ++++ b/drivers/net/macsec.c +@@ -3813,7 +3813,6 @@ static int macsec_changelink(struct net_device *dev, struct nlattr *tb[], + if (macsec_is_offloaded(macsec)) { + const struct macsec_ops *ops; + struct macsec_context ctx; +- int ret; + + ops = macsec_get_ops(netdev_priv(dev), &ctx); + if (!ops) { +-- +2.35.1 + diff --git a/queue-5.10/net-arcnet-fix-reset-flag-handling.patch b/queue-5.10/net-arcnet-fix-reset-flag-handling.patch new file mode 100644 index 00000000000..5e427d7827b --- /dev/null +++ b/queue-5.10/net-arcnet-fix-reset-flag-handling.patch @@ -0,0 +1,315 @@ +From c5aad92f3798965fce938cefb4e6d0bdc5029657 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 Jan 2021 20:48:02 +0100 +Subject: net: arcnet: Fix RESET flag handling + +From: Ahmed S. Darwish + +[ Upstream commit 01365633bd1c836240f9bbf86bbeee749795480a ] + +The main arcnet interrupt handler calls arcnet_close() then +arcnet_open(), if the RESET status flag is encountered. + +This is invalid: + + 1) In general, interrupt handlers should never call ->ndo_stop() and + ->ndo_open() functions. They are usually full of blocking calls and + other methods that are expected to be called only from drivers + init and exit code paths. + + 2) arcnet_close() contains a del_timer_sync(). If the irq handler + interrupts the to-be-deleted timer, del_timer_sync() will just loop + forever. + + 3) arcnet_close() also calls tasklet_kill(), which has a warning if + called from irq context. + + 4) For device reset, the sequence "arcnet_close(); arcnet_open();" is + not complete. Some children arcnet drivers have special init/exit + code sequences, which then embed a call to arcnet_open() and + arcnet_close() accordingly. Check drivers/net/arcnet/com20020.c. + +Run the device RESET sequence from a scheduled workqueue instead. + +Signed-off-by: Ahmed S. Darwish +Signed-off-by: Sebastian Andrzej Siewior +Link: https://lore.kernel.org/r/20210128194802.727770-1-a.darwish@linutronix.de +Signed-off-by: Jakub Kicinski +Stable-dep-of: 1c40cde6b517 ("arcnet: fix potential memory leak in com20020_probe()") +Signed-off-by: Sasha Levin +--- + drivers/net/arcnet/arc-rimi.c | 4 +- + drivers/net/arcnet/arcdevice.h | 6 +++ + drivers/net/arcnet/arcnet.c | 66 +++++++++++++++++++++++++++++-- + drivers/net/arcnet/com20020-isa.c | 4 +- + drivers/net/arcnet/com20020-pci.c | 2 +- + drivers/net/arcnet/com20020_cs.c | 2 +- + drivers/net/arcnet/com90io.c | 4 +- + drivers/net/arcnet/com90xx.c | 4 +- + 8 files changed, 78 insertions(+), 14 deletions(-) + +diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c +index 98df38fe553c..12d085405bd0 100644 +--- a/drivers/net/arcnet/arc-rimi.c ++++ b/drivers/net/arcnet/arc-rimi.c +@@ -332,7 +332,7 @@ static int __init arc_rimi_init(void) + dev->irq = 9; + + if (arcrimi_probe(dev)) { +- free_netdev(dev); ++ free_arcdev(dev); + return -EIO; + } + +@@ -349,7 +349,7 @@ static void __exit arc_rimi_exit(void) + iounmap(lp->mem_start); + release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); + free_irq(dev->irq, dev); +- free_netdev(dev); ++ free_arcdev(dev); + } + + #ifndef MODULE +diff --git a/drivers/net/arcnet/arcdevice.h b/drivers/net/arcnet/arcdevice.h +index 22a49c6d7ae6..5d4a4c7efbbf 100644 +--- a/drivers/net/arcnet/arcdevice.h ++++ b/drivers/net/arcnet/arcdevice.h +@@ -298,6 +298,10 @@ struct arcnet_local { + + int excnak_pending; /* We just got an excesive nak interrupt */ + ++ /* RESET flag handling */ ++ int reset_in_progress; ++ struct work_struct reset_work; ++ + struct { + uint16_t sequence; /* sequence number (incs with each packet) */ + __be16 aborted_seq; +@@ -350,7 +354,9 @@ void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc) + + void arcnet_unregister_proto(struct ArcProto *proto); + irqreturn_t arcnet_interrupt(int irq, void *dev_id); ++ + struct net_device *alloc_arcdev(const char *name); ++void free_arcdev(struct net_device *dev); + + int arcnet_open(struct net_device *dev); + int arcnet_close(struct net_device *dev); +diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c +index e04efc0a5c97..d76dd7d14299 100644 +--- a/drivers/net/arcnet/arcnet.c ++++ b/drivers/net/arcnet/arcnet.c +@@ -387,10 +387,44 @@ static void arcnet_timer(struct timer_list *t) + struct arcnet_local *lp = from_timer(lp, t, timer); + struct net_device *dev = lp->dev; + +- if (!netif_carrier_ok(dev)) { ++ spin_lock_irq(&lp->lock); ++ ++ if (!lp->reset_in_progress && !netif_carrier_ok(dev)) { + netif_carrier_on(dev); + netdev_info(dev, "link up\n"); + } ++ ++ spin_unlock_irq(&lp->lock); ++} ++ ++static void reset_device_work(struct work_struct *work) ++{ ++ struct arcnet_local *lp; ++ struct net_device *dev; ++ ++ lp = container_of(work, struct arcnet_local, reset_work); ++ dev = lp->dev; ++ ++ /* Do not bring the network interface back up if an ifdown ++ * was already done. ++ */ ++ if (!netif_running(dev) || !lp->reset_in_progress) ++ return; ++ ++ rtnl_lock(); ++ ++ /* Do another check, in case of an ifdown that was triggered in ++ * the small race window between the exit condition above and ++ * acquiring RTNL. ++ */ ++ if (!netif_running(dev) || !lp->reset_in_progress) ++ goto out; ++ ++ dev_close(dev); ++ dev_open(dev, NULL); ++ ++out: ++ rtnl_unlock(); + } + + static void arcnet_reply_tasklet(unsigned long data) +@@ -452,12 +486,25 @@ struct net_device *alloc_arcdev(const char *name) + lp->dev = dev; + spin_lock_init(&lp->lock); + timer_setup(&lp->timer, arcnet_timer, 0); ++ INIT_WORK(&lp->reset_work, reset_device_work); + } + + return dev; + } + EXPORT_SYMBOL(alloc_arcdev); + ++void free_arcdev(struct net_device *dev) ++{ ++ struct arcnet_local *lp = netdev_priv(dev); ++ ++ /* Do not cancel this at ->ndo_close(), as the workqueue itself ++ * indirectly calls the ifdown path through dev_close(). ++ */ ++ cancel_work_sync(&lp->reset_work); ++ free_netdev(dev); ++} ++EXPORT_SYMBOL(free_arcdev); ++ + /* Open/initialize the board. This is called sometime after booting when + * the 'ifconfig' program is run. + * +@@ -587,6 +634,10 @@ int arcnet_close(struct net_device *dev) + + /* shut down the card */ + lp->hw.close(dev); ++ ++ /* reset counters */ ++ lp->reset_in_progress = 0; ++ + module_put(lp->hw.owner); + return 0; + } +@@ -820,6 +871,9 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) + + spin_lock_irqsave(&lp->lock, flags); + ++ if (lp->reset_in_progress) ++ goto out; ++ + /* RESET flag was enabled - if device is not running, we must + * clear it right away (but nothing else). + */ +@@ -852,11 +906,14 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) + if (status & RESETflag) { + arc_printk(D_NORMAL, dev, "spurious reset (status=%Xh)\n", + status); +- arcnet_close(dev); +- arcnet_open(dev); ++ ++ lp->reset_in_progress = 1; ++ netif_stop_queue(dev); ++ netif_carrier_off(dev); ++ schedule_work(&lp->reset_work); + + /* get out of the interrupt handler! */ +- break; ++ goto out; + } + /* RX is inhibited - we must have received something. + * Prepare to receive into the next buffer. +@@ -1052,6 +1109,7 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) + udelay(1); + lp->hw.intmask(dev, lp->intmask); + ++out: + spin_unlock_irqrestore(&lp->lock, flags); + return retval; + } +diff --git a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c +index f983c4ce6b07..be618e4b9ed5 100644 +--- a/drivers/net/arcnet/com20020-isa.c ++++ b/drivers/net/arcnet/com20020-isa.c +@@ -169,7 +169,7 @@ static int __init com20020_init(void) + dev->irq = 9; + + if (com20020isa_probe(dev)) { +- free_netdev(dev); ++ free_arcdev(dev); + return -EIO; + } + +@@ -182,7 +182,7 @@ static void __exit com20020_exit(void) + unregister_netdev(my_dev); + free_irq(my_dev->irq, my_dev); + release_region(my_dev->base_addr, ARCNET_TOTAL_SIZE); +- free_netdev(my_dev); ++ free_arcdev(my_dev); + } + + #ifndef MODULE +diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c +index 9f44e2e458df..b4f8798d8c50 100644 +--- a/drivers/net/arcnet/com20020-pci.c ++++ b/drivers/net/arcnet/com20020-pci.c +@@ -294,7 +294,7 @@ static void com20020pci_remove(struct pci_dev *pdev) + + unregister_netdev(dev); + free_irq(dev->irq, dev); +- free_netdev(dev); ++ free_arcdev(dev); + } + } + +diff --git a/drivers/net/arcnet/com20020_cs.c b/drivers/net/arcnet/com20020_cs.c +index cf607ffcf358..9cc5eb6a8e90 100644 +--- a/drivers/net/arcnet/com20020_cs.c ++++ b/drivers/net/arcnet/com20020_cs.c +@@ -177,7 +177,7 @@ static void com20020_detach(struct pcmcia_device *link) + dev = info->dev; + if (dev) { + dev_dbg(&link->dev, "kfree...\n"); +- free_netdev(dev); ++ free_arcdev(dev); + } + dev_dbg(&link->dev, "kfree2...\n"); + kfree(info); +diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c +index cf214b730671..3856b447d38e 100644 +--- a/drivers/net/arcnet/com90io.c ++++ b/drivers/net/arcnet/com90io.c +@@ -396,7 +396,7 @@ static int __init com90io_init(void) + err = com90io_probe(dev); + + if (err) { +- free_netdev(dev); ++ free_arcdev(dev); + return err; + } + +@@ -419,7 +419,7 @@ static void __exit com90io_exit(void) + + free_irq(dev->irq, dev); + release_region(dev->base_addr, ARCNET_TOTAL_SIZE); +- free_netdev(dev); ++ free_arcdev(dev); + } + + module_init(com90io_init) +diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c +index 3dc3d533cb19..d8dfb9ea0de8 100644 +--- a/drivers/net/arcnet/com90xx.c ++++ b/drivers/net/arcnet/com90xx.c +@@ -554,7 +554,7 @@ static int __init com90xx_found(int ioaddr, int airq, u_long shmem, + err_release_mem: + release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); + err_free_dev: +- free_netdev(dev); ++ free_arcdev(dev); + return -EIO; + } + +@@ -672,7 +672,7 @@ static void __exit com90xx_exit(void) + release_region(dev->base_addr, ARCNET_TOTAL_SIZE); + release_mem_region(dev->mem_start, + dev->mem_end - dev->mem_start + 1); +- free_netdev(dev); ++ free_arcdev(dev); + } + } + +-- +2.35.1 + diff --git a/queue-5.10/net-enetc-cache-accesses-to-priv-si-hw.patch b/queue-5.10/net-enetc-cache-accesses-to-priv-si-hw.patch new file mode 100644 index 00000000000..1b6f813fffb --- /dev/null +++ b/queue-5.10/net-enetc-cache-accesses-to-priv-si-hw.patch @@ -0,0 +1,376 @@ +From 48f428c226bd8fe7da219fa71b9c2fc343915d80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Sep 2022 12:52:02 +0300 +Subject: net: enetc: cache accesses to &priv->si->hw + +From: Vladimir Oltean + +[ Upstream commit 715bf2610f1d1adf3d4f9b7b3dd729984ec4270a ] + +The &priv->si->hw construct dereferences 2 pointers and makes lines +longer than they need to be, in turn making the code harder to read. + +Replace &priv->si->hw accesses with a "hw" variable when there are 2 or +more accesses within a function that dereference this. This includes +loops, since &priv->si->hw is a loop invariant. + +Signed-off-by: Vladimir Oltean +Signed-off-by: Jakub Kicinski +Stable-dep-of: 290b5fe096e7 ("net: enetc: preserve TX ring priority across reconfiguration") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/enetc/enetc.c | 28 +++++---- + drivers/net/ethernet/freescale/enetc/enetc.h | 9 +-- + .../net/ethernet/freescale/enetc/enetc_qos.c | 60 +++++++++---------- + 3 files changed, 49 insertions(+), 48 deletions(-) + +diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c +index ca62c72eb772..65fa21776a98 100644 +--- a/drivers/net/ethernet/freescale/enetc/enetc.c ++++ b/drivers/net/ethernet/freescale/enetc/enetc.c +@@ -1272,13 +1272,14 @@ static void enetc_setup_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring) + + static void enetc_setup_bdrs(struct enetc_ndev_priv *priv) + { ++ struct enetc_hw *hw = &priv->si->hw; + int i; + + for (i = 0; i < priv->num_tx_rings; i++) +- enetc_setup_txbdr(&priv->si->hw, priv->tx_ring[i]); ++ enetc_setup_txbdr(hw, priv->tx_ring[i]); + + for (i = 0; i < priv->num_rx_rings; i++) +- enetc_setup_rxbdr(&priv->si->hw, priv->rx_ring[i]); ++ enetc_setup_rxbdr(hw, priv->rx_ring[i]); + } + + static void enetc_clear_rxbdr(struct enetc_hw *hw, struct enetc_bdr *rx_ring) +@@ -1311,13 +1312,14 @@ static void enetc_clear_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring) + + static void enetc_clear_bdrs(struct enetc_ndev_priv *priv) + { ++ struct enetc_hw *hw = &priv->si->hw; + int i; + + for (i = 0; i < priv->num_tx_rings; i++) +- enetc_clear_txbdr(&priv->si->hw, priv->tx_ring[i]); ++ enetc_clear_txbdr(hw, priv->tx_ring[i]); + + for (i = 0; i < priv->num_rx_rings; i++) +- enetc_clear_rxbdr(&priv->si->hw, priv->rx_ring[i]); ++ enetc_clear_rxbdr(hw, priv->rx_ring[i]); + + udelay(1); + } +@@ -1325,13 +1327,13 @@ static void enetc_clear_bdrs(struct enetc_ndev_priv *priv) + static int enetc_setup_irqs(struct enetc_ndev_priv *priv) + { + struct pci_dev *pdev = priv->si->pdev; ++ struct enetc_hw *hw = &priv->si->hw; + int i, j, err; + + for (i = 0; i < priv->bdr_int_num; i++) { + int irq = pci_irq_vector(pdev, ENETC_BDR_INT_BASE_IDX + i); + struct enetc_int_vector *v = priv->int_vector[i]; + int entry = ENETC_BDR_INT_BASE_IDX + i; +- struct enetc_hw *hw = &priv->si->hw; + + snprintf(v->name, sizeof(v->name), "%s-rxtx%d", + priv->ndev->name, i); +@@ -1419,13 +1421,14 @@ static void enetc_setup_interrupts(struct enetc_ndev_priv *priv) + + static void enetc_clear_interrupts(struct enetc_ndev_priv *priv) + { ++ struct enetc_hw *hw = &priv->si->hw; + int i; + + for (i = 0; i < priv->num_tx_rings; i++) +- enetc_txbdr_wr(&priv->si->hw, i, ENETC_TBIER, 0); ++ enetc_txbdr_wr(hw, i, ENETC_TBIER, 0); + + for (i = 0; i < priv->num_rx_rings; i++) +- enetc_rxbdr_wr(&priv->si->hw, i, ENETC_RBIER, 0); ++ enetc_rxbdr_wr(hw, i, ENETC_RBIER, 0); + } + + static int enetc_phylink_connect(struct net_device *ndev) +@@ -1565,6 +1568,7 @@ static int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data) + { + struct enetc_ndev_priv *priv = netdev_priv(ndev); + struct tc_mqprio_qopt *mqprio = type_data; ++ struct enetc_hw *hw = &priv->si->hw; + struct enetc_bdr *tx_ring; + u8 num_tc; + int i; +@@ -1579,7 +1583,7 @@ static int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data) + /* Reset all ring priorities to 0 */ + for (i = 0; i < priv->num_tx_rings; i++) { + tx_ring = priv->tx_ring[i]; +- enetc_set_bdr_prio(&priv->si->hw, tx_ring->index, 0); ++ enetc_set_bdr_prio(hw, tx_ring->index, 0); + } + + return 0; +@@ -1598,7 +1602,7 @@ static int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data) + */ + for (i = 0; i < num_tc; i++) { + tx_ring = priv->tx_ring[i]; +- enetc_set_bdr_prio(&priv->si->hw, tx_ring->index, i); ++ enetc_set_bdr_prio(hw, tx_ring->index, i); + } + + /* Reset the number of netdev queues based on the TC count */ +@@ -1679,19 +1683,21 @@ static int enetc_set_rss(struct net_device *ndev, int en) + static void enetc_enable_rxvlan(struct net_device *ndev, bool en) + { + struct enetc_ndev_priv *priv = netdev_priv(ndev); ++ struct enetc_hw *hw = &priv->si->hw; + int i; + + for (i = 0; i < priv->num_rx_rings; i++) +- enetc_bdr_enable_rxvlan(&priv->si->hw, i, en); ++ enetc_bdr_enable_rxvlan(hw, i, en); + } + + static void enetc_enable_txvlan(struct net_device *ndev, bool en) + { + struct enetc_ndev_priv *priv = netdev_priv(ndev); ++ struct enetc_hw *hw = &priv->si->hw; + int i; + + for (i = 0; i < priv->num_tx_rings; i++) +- enetc_bdr_enable_txvlan(&priv->si->hw, i, en); ++ enetc_bdr_enable_txvlan(hw, i, en); + } + + void enetc_set_features(struct net_device *ndev, netdev_features_t features) +diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h +index 00386c5d3cde..38d8ea48b931 100644 +--- a/drivers/net/ethernet/freescale/enetc/enetc.h ++++ b/drivers/net/ethernet/freescale/enetc/enetc.h +@@ -338,19 +338,20 @@ int enetc_set_psfp(struct net_device *ndev, bool en); + + static inline void enetc_get_max_cap(struct enetc_ndev_priv *priv) + { ++ struct enetc_hw *hw = &priv->si->hw; + u32 reg; + +- reg = enetc_port_rd(&priv->si->hw, ENETC_PSIDCAPR); ++ reg = enetc_port_rd(hw, ENETC_PSIDCAPR); + priv->psfp_cap.max_streamid = reg & ENETC_PSIDCAPR_MSK; + /* Port stream filter capability */ +- reg = enetc_port_rd(&priv->si->hw, ENETC_PSFCAPR); ++ reg = enetc_port_rd(hw, ENETC_PSFCAPR); + priv->psfp_cap.max_psfp_filter = reg & ENETC_PSFCAPR_MSK; + /* Port stream gate capability */ +- reg = enetc_port_rd(&priv->si->hw, ENETC_PSGCAPR); ++ reg = enetc_port_rd(hw, ENETC_PSGCAPR); + priv->psfp_cap.max_psfp_gate = (reg & ENETC_PSGCAPR_SGIT_MSK); + priv->psfp_cap.max_psfp_gatelist = (reg & ENETC_PSGCAPR_GCL_MSK) >> 16; + /* Port flow meter capability */ +- reg = enetc_port_rd(&priv->si->hw, ENETC_PFMCAPR); ++ reg = enetc_port_rd(hw, ENETC_PFMCAPR); + priv->psfp_cap.max_psfp_meter = reg & ENETC_PFMCAPR_MSK; + } + +diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c +index b0e278e1f4ad..d3a6367548a1 100644 +--- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c ++++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c +@@ -17,8 +17,9 @@ static u16 enetc_get_max_gcl_len(struct enetc_hw *hw) + + void enetc_sched_speed_set(struct enetc_ndev_priv *priv, int speed) + { ++ struct enetc_hw *hw = &priv->si->hw; + u32 old_speed = priv->speed; +- u32 pspeed; ++ u32 pspeed, tmp; + + if (speed == old_speed) + return; +@@ -39,16 +40,15 @@ void enetc_sched_speed_set(struct enetc_ndev_priv *priv, int speed) + } + + priv->speed = speed; +- enetc_port_wr(&priv->si->hw, ENETC_PMR, +- (enetc_port_rd(&priv->si->hw, ENETC_PMR) +- & (~ENETC_PMR_PSPEED_MASK)) +- | pspeed); ++ tmp = enetc_port_rd(hw, ENETC_PMR); ++ enetc_port_wr(hw, ENETC_PMR, (tmp & ~ENETC_PMR_PSPEED_MASK) | pspeed); + } + + static int enetc_setup_taprio(struct net_device *ndev, + struct tc_taprio_qopt_offload *admin_conf) + { + struct enetc_ndev_priv *priv = netdev_priv(ndev); ++ struct enetc_hw *hw = &priv->si->hw; + struct enetc_cbd cbd = {.cmd = 0}; + struct tgs_gcl_conf *gcl_config; + struct tgs_gcl_data *gcl_data; +@@ -60,15 +60,13 @@ static int enetc_setup_taprio(struct net_device *ndev, + int err; + int i; + +- if (admin_conf->num_entries > enetc_get_max_gcl_len(&priv->si->hw)) ++ if (admin_conf->num_entries > enetc_get_max_gcl_len(hw)) + return -EINVAL; + gcl_len = admin_conf->num_entries; + +- tge = enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET); ++ tge = enetc_rd(hw, ENETC_QBV_PTGCR_OFFSET); + if (!admin_conf->enable) { +- enetc_wr(&priv->si->hw, +- ENETC_QBV_PTGCR_OFFSET, +- tge & (~ENETC_QBV_TGE)); ++ enetc_wr(hw, ENETC_QBV_PTGCR_OFFSET, tge & ~ENETC_QBV_TGE); + + priv->active_offloads &= ~ENETC_F_QBV; + +@@ -126,14 +124,11 @@ static int enetc_setup_taprio(struct net_device *ndev, + cbd.cls = BDCR_CMD_PORT_GCL; + cbd.status_flags = 0; + +- enetc_wr(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET, +- tge | ENETC_QBV_TGE); ++ enetc_wr(hw, ENETC_QBV_PTGCR_OFFSET, tge | ENETC_QBV_TGE); + + err = enetc_send_cmd(priv->si, &cbd); + if (err) +- enetc_wr(&priv->si->hw, +- ENETC_QBV_PTGCR_OFFSET, +- tge & (~ENETC_QBV_TGE)); ++ enetc_wr(hw, ENETC_QBV_PTGCR_OFFSET, tge & ~ENETC_QBV_TGE); + + dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE); + kfree(gcl_data); +@@ -148,6 +143,7 @@ int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data) + { + struct tc_taprio_qopt_offload *taprio = type_data; + struct enetc_ndev_priv *priv = netdev_priv(ndev); ++ struct enetc_hw *hw = &priv->si->hw; + int err; + int i; + +@@ -157,16 +153,14 @@ int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data) + return -EBUSY; + + for (i = 0; i < priv->num_tx_rings; i++) +- enetc_set_bdr_prio(&priv->si->hw, +- priv->tx_ring[i]->index, ++ enetc_set_bdr_prio(hw, priv->tx_ring[i]->index, + taprio->enable ? i : 0); + + err = enetc_setup_taprio(ndev, taprio); + + if (err) + for (i = 0; i < priv->num_tx_rings; i++) +- enetc_set_bdr_prio(&priv->si->hw, +- priv->tx_ring[i]->index, ++ enetc_set_bdr_prio(hw, priv->tx_ring[i]->index, + taprio->enable ? 0 : i); + + return err; +@@ -188,7 +182,7 @@ int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data) + struct tc_cbs_qopt_offload *cbs = type_data; + u32 port_transmit_rate = priv->speed; + u8 tc_nums = netdev_get_num_tc(ndev); +- struct enetc_si *si = priv->si; ++ struct enetc_hw *hw = &priv->si->hw; + u32 hi_credit_bit, hi_credit_reg; + u32 max_interference_size; + u32 port_frame_max_size; +@@ -209,15 +203,15 @@ int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data) + * lower than this TC have been disabled. + */ + if (tc == prio_top && +- enetc_get_cbs_enable(&si->hw, prio_next)) { ++ enetc_get_cbs_enable(hw, prio_next)) { + dev_err(&ndev->dev, + "Disable TC%d before disable TC%d\n", + prio_next, tc); + return -EINVAL; + } + +- enetc_port_wr(&si->hw, ENETC_PTCCBSR1(tc), 0); +- enetc_port_wr(&si->hw, ENETC_PTCCBSR0(tc), 0); ++ enetc_port_wr(hw, ENETC_PTCCBSR1(tc), 0); ++ enetc_port_wr(hw, ENETC_PTCCBSR0(tc), 0); + + return 0; + } +@@ -234,13 +228,13 @@ int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data) + * higher than this TC have been enabled. + */ + if (tc == prio_next) { +- if (!enetc_get_cbs_enable(&si->hw, prio_top)) { ++ if (!enetc_get_cbs_enable(hw, prio_top)) { + dev_err(&ndev->dev, + "Enable TC%d first before enable TC%d\n", + prio_top, prio_next); + return -EINVAL; + } +- bw_sum += enetc_get_cbs_bw(&si->hw, prio_top); ++ bw_sum += enetc_get_cbs_bw(hw, prio_top); + } + + if (bw_sum + bw >= 100) { +@@ -249,7 +243,7 @@ int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data) + return -EINVAL; + } + +- enetc_port_rd(&si->hw, ENETC_PTCMSDUR(tc)); ++ enetc_port_rd(hw, ENETC_PTCMSDUR(tc)); + + /* For top prio TC, the max_interfrence_size is maxSizedFrame. + * +@@ -269,8 +263,8 @@ int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data) + u32 m0, ma, r0, ra; + + m0 = port_frame_max_size * 8; +- ma = enetc_port_rd(&si->hw, ENETC_PTCMSDUR(prio_top)) * 8; +- ra = enetc_get_cbs_bw(&si->hw, prio_top) * ++ ma = enetc_port_rd(hw, ENETC_PTCMSDUR(prio_top)) * 8; ++ ra = enetc_get_cbs_bw(hw, prio_top) * + port_transmit_rate * 10000ULL; + r0 = port_transmit_rate * 1000000ULL; + max_interference_size = m0 + ma + +@@ -290,10 +284,10 @@ int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data) + hi_credit_reg = (u32)div_u64((ENETC_CLK * 100ULL) * hi_credit_bit, + port_transmit_rate * 1000000ULL); + +- enetc_port_wr(&si->hw, ENETC_PTCCBSR1(tc), hi_credit_reg); ++ enetc_port_wr(hw, ENETC_PTCCBSR1(tc), hi_credit_reg); + + /* Set bw register and enable this traffic class */ +- enetc_port_wr(&si->hw, ENETC_PTCCBSR0(tc), bw | ENETC_CBSE); ++ enetc_port_wr(hw, ENETC_PTCCBSR0(tc), bw | ENETC_CBSE); + + return 0; + } +@@ -303,6 +297,7 @@ int enetc_setup_tc_txtime(struct net_device *ndev, void *type_data) + struct enetc_ndev_priv *priv = netdev_priv(ndev); + struct tc_etf_qopt_offload *qopt = type_data; + u8 tc_nums = netdev_get_num_tc(ndev); ++ struct enetc_hw *hw = &priv->si->hw; + int tc; + + if (!tc_nums) +@@ -318,12 +313,11 @@ int enetc_setup_tc_txtime(struct net_device *ndev, void *type_data) + return -EBUSY; + + /* TSD and Qbv are mutually exclusive in hardware */ +- if (enetc_rd(&priv->si->hw, ENETC_QBV_PTGCR_OFFSET) & ENETC_QBV_TGE) ++ if (enetc_rd(hw, ENETC_QBV_PTGCR_OFFSET) & ENETC_QBV_TGE) + return -EBUSY; + + priv->tx_ring[tc]->tsd_enable = qopt->enable; +- enetc_port_wr(&priv->si->hw, ENETC_PTCTSDR(tc), +- qopt->enable ? ENETC_TSDE : 0); ++ enetc_port_wr(hw, ENETC_PTCTSDR(tc), qopt->enable ? ENETC_TSDE : 0); + + return 0; + } +-- +2.35.1 + diff --git a/queue-5.10/net-enetc-manage-enetc_f_qbv-in-priv-active_offloads.patch b/queue-5.10/net-enetc-manage-enetc_f_qbv-in-priv-active_offloads.patch new file mode 100644 index 00000000000..4c7722e9154 --- /dev/null +++ b/queue-5.10/net-enetc-manage-enetc_f_qbv-in-priv-active_offloads.patch @@ -0,0 +1,88 @@ +From 4b2e7d57332fcdb8693dc59f3862767d2f70a901 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 May 2022 19:36:14 +0300 +Subject: net: enetc: manage ENETC_F_QBV in priv->active_offloads only when + enabled + +From: Vladimir Oltean + +[ Upstream commit 32bf8e1f6fb9f6dc334b2b98dffc2e5dcd51e513 ] + +Future work in this driver would like to look at priv->active_offloads & +ENETC_F_QBV to determine whether a tc-taprio qdisc offload was +installed, but this does not produce the intended effect. + +All the other flags in priv->active_offloads are managed dynamically, +except ENETC_F_QBV which is set statically based on the probed SI capability. + +This change makes priv->active_offloads & ENETC_F_QBV really track the +presence of a tc-taprio schedule on the port. + +Some existing users, like the enetc_sched_speed_set() call from +phylink_mac_link_up(), are best kept using the old logic: the tc-taprio +offload does not re-trigger another link mode resolve, so the scheduler +needs to be functional from the get go, as long as Qbv is supported at +all on the port. So to preserve functionality there, look at the static +station interface capability from pf->si->hw_features instead. + +Signed-off-by: Vladimir Oltean +Reviewed-by: Claudiu Manoil +Signed-off-by: Jakub Kicinski +Stable-dep-of: 290b5fe096e7 ("net: enetc: preserve TX ring priority across reconfiguration") +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/enetc/enetc_pf.c | 6 ++---- + drivers/net/ethernet/freescale/enetc/enetc_qos.c | 6 ++++++ + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c +index 6904e10dd46b..515db7e6e649 100644 +--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c ++++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c +@@ -748,9 +748,6 @@ static void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev, + + ndev->priv_flags |= IFF_UNICAST_FLT; + +- if (si->hw_features & ENETC_SI_F_QBV) +- priv->active_offloads |= ENETC_F_QBV; +- + if (si->hw_features & ENETC_SI_F_PSFP && !enetc_psfp_enable(priv)) { + priv->active_offloads |= ENETC_F_QCI; + ndev->features |= NETIF_F_HW_TC; +@@ -996,7 +993,8 @@ static void enetc_pl_mac_link_up(struct phylink_config *config, + struct enetc_ndev_priv *priv; + + priv = netdev_priv(pf->si->ndev); +- if (priv->active_offloads & ENETC_F_QBV) ++ ++ if (pf->si->hw_features & ENETC_SI_F_QBV) + enetc_sched_speed_set(priv, speed); + + if (!phylink_autoneg_inband(mode) && +diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c +index 62efe1aebf86..b0e278e1f4ad 100644 +--- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c ++++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c +@@ -69,6 +69,9 @@ static int enetc_setup_taprio(struct net_device *ndev, + enetc_wr(&priv->si->hw, + ENETC_QBV_PTGCR_OFFSET, + tge & (~ENETC_QBV_TGE)); ++ ++ priv->active_offloads &= ~ENETC_F_QBV; ++ + return 0; + } + +@@ -135,6 +138,9 @@ static int enetc_setup_taprio(struct net_device *ndev, + dma_unmap_single(&priv->si->pdev->dev, dma, data_size, DMA_TO_DEVICE); + kfree(gcl_data); + ++ if (!err) ++ priv->active_offloads |= ENETC_F_QBV; ++ + return err; + } + +-- +2.35.1 + diff --git a/queue-5.10/net-enetc-preserve-tx-ring-priority-across-reconfigu.patch b/queue-5.10/net-enetc-preserve-tx-ring-priority-across-reconfigu.patch new file mode 100644 index 00000000000..b7aecbfd1ff --- /dev/null +++ b/queue-5.10/net-enetc-preserve-tx-ring-priority-across-reconfigu.patch @@ -0,0 +1,126 @@ +From 8ea1b78147593ac4caabfc6028c29e2d87d5c4d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 22 Nov 2022 15:09:36 +0200 +Subject: net: enetc: preserve TX ring priority across reconfiguration + +From: Vladimir Oltean + +[ Upstream commit 290b5fe096e7dd0aad730d1af4f7f2d9fea43e11 ] + +In the blamed commit, a rudimentary reallocation procedure for RX buffer +descriptors was implemented, for the situation when their format changes +between normal (no PTP) and extended (PTP). + +enetc_hwtstamp_set() calls enetc_close() and enetc_open() in a sequence, +and this sequence loses information which was previously configured in +the TX BDR Mode Register, specifically via the enetc_set_bdr_prio() call. +The TX ring priority is configured by tc-mqprio and tc-taprio, and +affects important things for TSN such as the TX time of packets. The +issue manifests itself most visibly by the fact that isochron --txtime +reports premature packet transmissions when PTP is first enabled on an +enetc interface. + +Save the TX ring priority in a new field in struct enetc_bdr (occupies a +2 byte hole on arm64) in order to make this survive a ring reconfiguration. + +Fixes: 434cebabd3a2 ("enetc: Add dynamic allocation of extended Rx BD rings") +Signed-off-by: Vladimir Oltean +Reviewed-by: Alexander Lobakin +Link: https://lore.kernel.org/r/20221122130936.1704151-1-vladimir.oltean@nxp.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/freescale/enetc/enetc.c | 8 ++++--- + drivers/net/ethernet/freescale/enetc/enetc.h | 1 + + .../net/ethernet/freescale/enetc/enetc_qos.c | 21 ++++++++++++------- + 3 files changed, 19 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c +index 65fa21776a98..975762ccb66f 100644 +--- a/drivers/net/ethernet/freescale/enetc/enetc.c ++++ b/drivers/net/ethernet/freescale/enetc/enetc.c +@@ -1212,7 +1212,7 @@ static void enetc_setup_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring) + /* enable Tx ints by setting pkt thr to 1 */ + enetc_txbdr_wr(hw, idx, ENETC_TBICR0, ENETC_TBICR0_ICEN | 0x1); + +- tbmr = ENETC_TBMR_EN; ++ tbmr = ENETC_TBMR_EN | ENETC_TBMR_SET_PRIO(tx_ring->prio); + if (tx_ring->ndev->features & NETIF_F_HW_VLAN_CTAG_TX) + tbmr |= ENETC_TBMR_VIH; + +@@ -1583,7 +1583,8 @@ static int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data) + /* Reset all ring priorities to 0 */ + for (i = 0; i < priv->num_tx_rings; i++) { + tx_ring = priv->tx_ring[i]; +- enetc_set_bdr_prio(hw, tx_ring->index, 0); ++ tx_ring->prio = 0; ++ enetc_set_bdr_prio(hw, tx_ring->index, tx_ring->prio); + } + + return 0; +@@ -1602,7 +1603,8 @@ static int enetc_setup_tc_mqprio(struct net_device *ndev, void *type_data) + */ + for (i = 0; i < num_tc; i++) { + tx_ring = priv->tx_ring[i]; +- enetc_set_bdr_prio(hw, tx_ring->index, i); ++ tx_ring->prio = i; ++ enetc_set_bdr_prio(hw, tx_ring->index, tx_ring->prio); + } + + /* Reset the number of netdev queues based on the TC count */ +diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h +index 38d8ea48b931..725c3d1cbb19 100644 +--- a/drivers/net/ethernet/freescale/enetc/enetc.h ++++ b/drivers/net/ethernet/freescale/enetc/enetc.h +@@ -58,6 +58,7 @@ struct enetc_bdr { + void __iomem *rcir; + }; + u16 index; ++ u16 prio; + int bd_count; /* # of BDs */ + int next_to_use; + int next_to_clean; +diff --git a/drivers/net/ethernet/freescale/enetc/enetc_qos.c b/drivers/net/ethernet/freescale/enetc/enetc_qos.c +index d3a6367548a1..5841721c8119 100644 +--- a/drivers/net/ethernet/freescale/enetc/enetc_qos.c ++++ b/drivers/net/ethernet/freescale/enetc/enetc_qos.c +@@ -144,6 +144,7 @@ int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data) + struct tc_taprio_qopt_offload *taprio = type_data; + struct enetc_ndev_priv *priv = netdev_priv(ndev); + struct enetc_hw *hw = &priv->si->hw; ++ struct enetc_bdr *tx_ring; + int err; + int i; + +@@ -152,16 +153,20 @@ int enetc_setup_tc_taprio(struct net_device *ndev, void *type_data) + if (priv->tx_ring[i]->tsd_enable) + return -EBUSY; + +- for (i = 0; i < priv->num_tx_rings; i++) +- enetc_set_bdr_prio(hw, priv->tx_ring[i]->index, +- taprio->enable ? i : 0); ++ for (i = 0; i < priv->num_tx_rings; i++) { ++ tx_ring = priv->tx_ring[i]; ++ tx_ring->prio = taprio->enable ? i : 0; ++ enetc_set_bdr_prio(hw, tx_ring->index, tx_ring->prio); ++ } + + err = enetc_setup_taprio(ndev, taprio); +- +- if (err) +- for (i = 0; i < priv->num_tx_rings; i++) +- enetc_set_bdr_prio(hw, priv->tx_ring[i]->index, +- taprio->enable ? 0 : i); ++ if (err) { ++ for (i = 0; i < priv->num_tx_rings; i++) { ++ tx_ring = priv->tx_ring[i]; ++ tx_ring->prio = taprio->enable ? 0 : i; ++ enetc_set_bdr_prio(hw, tx_ring->index, tx_ring->prio); ++ } ++ } + + return err; + } +-- +2.35.1 + diff --git a/queue-5.10/net-ethernet-mtk_eth_soc-fix-error-handling-in-mtk_o.patch b/queue-5.10/net-ethernet-mtk_eth_soc-fix-error-handling-in-mtk_o.patch new file mode 100644 index 00000000000..f2e431dacda --- /dev/null +++ b/queue-5.10/net-ethernet-mtk_eth_soc-fix-error-handling-in-mtk_o.patch @@ -0,0 +1,41 @@ +From baf89c96ebe44778cbb9251e70cb981ea3ba08b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Nov 2022 19:13:56 +0800 +Subject: net: ethernet: mtk_eth_soc: fix error handling in mtk_open() + +From: Liu Jian + +[ Upstream commit f70074140524c59a0935947b06dd6cb6e1ea642d ] + +If mtk_start_dma() fails, invoke phylink_disconnect_phy() to perform +cleanup. phylink_disconnect_phy() contains the put_device action. If +phylink_disconnect_phy is not performed, the Kref of netdev will leak. + +Fixes: b8fc9f30821e ("net: ethernet: mediatek: Add basic PHYLINK support") +Signed-off-by: Liu Jian +Reviewed-by: Russell King (Oracle) +Link: https://lore.kernel.org/r/20221117111356.161547-1-liujian56@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +index c7aff89141e1..217dc67c48fa 100644 +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -2299,7 +2299,10 @@ static int mtk_open(struct net_device *dev) + int err = mtk_start_dma(eth); + + if (err) ++ if (err) { ++ phylink_disconnect_phy(mac->phylink); + return err; ++ } + + mtk_gdm_config(eth, MTK_GDMA_TO_PDMA); + +-- +2.35.1 + diff --git a/queue-5.10/net-liquidio-simplify-if-expression.patch b/queue-5.10/net-liquidio-simplify-if-expression.patch new file mode 100644 index 00000000000..ac0167ba9ab --- /dev/null +++ b/queue-5.10/net-liquidio-simplify-if-expression.patch @@ -0,0 +1,50 @@ +From 34a509622fa824bddf6959b16b2ea16fd3d8adb7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 15 Nov 2022 19:34:39 +0200 +Subject: net: liquidio: simplify if expression + +From: Leon Romanovsky + +[ Upstream commit 733d4bbf9514890eb53ebe75827bf1fb4fd25ebe ] + +Fix the warning reported by kbuild: + +cocci warnings: (new ones prefixed by >>) +>> drivers/net/ethernet/cavium/liquidio/lio_main.c:1797:54-56: WARNING !A || A && B is equivalent to !A || B + drivers/net/ethernet/cavium/liquidio/lio_main.c:1827:54-56: WARNING !A || A && B is equivalent to !A || B + +Fixes: 8979f428a4af ("net: liquidio: release resources when liquidio driver open failed") +Reported-by: kernel test robot +Signed-off-by: Leon Romanovsky +Reviewed-by: Saeed Mahameed +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cavium/liquidio/lio_main.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c +index c4dc6e2ccd6b..eefb25bcf57f 100644 +--- a/drivers/net/ethernet/cavium/liquidio/lio_main.c ++++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c +@@ -1798,7 +1798,7 @@ static int liquidio_open(struct net_device *netdev) + + ifstate_set(lio, LIO_IFSTATE_RUNNING); + +- if (!OCTEON_CN23XX_PF(oct) || (OCTEON_CN23XX_PF(oct) && !oct->msix_on)) { ++ if (!OCTEON_CN23XX_PF(oct) || !oct->msix_on) { + ret = setup_tx_poll_fn(netdev); + if (ret) + goto err_poll; +@@ -1828,7 +1828,7 @@ static int liquidio_open(struct net_device *netdev) + return 0; + + err_rx_ctrl: +- if (!OCTEON_CN23XX_PF(oct) || (OCTEON_CN23XX_PF(oct) && !oct->msix_on)) ++ if (!OCTEON_CN23XX_PF(oct) || !oct->msix_on) + cleanup_tx_poll_fn(netdev); + err_poll: + if (lio->ptp_clock) { +-- +2.35.1 + diff --git a/queue-5.10/net-mlx4-check-retval-of-mlx4_bitmap_init.patch b/queue-5.10/net-mlx4-check-retval-of-mlx4_bitmap_init.patch new file mode 100644 index 00000000000..05db33e1c68 --- /dev/null +++ b/queue-5.10/net-mlx4-check-retval-of-mlx4_bitmap_init.patch @@ -0,0 +1,43 @@ +From 8fd291d7e84345d485c0801faa0f8c5568707f6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Nov 2022 18:28:06 +0300 +Subject: net/mlx4: Check retval of mlx4_bitmap_init + +From: Peter Kosyh + +[ Upstream commit 594c61ffc77de0a197934aa0f1df9285c68801c6 ] + +If mlx4_bitmap_init fails, mlx4_bitmap_alloc_range will dereference +the NULL pointer (bitmap->table). + +Make sure, that mlx4_bitmap_alloc_range called in no error case. + +Found by Linux Verification Center (linuxtesting.org) with SVACE. + +Fixes: d57febe1a478 ("net/mlx4: Add A0 hybrid steering") +Reviewed-by: Tariq Toukan +Signed-off-by: Peter Kosyh +Link: https://lore.kernel.org/r/20221117152806.278072-1-pkosyh@yandex.ru +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx4/qp.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c +index 427e7a31862c..d7f2890c254f 100644 +--- a/drivers/net/ethernet/mellanox/mlx4/qp.c ++++ b/drivers/net/ethernet/mellanox/mlx4/qp.c +@@ -697,7 +697,8 @@ static int mlx4_create_zones(struct mlx4_dev *dev, + err = mlx4_bitmap_init(*bitmap + k, 1, + MLX4_QP_TABLE_RAW_ETH_SIZE - 1, 0, + 0); +- mlx4_bitmap_alloc_range(*bitmap + k, 1, 1, 0); ++ if (!err) ++ mlx4_bitmap_alloc_range(*bitmap + k, 1, 1, 0); + } + + if (err) +-- +2.35.1 + diff --git a/queue-5.10/net-mlx5-fix-fw-tracer-timestamp-calculation.patch b/queue-5.10/net-mlx5-fix-fw-tracer-timestamp-calculation.patch new file mode 100644 index 00000000000..fe4eb55ebc7 --- /dev/null +++ b/queue-5.10/net-mlx5-fix-fw-tracer-timestamp-calculation.patch @@ -0,0 +1,38 @@ +From 6cf195be76d4a4e2738136884398655e904154d0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Oct 2022 12:25:59 +0300 +Subject: net/mlx5: Fix FW tracer timestamp calculation + +From: Moshe Shemesh + +[ Upstream commit 61db3d7b99a367416e489ccf764cc5f9b00d62a1 ] + +Fix a bug in calculation of FW tracer timestamp. Decreasing one in the +calculation should effect only bits 52_7 and not effect bits 6_0 of the +timestamp, otherwise bits 6_0 are always set in this calculation. + +Fixes: 70dd6fdb8987 ("net/mlx5: FW tracer, parse traces and kernel tracing support") +Signed-off-by: Moshe Shemesh +Reviewed-by: Feras Daoud +Signed-off-by: Saeed Mahameed +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c +index e8a4adccd2b2..f800e1ca5ba6 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/diag/fw_tracer.c +@@ -638,7 +638,7 @@ static void mlx5_tracer_handle_timestamp_trace(struct mlx5_fw_tracer *tracer, + trace_timestamp = (timestamp_event.timestamp & MASK_52_7) | + (str_frmt->timestamp & MASK_6_0); + else +- trace_timestamp = ((timestamp_event.timestamp & MASK_52_7) - 1) | ++ trace_timestamp = ((timestamp_event.timestamp - 1) & MASK_52_7) | + (str_frmt->timestamp & MASK_6_0); + + mlx5_tracer_print_trace(str_frmt, dev, trace_timestamp); +-- +2.35.1 + diff --git a/queue-5.10/net-mlx5-fix-handling-of-entry-refcount-when-command.patch b/queue-5.10/net-mlx5-fix-handling-of-entry-refcount-when-command.patch new file mode 100644 index 00000000000..97890ea16e5 --- /dev/null +++ b/queue-5.10/net-mlx5-fix-handling-of-entry-refcount-when-command.patch @@ -0,0 +1,62 @@ +From 7753bfe929372bcbc2010a72cf5dd418b25a9084 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Nov 2022 09:07:20 +0200 +Subject: net/mlx5: Fix handling of entry refcount when command is not issued + to FW + +From: Moshe Shemesh + +[ Upstream commit aaf2e65cac7f2e1ae729c2fbc849091df9699f96 ] + +In case command interface is down, or the command is not allowed, driver +did not increment the entry refcount, but might have decrement as part +of forced completion handling. + +Fix that by always increment and decrement the refcount to make it +symmetric for all flows. + +Fixes: 50b2412b7e78 ("net/mlx5: Avoid possible free of command entry while timeout comp handler") +Signed-off-by: Eran Ben Elisha +Signed-off-by: Moshe Shemesh +Reported-by: Jack Wang +Tested-by: Jack Wang +Signed-off-by: Saeed Mahameed +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/mellanox/mlx5/core/cmd.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +index cf07318048df..c838d8698eab 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +@@ -959,6 +959,7 @@ static void cmd_work_handler(struct work_struct *work) + cmd_ent_get(ent); + set_bit(MLX5_CMD_ENT_STATE_PENDING_COMP, &ent->state); + ++ cmd_ent_get(ent); /* for the _real_ FW event on completion */ + /* Skip sending command to fw if internal error */ + if (mlx5_cmd_is_down(dev) || !opcode_allowed(&dev->cmd, ent->op)) { + u8 status = 0; +@@ -972,7 +973,6 @@ static void cmd_work_handler(struct work_struct *work) + return; + } + +- cmd_ent_get(ent); /* for the _real_ FW event on completion */ + /* ring doorbell after the descriptor is valid */ + mlx5_core_dbg(dev, "writing 0x%x to command doorbell\n", 1 << ent->idx); + wmb(); +@@ -1586,8 +1586,8 @@ static void mlx5_cmd_comp_handler(struct mlx5_core_dev *dev, u64 vec, bool force + cmd_ent_put(ent); /* timeout work was canceled */ + + if (!forced || /* Real FW completion */ +- pci_channel_offline(dev->pdev) || /* FW is inaccessible */ +- dev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) ++ mlx5_cmd_is_down(dev) || /* No real FW completion is expected */ ++ !opcode_allowed(cmd, ent->op)) + cmd_ent_put(ent); + + ent->ts2 = ktime_get_ns(); +-- +2.35.1 + diff --git a/queue-5.10/net-pch_gbe-fix-pci-device-refcount-leak-while-modul.patch b/queue-5.10/net-pch_gbe-fix-pci-device-refcount-leak-while-modul.patch new file mode 100644 index 00000000000..33026dd5586 --- /dev/null +++ b/queue-5.10/net-pch_gbe-fix-pci-device-refcount-leak-while-modul.patch @@ -0,0 +1,60 @@ +From ac63d2b152cd201443e584c9f5b614f020b913c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Nov 2022 21:51:48 +0800 +Subject: net: pch_gbe: fix pci device refcount leak while module exiting + +From: Yang Yingliang + +[ Upstream commit 5619537284f1017e9f6c7500b02b859b3830a06d ] + +As comment of pci_get_domain_bus_and_slot() says, it returns +a pci device with refcount increment, when finish using it, +the caller must decrement the reference count by calling +pci_dev_put(). + +In pch_gbe_probe(), pci_get_domain_bus_and_slot() is called, +so in error path in probe() and remove() function, pci_dev_put() +should be called to avoid refcount leak. Compile tested only. + +Fixes: 1a0bdadb4e36 ("net/pch_gbe: supports eg20t ptp clock") +Signed-off-by: Yang Yingliang +Link: https://lore.kernel.org/r/20221117135148.301014-1-yangyingliang@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +index 3361166e56de..bde32f0845ca 100644 +--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c ++++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +@@ -2482,6 +2482,7 @@ static void pch_gbe_remove(struct pci_dev *pdev) + unregister_netdev(netdev); + + pch_gbe_phy_hw_reset(&adapter->hw); ++ pci_dev_put(adapter->ptp_pdev); + + free_netdev(netdev); + } +@@ -2563,7 +2564,7 @@ static int pch_gbe_probe(struct pci_dev *pdev, + /* setup the private structure */ + ret = pch_gbe_sw_init(adapter); + if (ret) +- goto err_free_netdev; ++ goto err_put_dev; + + /* Initialize PHY */ + ret = pch_gbe_init_phy(adapter); +@@ -2621,6 +2622,8 @@ static int pch_gbe_probe(struct pci_dev *pdev, + + err_free_adapter: + pch_gbe_phy_hw_reset(&adapter->hw); ++err_put_dev: ++ pci_dev_put(adapter->ptp_pdev); + err_free_netdev: + free_netdev(netdev); + return ret; +-- +2.35.1 + diff --git a/queue-5.10/net-pch_gbe-fix-potential-memleak-in-pch_gbe_tx_queu.patch b/queue-5.10/net-pch_gbe-fix-potential-memleak-in-pch_gbe_tx_queu.patch new file mode 100644 index 00000000000..b03af4609e4 --- /dev/null +++ b/queue-5.10/net-pch_gbe-fix-potential-memleak-in-pch_gbe_tx_queu.patch @@ -0,0 +1,38 @@ +From c3499a97d78e22098dcb417a94cb8f5c215bcb4b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Nov 2022 14:55:27 +0800 +Subject: net: pch_gbe: fix potential memleak in pch_gbe_tx_queue() + +From: Wang Hai + +[ Upstream commit 2360f9b8c4e81d242d4cbf99d630a2fffa681fab ] + +In pch_gbe_xmit_frame(), NETDEV_TX_OK will be returned whether +pch_gbe_tx_queue() sends data successfully or not, so pch_gbe_tx_queue() +needs to free skb before returning. But pch_gbe_tx_queue() returns without +freeing skb in case of dma_map_single() fails. Add dev_kfree_skb_any() +to fix it. + +Fixes: 77555ee72282 ("net: Add Gigabit Ethernet driver of Topcliff PCH") +Signed-off-by: Wang Hai +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +index 2942102efd48..3361166e56de 100644 +--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c ++++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c +@@ -1166,6 +1166,7 @@ static void pch_gbe_tx_queue(struct pch_gbe_adapter *adapter, + buffer_info->dma = 0; + buffer_info->time_stamp = 0; + tx_ring->next_to_use = ring_num; ++ dev_kfree_skb_any(skb); + return; + } + buffer_info->mapped = true; +-- +2.35.1 + diff --git a/queue-5.10/net-qla3xxx-fix-potential-memleak-in-ql3xxx_send.patch b/queue-5.10/net-qla3xxx-fix-potential-memleak-in-ql3xxx_send.patch new file mode 100644 index 00000000000..4631f0007dc --- /dev/null +++ b/queue-5.10/net-qla3xxx-fix-potential-memleak-in-ql3xxx_send.patch @@ -0,0 +1,36 @@ +From 5791817c6675fcda92590dfc46ee3921b23b0c4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Nov 2022 16:50:38 +0800 +Subject: net/qla3xxx: fix potential memleak in ql3xxx_send() + +From: Zhang Changzhong + +[ Upstream commit 62a7311fb96c61d281da9852dbee4712fc8c3277 ] + +The ql3xxx_send() returns NETDEV_TX_OK without freeing skb in error +handling case, add dev_kfree_skb_any() to fix it. + +Fixes: bd36b0ac5d06 ("qla3xxx: Add support for Qlogic 4032 chip.") +Signed-off-by: Zhang Changzhong +Link: https://lore.kernel.org/r/1668675039-21138-1-git-send-email-zhangchangzhong@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/qlogic/qla3xxx.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/qlogic/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c +index 2219e4c59ae6..99fd35a8ca75 100644 +--- a/drivers/net/ethernet/qlogic/qla3xxx.c ++++ b/drivers/net/ethernet/qlogic/qla3xxx.c +@@ -2475,6 +2475,7 @@ static netdev_tx_t ql3xxx_send(struct sk_buff *skb, + skb_shinfo(skb)->nr_frags); + if (tx_cb->seg_count == -1) { + netdev_err(ndev, "%s: invalid segment count!\n", __func__); ++ dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + +-- +2.35.1 + diff --git a/queue-5.10/net-sched-allow-act_ct-to-be-built-without-nf_nat.patch b/queue-5.10/net-sched-allow-act_ct-to-be-built-without-nf_nat.patch new file mode 100644 index 00000000000..26f01f54045 --- /dev/null +++ b/queue-5.10/net-sched-allow-act_ct-to-be-built-without-nf_nat.patch @@ -0,0 +1,40 @@ +From 5642b6cc3e36dc23dd0cf04122992abc6819ba91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 18 Nov 2022 16:33:03 -0500 +Subject: net: sched: allow act_ct to be built without NF_NAT + +From: Xin Long + +[ Upstream commit 8427fd100c7b7793650e212a81e42f1cf124613d ] + +In commit f11fe1dae1c4 ("net/sched: Make NET_ACT_CT depends on NF_NAT"), +it fixed the build failure when NF_NAT is m and NET_ACT_CT is y by +adding depends on NF_NAT for NET_ACT_CT. However, it would also cause +NET_ACT_CT cannot be built without NF_NAT, which is not expected. This +patch fixes it by changing to use "(!NF_NAT || NF_NAT)" as the depend. + +Fixes: f11fe1dae1c4 ("net/sched: Make NET_ACT_CT depends on NF_NAT") +Signed-off-by: Xin Long +Link: https://lore.kernel.org/r/b6386f28d1ba34721795fb776a91cbdabb203447.1668807183.git.lucien.xin@gmail.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/sched/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/sched/Kconfig b/net/sched/Kconfig +index d762e89ab74f..bc4e5da76fa6 100644 +--- a/net/sched/Kconfig ++++ b/net/sched/Kconfig +@@ -976,7 +976,7 @@ config NET_ACT_TUNNEL_KEY + + config NET_ACT_CT + tristate "connection tracking tc action" +- depends on NET_CLS_ACT && NF_CONNTRACK && NF_NAT && NF_FLOW_TABLE ++ depends on NET_CLS_ACT && NF_CONNTRACK && (!NF_NAT || NF_NAT) && NF_FLOW_TABLE + help + Say Y here to allow sending the packets to conntrack module. + +-- +2.35.1 + diff --git a/queue-5.10/net-thunderx-fix-the-acpi-memory-leak.patch b/queue-5.10/net-thunderx-fix-the-acpi-memory-leak.patch new file mode 100644 index 00000000000..d83b7f67c61 --- /dev/null +++ b/queue-5.10/net-thunderx-fix-the-acpi-memory-leak.patch @@ -0,0 +1,41 @@ +From f5373b6276d8065085601bb117fc0f1213c7a465 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 23 Nov 2022 16:22:36 +0800 +Subject: net: thunderx: Fix the ACPI memory leak + +From: Yu Liao + +[ Upstream commit 661e5ebbafd26d9d2e3c749f5cf591e55c7364f5 ] + +The ACPI buffer memory (string.pointer) should be freed as the buffer is +not used after returning from bgx_acpi_match_id(), free it to prevent +memory leak. + +Fixes: 46b903a01c05 ("net, thunder, bgx: Add support to get MAC address from ACPI.") +Signed-off-by: Yu Liao +Link: https://lore.kernel.org/r/20221123082237.1220521-1-liaoyu15@huawei.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/cavium/thunder/thunder_bgx.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c +index 8ff28ed04b7f..f0e48b9373d6 100644 +--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c ++++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c +@@ -1438,8 +1438,10 @@ static acpi_status bgx_acpi_match_id(acpi_handle handle, u32 lvl, + return AE_OK; + } + +- if (strncmp(string.pointer, bgx_sel, 4)) ++ if (strncmp(string.pointer, bgx_sel, 4)) { ++ kfree(string.pointer); + return AE_OK; ++ } + + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + bgx_acpi_register_phy, NULL, bgx, NULL); +-- +2.35.1 + diff --git a/queue-5.10/netfilter-conntrack-fix-data-races-around-ct-mark.patch b/queue-5.10/netfilter-conntrack-fix-data-races-around-ct-mark.patch new file mode 100644 index 00000000000..998c65d55d8 --- /dev/null +++ b/queue-5.10/netfilter-conntrack-fix-data-races-around-ct-mark.patch @@ -0,0 +1,369 @@ +From cbc69fcfccda8fa1523b5e1010a6a0db8e6b9221 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 9 Nov 2022 12:39:07 -0700 +Subject: netfilter: conntrack: Fix data-races around ct mark + +From: Daniel Xu + +[ Upstream commit 52d1aa8b8249ff477aaa38b6f74a8ced780d079c ] + +nf_conn:mark can be read from and written to in parallel. Use +READ_ONCE()/WRITE_ONCE() for reads and writes to prevent unwanted +compiler optimizations. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Signed-off-by: Daniel Xu +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/core/flow_dissector.c | 2 +- + net/ipv4/netfilter/ipt_CLUSTERIP.c | 4 ++-- + net/netfilter/nf_conntrack_core.c | 2 +- + net/netfilter/nf_conntrack_netlink.c | 24 ++++++++++++++---------- + net/netfilter/nf_conntrack_standalone.c | 2 +- + net/netfilter/nft_ct.c | 6 +++--- + net/netfilter/xt_connmark.c | 18 ++++++++++-------- + net/openvswitch/conntrack.c | 8 ++++---- + net/sched/act_connmark.c | 4 ++-- + net/sched/act_ct.c | 8 ++++---- + net/sched/act_ctinfo.c | 6 +++--- + 11 files changed, 45 insertions(+), 39 deletions(-) + +diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c +index ed120828c7e2..b8d082f55718 100644 +--- a/net/core/flow_dissector.c ++++ b/net/core/flow_dissector.c +@@ -263,7 +263,7 @@ skb_flow_dissect_ct(const struct sk_buff *skb, + key->ct_zone = ct->zone.id; + #endif + #if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) +- key->ct_mark = ct->mark; ++ key->ct_mark = READ_ONCE(ct->mark); + #endif + + cl = nf_ct_labels_find(ct); +diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c +index 1088564d4dbc..77e3b67e8790 100644 +--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c ++++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c +@@ -424,7 +424,7 @@ clusterip_tg(struct sk_buff *skb, const struct xt_action_param *par) + + switch (ctinfo) { + case IP_CT_NEW: +- ct->mark = hash; ++ WRITE_ONCE(ct->mark, hash); + break; + case IP_CT_RELATED: + case IP_CT_RELATED_REPLY: +@@ -441,7 +441,7 @@ clusterip_tg(struct sk_buff *skb, const struct xt_action_param *par) + #ifdef DEBUG + nf_ct_dump_tuple_ip(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + #endif +- pr_debug("hash=%u ct_hash=%u ", hash, ct->mark); ++ pr_debug("hash=%u ct_hash=%u ", hash, READ_ONCE(ct->mark)); + if (!clusterip_responsible(cipinfo->config, hash)) { + pr_debug("not responsible\n"); + return NF_DROP; +diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c +index 8369af0c50ea..193a18bfddc0 100644 +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -1598,7 +1598,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, + } + + #ifdef CONFIG_NF_CONNTRACK_MARK +- ct->mark = exp->master->mark; ++ ct->mark = READ_ONCE(exp->master->mark); + #endif + #ifdef CONFIG_NF_CONNTRACK_SECMARK + ct->secmark = exp->master->secmark; +diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c +index 9e6898164199..c402283e7545 100644 +--- a/net/netfilter/nf_conntrack_netlink.c ++++ b/net/netfilter/nf_conntrack_netlink.c +@@ -317,9 +317,9 @@ ctnetlink_dump_timestamp(struct sk_buff *skb, const struct nf_conn *ct) + } + + #ifdef CONFIG_NF_CONNTRACK_MARK +-static int ctnetlink_dump_mark(struct sk_buff *skb, const struct nf_conn *ct) ++static int ctnetlink_dump_mark(struct sk_buff *skb, u32 mark) + { +- if (nla_put_be32(skb, CTA_MARK, htonl(ct->mark))) ++ if (nla_put_be32(skb, CTA_MARK, htonl(mark))) + goto nla_put_failure; + return 0; + +@@ -532,7 +532,7 @@ static int ctnetlink_dump_extinfo(struct sk_buff *skb, + static int ctnetlink_dump_info(struct sk_buff *skb, struct nf_conn *ct) + { + if (ctnetlink_dump_status(skb, ct) < 0 || +- ctnetlink_dump_mark(skb, ct) < 0 || ++ ctnetlink_dump_mark(skb, READ_ONCE(ct->mark)) < 0 || + ctnetlink_dump_secctx(skb, ct) < 0 || + ctnetlink_dump_id(skb, ct) < 0 || + ctnetlink_dump_use(skb, ct) < 0 || +@@ -711,6 +711,7 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) + struct sk_buff *skb; + unsigned int type; + unsigned int flags = 0, group; ++ u32 mark; + int err; + + if (events & (1 << IPCT_DESTROY)) { +@@ -811,8 +812,9 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) + } + + #ifdef CONFIG_NF_CONNTRACK_MARK +- if ((events & (1 << IPCT_MARK) || ct->mark) +- && ctnetlink_dump_mark(skb, ct) < 0) ++ mark = READ_ONCE(ct->mark); ++ if ((events & (1 << IPCT_MARK) || mark) && ++ ctnetlink_dump_mark(skb, mark) < 0) + goto nla_put_failure; + #endif + nlmsg_end(skb, nlh); +@@ -1099,7 +1101,7 @@ static int ctnetlink_filter_match(struct nf_conn *ct, void *data) + } + + #ifdef CONFIG_NF_CONNTRACK_MARK +- if ((ct->mark & filter->mark.mask) != filter->mark.val) ++ if ((READ_ONCE(ct->mark) & filter->mark.mask) != filter->mark.val) + goto ignore_entry; + #endif + +@@ -1979,9 +1981,9 @@ static void ctnetlink_change_mark(struct nf_conn *ct, + mask = ~ntohl(nla_get_be32(cda[CTA_MARK_MASK])); + + mark = ntohl(nla_get_be32(cda[CTA_MARK])); +- newmark = (ct->mark & mask) ^ mark; +- if (newmark != ct->mark) +- ct->mark = newmark; ++ newmark = (READ_ONCE(ct->mark) & mask) ^ mark; ++ if (newmark != READ_ONCE(ct->mark)) ++ WRITE_ONCE(ct->mark, newmark); + } + #endif + +@@ -2669,6 +2671,7 @@ static int __ctnetlink_glue_build(struct sk_buff *skb, struct nf_conn *ct) + { + const struct nf_conntrack_zone *zone; + struct nlattr *nest_parms; ++ u32 mark; + + zone = nf_ct_zone(ct); + +@@ -2726,7 +2729,8 @@ static int __ctnetlink_glue_build(struct sk_buff *skb, struct nf_conn *ct) + goto nla_put_failure; + + #ifdef CONFIG_NF_CONNTRACK_MARK +- if (ct->mark && ctnetlink_dump_mark(skb, ct) < 0) ++ mark = READ_ONCE(ct->mark); ++ if (mark && ctnetlink_dump_mark(skb, mark) < 0) + goto nla_put_failure; + #endif + if (ctnetlink_dump_labels(skb, ct) < 0) +diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c +index 313d1c8ff066..a7f88cdf3f87 100644 +--- a/net/netfilter/nf_conntrack_standalone.c ++++ b/net/netfilter/nf_conntrack_standalone.c +@@ -360,7 +360,7 @@ static int ct_seq_show(struct seq_file *s, void *v) + goto release; + + #if defined(CONFIG_NF_CONNTRACK_MARK) +- seq_printf(s, "mark=%u ", ct->mark); ++ seq_printf(s, "mark=%u ", READ_ONCE(ct->mark)); + #endif + + ct_show_secctx(s, ct); +diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c +index 781118465d46..14093d86e682 100644 +--- a/net/netfilter/nft_ct.c ++++ b/net/netfilter/nft_ct.c +@@ -97,7 +97,7 @@ static void nft_ct_get_eval(const struct nft_expr *expr, + return; + #ifdef CONFIG_NF_CONNTRACK_MARK + case NFT_CT_MARK: +- *dest = ct->mark; ++ *dest = READ_ONCE(ct->mark); + return; + #endif + #ifdef CONFIG_NF_CONNTRACK_SECMARK +@@ -294,8 +294,8 @@ static void nft_ct_set_eval(const struct nft_expr *expr, + switch (priv->key) { + #ifdef CONFIG_NF_CONNTRACK_MARK + case NFT_CT_MARK: +- if (ct->mark != value) { +- ct->mark = value; ++ if (READ_ONCE(ct->mark) != value) { ++ WRITE_ONCE(ct->mark, value); + nf_conntrack_event_cache(IPCT_MARK, ct); + } + break; +diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c +index e5ebc0810675..ad3c033db64e 100644 +--- a/net/netfilter/xt_connmark.c ++++ b/net/netfilter/xt_connmark.c +@@ -30,6 +30,7 @@ connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info) + u_int32_t new_targetmark; + struct nf_conn *ct; + u_int32_t newmark; ++ u_int32_t oldmark; + + ct = nf_ct_get(skb, &ctinfo); + if (ct == NULL) +@@ -37,14 +38,15 @@ connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info) + + switch (info->mode) { + case XT_CONNMARK_SET: +- newmark = (ct->mark & ~info->ctmask) ^ info->ctmark; ++ oldmark = READ_ONCE(ct->mark); ++ newmark = (oldmark & ~info->ctmask) ^ info->ctmark; + if (info->shift_dir == D_SHIFT_RIGHT) + newmark >>= info->shift_bits; + else + newmark <<= info->shift_bits; + +- if (ct->mark != newmark) { +- ct->mark = newmark; ++ if (READ_ONCE(ct->mark) != newmark) { ++ WRITE_ONCE(ct->mark, newmark); + nf_conntrack_event_cache(IPCT_MARK, ct); + } + break; +@@ -55,15 +57,15 @@ connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info) + else + new_targetmark <<= info->shift_bits; + +- newmark = (ct->mark & ~info->ctmask) ^ ++ newmark = (READ_ONCE(ct->mark) & ~info->ctmask) ^ + new_targetmark; +- if (ct->mark != newmark) { +- ct->mark = newmark; ++ if (READ_ONCE(ct->mark) != newmark) { ++ WRITE_ONCE(ct->mark, newmark); + nf_conntrack_event_cache(IPCT_MARK, ct); + } + break; + case XT_CONNMARK_RESTORE: +- new_targetmark = (ct->mark & info->ctmask); ++ new_targetmark = (READ_ONCE(ct->mark) & info->ctmask); + if (info->shift_dir == D_SHIFT_RIGHT) + new_targetmark >>= info->shift_bits; + else +@@ -126,7 +128,7 @@ connmark_mt(const struct sk_buff *skb, struct xt_action_param *par) + if (ct == NULL) + return false; + +- return ((ct->mark & info->mask) == info->mark) ^ info->invert; ++ return ((READ_ONCE(ct->mark) & info->mask) == info->mark) ^ info->invert; + } + + static int connmark_mt_check(const struct xt_mtchk_param *par) +diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c +index 41f248895a87..0f0f380e81a4 100644 +--- a/net/openvswitch/conntrack.c ++++ b/net/openvswitch/conntrack.c +@@ -150,7 +150,7 @@ static u8 ovs_ct_get_state(enum ip_conntrack_info ctinfo) + static u32 ovs_ct_get_mark(const struct nf_conn *ct) + { + #if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) +- return ct ? ct->mark : 0; ++ return ct ? READ_ONCE(ct->mark) : 0; + #else + return 0; + #endif +@@ -336,9 +336,9 @@ static int ovs_ct_set_mark(struct nf_conn *ct, struct sw_flow_key *key, + #if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) + u32 new_mark; + +- new_mark = ct_mark | (ct->mark & ~(mask)); +- if (ct->mark != new_mark) { +- ct->mark = new_mark; ++ new_mark = ct_mark | (READ_ONCE(ct->mark) & ~(mask)); ++ if (READ_ONCE(ct->mark) != new_mark) { ++ WRITE_ONCE(ct->mark, new_mark); + if (nf_ct_is_confirmed(ct)) + nf_conntrack_event_cache(IPCT_MARK, ct); + key->ct.mark = new_mark; +diff --git a/net/sched/act_connmark.c b/net/sched/act_connmark.c +index e19885d7fe2c..31d268eedf3f 100644 +--- a/net/sched/act_connmark.c ++++ b/net/sched/act_connmark.c +@@ -62,7 +62,7 @@ static int tcf_connmark_act(struct sk_buff *skb, const struct tc_action *a, + + c = nf_ct_get(skb, &ctinfo); + if (c) { +- skb->mark = c->mark; ++ skb->mark = READ_ONCE(c->mark); + /* using overlimits stats to count how many packets marked */ + ca->tcf_qstats.overlimits++; + goto out; +@@ -82,7 +82,7 @@ static int tcf_connmark_act(struct sk_buff *skb, const struct tc_action *a, + c = nf_ct_tuplehash_to_ctrack(thash); + /* using overlimits stats to count how many packets marked */ + ca->tcf_qstats.overlimits++; +- skb->mark = c->mark; ++ skb->mark = READ_ONCE(c->mark); + nf_ct_put(c); + + out: +diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c +index f7e88d7466c3..2d41d866de3e 100644 +--- a/net/sched/act_ct.c ++++ b/net/sched/act_ct.c +@@ -177,7 +177,7 @@ static void tcf_ct_flow_table_add_action_meta(struct nf_conn *ct, + entry = tcf_ct_flow_table_flow_action_get_next(action); + entry->id = FLOW_ACTION_CT_METADATA; + #if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) +- entry->ct_metadata.mark = ct->mark; ++ entry->ct_metadata.mark = READ_ONCE(ct->mark); + #endif + ctinfo = dir == IP_CT_DIR_ORIGINAL ? IP_CT_ESTABLISHED : + IP_CT_ESTABLISHED_REPLY; +@@ -843,9 +843,9 @@ static void tcf_ct_act_set_mark(struct nf_conn *ct, u32 mark, u32 mask) + if (!mask) + return; + +- new_mark = mark | (ct->mark & ~(mask)); +- if (ct->mark != new_mark) { +- ct->mark = new_mark; ++ new_mark = mark | (READ_ONCE(ct->mark) & ~(mask)); ++ if (READ_ONCE(ct->mark) != new_mark) { ++ WRITE_ONCE(ct->mark, new_mark); + if (nf_ct_is_confirmed(ct)) + nf_conntrack_event_cache(IPCT_MARK, ct); + } +diff --git a/net/sched/act_ctinfo.c b/net/sched/act_ctinfo.c +index b20c8ce59905..06c74f22ab98 100644 +--- a/net/sched/act_ctinfo.c ++++ b/net/sched/act_ctinfo.c +@@ -33,7 +33,7 @@ static void tcf_ctinfo_dscp_set(struct nf_conn *ct, struct tcf_ctinfo *ca, + { + u8 dscp, newdscp; + +- newdscp = (((ct->mark & cp->dscpmask) >> cp->dscpmaskshift) << 2) & ++ newdscp = (((READ_ONCE(ct->mark) & cp->dscpmask) >> cp->dscpmaskshift) << 2) & + ~INET_ECN_MASK; + + switch (proto) { +@@ -73,7 +73,7 @@ static void tcf_ctinfo_cpmark_set(struct nf_conn *ct, struct tcf_ctinfo *ca, + struct sk_buff *skb) + { + ca->stats_cpmark_set++; +- skb->mark = ct->mark & cp->cpmarkmask; ++ skb->mark = READ_ONCE(ct->mark) & cp->cpmarkmask; + } + + static int tcf_ctinfo_act(struct sk_buff *skb, const struct tc_action *a, +@@ -131,7 +131,7 @@ static int tcf_ctinfo_act(struct sk_buff *skb, const struct tc_action *a, + } + + if (cp->mode & CTINFO_MODE_DSCP) +- if (!cp->dscpstatemask || (ct->mark & cp->dscpstatemask)) ++ if (!cp->dscpstatemask || (READ_ONCE(ct->mark) & cp->dscpstatemask)) + tcf_ctinfo_dscp_set(ct, ca, cp, skb, wlen, proto); + + if (cp->mode & CTINFO_MODE_CPMARK) +-- +2.35.1 + diff --git a/queue-5.10/netfilter-flowtable_offload-add-missing-locking.patch b/queue-5.10/netfilter-flowtable_offload-add-missing-locking.patch new file mode 100644 index 00000000000..ac436b59709 --- /dev/null +++ b/queue-5.10/netfilter-flowtable_offload-add-missing-locking.patch @@ -0,0 +1,55 @@ +From 91065e7070e453983498e48db6f3a223f6d28487 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 21 Nov 2022 19:26:15 +0100 +Subject: netfilter: flowtable_offload: add missing locking + +From: Felix Fietkau + +[ Upstream commit bcd9e3c1656d0f7dd9743598c65c3ae24efb38d0 ] + +nf_flow_table_block_setup and the driver TC_SETUP_FT call can modify the flow +block cb list while they are being traversed elsewhere, causing a crash. +Add a write lock around the calls to protect readers + +Fixes: c29f74e0df7a ("netfilter: nf_flow_table: hardware offload support") +Reported-by: Chad Monroe +Signed-off-by: Felix Fietkau +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/nf_flow_table_offload.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c +index d1862782be45..28306cb66719 100644 +--- a/net/netfilter/nf_flow_table_offload.c ++++ b/net/netfilter/nf_flow_table_offload.c +@@ -910,6 +910,7 @@ static int nf_flow_table_block_setup(struct nf_flowtable *flowtable, + struct flow_block_cb *block_cb, *next; + int err = 0; + ++ down_write(&flowtable->flow_block_lock); + switch (cmd) { + case FLOW_BLOCK_BIND: + list_splice(&bo->cb_list, &flowtable->flow_block.cb_list); +@@ -924,6 +925,7 @@ static int nf_flow_table_block_setup(struct nf_flowtable *flowtable, + WARN_ON_ONCE(1); + err = -EOPNOTSUPP; + } ++ up_write(&flowtable->flow_block_lock); + + return err; + } +@@ -980,7 +982,9 @@ static int nf_flow_table_offload_cmd(struct flow_block_offload *bo, + + nf_flow_table_block_offload_init(bo, dev_net(dev), cmd, flowtable, + extack); ++ down_write(&flowtable->flow_block_lock); + err = dev->netdev_ops->ndo_setup_tc(dev, TC_SETUP_FT, bo); ++ up_write(&flowtable->flow_block_lock); + if (err < 0) + return err; + +-- +2.35.1 + diff --git a/queue-5.10/netfilter-ipset-limit-the-maximal-range-of-consecuti.patch b/queue-5.10/netfilter-ipset-limit-the-maximal-range-of-consecuti.patch new file mode 100644 index 00000000000..abdbb692bd4 --- /dev/null +++ b/queue-5.10/netfilter-ipset-limit-the-maximal-range-of-consecuti.patch @@ -0,0 +1,310 @@ +From 7109e120fb2c1f2e76b1665364d7d9a4c791852b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jul 2021 17:01:15 +0200 +Subject: netfilter: ipset: Limit the maximal range of consecutive elements to + add/delete + +From: Jozsef Kadlecsik + +[ Upstream commit 5f7b51bf09baca8e4f80cbe879536842bafb5f31 ] + +The range size of consecutive elements were not limited. Thus one could +define a huge range which may result soft lockup errors due to the long +execution time. Now the range size is limited to 2^20 entries. + +Reported-by: Brad Spengler +Signed-off-by: Jozsef Kadlecsik +Signed-off-by: Pablo Neira Ayuso +Stable-dep-of: c7aa1a76d4a0 ("netfilter: ipset: regression in ip_set_hash_ip.c") +Signed-off-by: Sasha Levin +--- + include/linux/netfilter/ipset/ip_set.h | 3 +++ + net/netfilter/ipset/ip_set_hash_ip.c | 9 ++++++++- + net/netfilter/ipset/ip_set_hash_ipmark.c | 10 +++++++++- + net/netfilter/ipset/ip_set_hash_ipport.c | 3 +++ + net/netfilter/ipset/ip_set_hash_ipportip.c | 3 +++ + net/netfilter/ipset/ip_set_hash_ipportnet.c | 3 +++ + net/netfilter/ipset/ip_set_hash_net.c | 11 ++++++++++- + net/netfilter/ipset/ip_set_hash_netiface.c | 10 +++++++++- + net/netfilter/ipset/ip_set_hash_netnet.c | 16 +++++++++++++++- + net/netfilter/ipset/ip_set_hash_netport.c | 11 ++++++++++- + net/netfilter/ipset/ip_set_hash_netportnet.c | 16 +++++++++++++++- + 11 files changed, 88 insertions(+), 7 deletions(-) + +diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h +index ab192720e2d6..53c9a17ecb3e 100644 +--- a/include/linux/netfilter/ipset/ip_set.h ++++ b/include/linux/netfilter/ipset/ip_set.h +@@ -198,6 +198,9 @@ struct ip_set_region { + u32 elements; /* Number of elements vs timeout */ + }; + ++/* Max range where every element is added/deleted in one step */ ++#define IPSET_MAX_RANGE (1<<20) ++ + /* The core set type structure */ + struct ip_set_type { + struct list_head list; +diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c +index 5d6d68eaf6a9..361f4fd69bf4 100644 +--- a/net/netfilter/ipset/ip_set_hash_ip.c ++++ b/net/netfilter/ipset/ip_set_hash_ip.c +@@ -131,8 +131,11 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], + ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); + if (ret) + return ret; +- if (ip > ip_to) ++ if (ip > ip_to) { ++ if (ip_to == 0) ++ return -IPSET_ERR_HASH_ELEM; + swap(ip, ip_to); ++ } + } else if (tb[IPSET_ATTR_CIDR]) { + u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); + +@@ -143,6 +146,10 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], + + hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1); + ++ /* 64bit division is not allowed on 32bit */ ++ if (((u64)ip_to - ip + 1) >> (32 - h->netmask) > IPSET_MAX_RANGE) ++ return -ERANGE; ++ + if (retried) { + ip = ntohl(h->next.ip); + e.ip = htonl(ip); +diff --git a/net/netfilter/ipset/ip_set_hash_ipmark.c b/net/netfilter/ipset/ip_set_hash_ipmark.c +index aba1df617d6e..eefce34a34f0 100644 +--- a/net/netfilter/ipset/ip_set_hash_ipmark.c ++++ b/net/netfilter/ipset/ip_set_hash_ipmark.c +@@ -120,6 +120,8 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[], + + e.mark = ntohl(nla_get_be32(tb[IPSET_ATTR_MARK])); + e.mark &= h->markmask; ++ if (e.mark == 0 && e.ip == 0) ++ return -IPSET_ERR_HASH_ELEM; + + if (adt == IPSET_TEST || + !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR])) { +@@ -132,8 +134,11 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[], + ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); + if (ret) + return ret; +- if (ip > ip_to) ++ if (ip > ip_to) { ++ if (e.mark == 0 && ip_to == 0) ++ return -IPSET_ERR_HASH_ELEM; + swap(ip, ip_to); ++ } + } else if (tb[IPSET_ATTR_CIDR]) { + u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); + +@@ -142,6 +147,9 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[], + ip_set_mask_from_to(ip, ip_to, cidr); + } + ++ if (((u64)ip_to - ip + 1) > IPSET_MAX_RANGE) ++ return -ERANGE; ++ + if (retried) + ip = ntohl(h->next.ip); + for (; ip <= ip_to; ip++) { +diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c +index 1ff228717e29..4a54e9e8ae59 100644 +--- a/net/netfilter/ipset/ip_set_hash_ipport.c ++++ b/net/netfilter/ipset/ip_set_hash_ipport.c +@@ -172,6 +172,9 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], + swap(port, port_to); + } + ++ if (((u64)ip_to - ip + 1)*(port_to - port + 1) > IPSET_MAX_RANGE) ++ return -ERANGE; ++ + if (retried) + ip = ntohl(h->next.ip); + for (; ip <= ip_to; ip++) { +diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c +index fa88afd812fa..09737de5ecc3 100644 +--- a/net/netfilter/ipset/ip_set_hash_ipportip.c ++++ b/net/netfilter/ipset/ip_set_hash_ipportip.c +@@ -179,6 +179,9 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], + swap(port, port_to); + } + ++ if (((u64)ip_to - ip + 1)*(port_to - port + 1) > IPSET_MAX_RANGE) ++ return -ERANGE; ++ + if (retried) + ip = ntohl(h->next.ip); + for (; ip <= ip_to; ip++) { +diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c +index eef6ecfcb409..02685371a682 100644 +--- a/net/netfilter/ipset/ip_set_hash_ipportnet.c ++++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c +@@ -252,6 +252,9 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], + swap(port, port_to); + } + ++ if (((u64)ip_to - ip + 1)*(port_to - port + 1) > IPSET_MAX_RANGE) ++ return -ERANGE; ++ + ip2_to = ip2_from; + if (tb[IPSET_ATTR_IP2_TO]) { + ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to); +diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c +index 136cf0781d3a..9d1beaacb973 100644 +--- a/net/netfilter/ipset/ip_set_hash_net.c ++++ b/net/netfilter/ipset/ip_set_hash_net.c +@@ -139,7 +139,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], + ipset_adtfn adtfn = set->variant->adt[adt]; + struct hash_net4_elem e = { .cidr = HOST_MASK }; + struct ip_set_ext ext = IP_SET_INIT_UEXT(set); +- u32 ip = 0, ip_to = 0; ++ u32 ip = 0, ip_to = 0, ipn, n = 0; + int ret; + + if (tb[IPSET_ATTR_LINENO]) +@@ -187,6 +187,15 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], + if (ip + UINT_MAX == ip_to) + return -IPSET_ERR_HASH_RANGE; + } ++ ipn = ip; ++ do { ++ ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr); ++ n++; ++ } while (ipn++ < ip_to); ++ ++ if (n > IPSET_MAX_RANGE) ++ return -ERANGE; ++ + if (retried) + ip = ntohl(h->next.ip); + do { +diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c +index be5e95a0d876..c3ada9c63fa3 100644 +--- a/net/netfilter/ipset/ip_set_hash_netiface.c ++++ b/net/netfilter/ipset/ip_set_hash_netiface.c +@@ -201,7 +201,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], + ipset_adtfn adtfn = set->variant->adt[adt]; + struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 }; + struct ip_set_ext ext = IP_SET_INIT_UEXT(set); +- u32 ip = 0, ip_to = 0; ++ u32 ip = 0, ip_to = 0, ipn, n = 0; + int ret; + + if (tb[IPSET_ATTR_LINENO]) +@@ -255,6 +255,14 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], + } else { + ip_set_mask_from_to(ip, ip_to, e.cidr); + } ++ ipn = ip; ++ do { ++ ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr); ++ n++; ++ } while (ipn++ < ip_to); ++ ++ if (n > IPSET_MAX_RANGE) ++ return -ERANGE; + + if (retried) + ip = ntohl(h->next.ip); +diff --git a/net/netfilter/ipset/ip_set_hash_netnet.c b/net/netfilter/ipset/ip_set_hash_netnet.c +index da4ef910b12d..b1411bc91a40 100644 +--- a/net/netfilter/ipset/ip_set_hash_netnet.c ++++ b/net/netfilter/ipset/ip_set_hash_netnet.c +@@ -167,7 +167,8 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], + struct hash_netnet4_elem e = { }; + struct ip_set_ext ext = IP_SET_INIT_UEXT(set); + u32 ip = 0, ip_to = 0; +- u32 ip2 = 0, ip2_from = 0, ip2_to = 0; ++ u32 ip2 = 0, ip2_from = 0, ip2_to = 0, ipn; ++ u64 n = 0, m = 0; + int ret; + + if (tb[IPSET_ATTR_LINENO]) +@@ -243,6 +244,19 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], + } else { + ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]); + } ++ ipn = ip; ++ do { ++ ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr[0]); ++ n++; ++ } while (ipn++ < ip_to); ++ ipn = ip2_from; ++ do { ++ ipn = ip_set_range_to_cidr(ipn, ip2_to, &e.cidr[1]); ++ m++; ++ } while (ipn++ < ip2_to); ++ ++ if (n*m > IPSET_MAX_RANGE) ++ return -ERANGE; + + if (retried) { + ip = ntohl(h->next.ip[0]); +diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c +index 34448df80fb9..d26d13528fe8 100644 +--- a/net/netfilter/ipset/ip_set_hash_netport.c ++++ b/net/netfilter/ipset/ip_set_hash_netport.c +@@ -157,7 +157,8 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], + ipset_adtfn adtfn = set->variant->adt[adt]; + struct hash_netport4_elem e = { .cidr = HOST_MASK - 1 }; + struct ip_set_ext ext = IP_SET_INIT_UEXT(set); +- u32 port, port_to, p = 0, ip = 0, ip_to = 0; ++ u32 port, port_to, p = 0, ip = 0, ip_to = 0, ipn; ++ u64 n = 0; + bool with_ports = false; + u8 cidr; + int ret; +@@ -234,6 +235,14 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], + } else { + ip_set_mask_from_to(ip, ip_to, e.cidr + 1); + } ++ ipn = ip; ++ do { ++ ipn = ip_set_range_to_cidr(ipn, ip_to, &cidr); ++ n++; ++ } while (ipn++ < ip_to); ++ ++ if (n*(port_to - port + 1) > IPSET_MAX_RANGE) ++ return -ERANGE; + + if (retried) { + ip = ntohl(h->next.ip); +diff --git a/net/netfilter/ipset/ip_set_hash_netportnet.c b/net/netfilter/ipset/ip_set_hash_netportnet.c +index 934c1712cba8..6446f4fccc72 100644 +--- a/net/netfilter/ipset/ip_set_hash_netportnet.c ++++ b/net/netfilter/ipset/ip_set_hash_netportnet.c +@@ -181,7 +181,8 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[], + struct hash_netportnet4_elem e = { }; + struct ip_set_ext ext = IP_SET_INIT_UEXT(set); + u32 ip = 0, ip_to = 0, p = 0, port, port_to; +- u32 ip2_from = 0, ip2_to = 0, ip2; ++ u32 ip2_from = 0, ip2_to = 0, ip2, ipn; ++ u64 n = 0, m = 0; + bool with_ports = false; + int ret; + +@@ -283,6 +284,19 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[], + } else { + ip_set_mask_from_to(ip2_from, ip2_to, e.cidr[1]); + } ++ ipn = ip; ++ do { ++ ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr[0]); ++ n++; ++ } while (ipn++ < ip_to); ++ ipn = ip2_from; ++ do { ++ ipn = ip_set_range_to_cidr(ipn, ip2_to, &e.cidr[1]); ++ m++; ++ } while (ipn++ < ip2_to); ++ ++ if (n*m*(port_to - port + 1) > IPSET_MAX_RANGE) ++ return -ERANGE; + + if (retried) { + ip = ntohl(h->next.ip[0]); +-- +2.35.1 + diff --git a/queue-5.10/netfilter-ipset-regression-in-ip_set_hash_ip.c.patch b/queue-5.10/netfilter-ipset-regression-in-ip_set_hash_ip.c.patch new file mode 100644 index 00000000000..d242595682d --- /dev/null +++ b/queue-5.10/netfilter-ipset-regression-in-ip_set_hash_ip.c.patch @@ -0,0 +1,66 @@ +From fcc8291b1b239de1b22108c30b0feec08ed5e3a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Sep 2022 14:26:50 -0400 +Subject: netfilter: ipset: regression in ip_set_hash_ip.c + +From: Vishwanath Pai + +[ Upstream commit c7aa1a76d4a0a3c401025b60c401412bbb60f8c6 ] + +This patch introduced a regression: commit 48596a8ddc46 ("netfilter: +ipset: Fix adding an IPv4 range containing more than 2^31 addresses") + +The variable e.ip is passed to adtfn() function which finally adds the +ip address to the set. The patch above refactored the for loop and moved +e.ip = htonl(ip) to the end of the for loop. + +What this means is that if the value of "ip" changes between the first +assignement of e.ip and the forloop, then e.ip is pointing to a +different ip address than "ip". + +Test case: +$ ipset create jdtest_tmp hash:ip family inet hashsize 2048 maxelem 100000 +$ ipset add jdtest_tmp 10.0.1.1/31 +ipset v6.21.1: Element cannot be added to the set: it's already added + +The value of ip gets updated inside the "else if (tb[IPSET_ATTR_CIDR])" +block but e.ip is still pointing to the old value. + +Fixes: 48596a8ddc46 ("netfilter: ipset: Fix adding an IPv4 range containing more than 2^31 addresses") +Reviewed-by: Joshua Hunt +Signed-off-by: Vishwanath Pai +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + net/netfilter/ipset/ip_set_hash_ip.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c +index 361f4fd69bf4..d7a81b2250e7 100644 +--- a/net/netfilter/ipset/ip_set_hash_ip.c ++++ b/net/netfilter/ipset/ip_set_hash_ip.c +@@ -150,18 +150,16 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], + if (((u64)ip_to - ip + 1) >> (32 - h->netmask) > IPSET_MAX_RANGE) + return -ERANGE; + +- if (retried) { ++ if (retried) + ip = ntohl(h->next.ip); +- e.ip = htonl(ip); +- } + for (; ip <= ip_to;) { ++ e.ip = htonl(ip); + ret = adtfn(set, &e, &ext, &ext, flags); + if (ret && !ip_set_eexist(ret, flags)) + return ret; + + ip += hosts; +- e.ip = htonl(ip); +- if (e.ip == 0) ++ if (ip == 0) + return 0; + + ret = 0; +-- +2.35.1 + diff --git a/queue-5.10/nfc-nci-fix-memory-leak-in-nci_rx_data_packet.patch b/queue-5.10/nfc-nci-fix-memory-leak-in-nci_rx_data_packet.patch new file mode 100644 index 00000000000..1975a2cac2f --- /dev/null +++ b/queue-5.10/nfc-nci-fix-memory-leak-in-nci_rx_data_packet.patch @@ -0,0 +1,61 @@ +From 8b77d63ca5e464453c53153d3e934e14f9a03df4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 18 Nov 2022 16:24:19 +0800 +Subject: NFC: nci: fix memory leak in nci_rx_data_packet() + +From: Liu Shixin + +[ Upstream commit 53270fb0fd77fe786d8c07a0793981d797836b93 ] + +Syzbot reported a memory leak about skb: + +unreferenced object 0xffff88810e144e00 (size 240): + comm "syz-executor284", pid 3701, jiffies 4294952403 (age 12.620s) + hex dump (first 32 bytes): + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + backtrace: + [] __alloc_skb+0x1f9/0x270 net/core/skbuff.c:497 + [] alloc_skb include/linux/skbuff.h:1267 [inline] + [] virtual_ncidev_write+0x24/0xe0 drivers/nfc/virtual_ncidev.c:116 + [] do_loop_readv_writev fs/read_write.c:759 [inline] + [] do_loop_readv_writev fs/read_write.c:743 [inline] + [] do_iter_write+0x253/0x300 fs/read_write.c:863 + [] vfs_writev+0xdd/0x240 fs/read_write.c:934 + [] do_writev+0xa6/0x1c0 fs/read_write.c:977 + [] do_syscall_x64 arch/x86/entry/common.c:50 [inline] + [] do_syscall_64+0x35/0xb0 arch/x86/entry/common.c:80 + [] entry_SYSCALL_64_after_hwframe+0x63/0xcd + +In nci_rx_data_packet(), if we don't get a valid conn_info, we will return +directly but forget to release the skb. + +Reported-by: syzbot+cdb9a427d1bc08815104@syzkaller.appspotmail.com +Fixes: 4aeee6871e8c ("NFC: nci: Add dynamic logical connections support") +Signed-off-by: Liu Shixin +Link: https://lore.kernel.org/r/20221118082419.239475-1-liushixin2@huawei.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + net/nfc/nci/data.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c +index b002e18f38c8..b4548d887489 100644 +--- a/net/nfc/nci/data.c ++++ b/net/nfc/nci/data.c +@@ -279,8 +279,10 @@ void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb) + nci_plen(skb->data)); + + conn_info = nci_get_conn_info_by_conn_id(ndev, nci_conn_id(skb->data)); +- if (!conn_info) ++ if (!conn_info) { ++ kfree_skb(skb); + return; ++ } + + /* strip the nci data header */ + skb_pull(skb, NCI_DATA_HDR_SIZE); +-- +2.35.1 + diff --git a/queue-5.10/nfc-nci-fix-race-with-opening-and-closing.patch b/queue-5.10/nfc-nci-fix-race-with-opening-and-closing.patch new file mode 100644 index 00000000000..91cc487956e --- /dev/null +++ b/queue-5.10/nfc-nci-fix-race-with-opening-and-closing.patch @@ -0,0 +1,42 @@ +From 4bf8bd86d4d9a93c6d32ab49a6f0782ff7314232 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Nov 2022 21:02:49 +0800 +Subject: nfc/nci: fix race with opening and closing + +From: Lin Ma + +[ Upstream commit 0ad6bded175e829c2ca261529c9dce39a32a042d ] + +Previously we leverage NCI_UNREG and the lock inside nci_close_device to +prevent the race condition between opening a device and closing a +device. However, it still has problem because a failed opening command +will erase the NCI_UNREG flag and allow another opening command to +bypass the status checking. + +This fix corrects that by making sure the NCI_UNREG is held. + +Reported-by: syzbot+43475bf3cfbd6e41f5b7@syzkaller.appspotmail.com +Fixes: 48b71a9e66c2 ("NFC: add NCI_UNREG flag to eliminate the race") +Signed-off-by: Lin Ma +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/nfc/nci/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c +index 2cfff70f70e0..ed9019d807c7 100644 +--- a/net/nfc/nci/core.c ++++ b/net/nfc/nci/core.c +@@ -530,7 +530,7 @@ static int nci_open_device(struct nci_dev *ndev) + skb_queue_purge(&ndev->tx_q); + + ndev->ops->close(ndev); +- ndev->flags = 0; ++ ndev->flags &= BIT(NCI_UNREG); + } + + done: +-- +2.35.1 + diff --git a/queue-5.10/nfc-st-nci-fix-incorrect-validating-logic-in-evt_tra.patch b/queue-5.10/nfc-st-nci-fix-incorrect-validating-logic-in-evt_tra.patch new file mode 100644 index 00000000000..c2296af39f6 --- /dev/null +++ b/queue-5.10/nfc-st-nci-fix-incorrect-validating-logic-in-evt_tra.patch @@ -0,0 +1,41 @@ +From dea7b336940ce66aca2cd5ecff2eb3ea64428ff8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 21 Nov 2022 18:42:44 -0600 +Subject: nfc: st-nci: fix incorrect validating logic in EVT_TRANSACTION + +From: Martin Faltesek + +[ Upstream commit c60c152230828825c06e62a8f1ce956d4b659266 ] + +The first validation check for EVT_TRANSACTION has two different checks +tied together with logical AND. One is a check for minimum packet length, +and the other is for a valid aid_tag. If either condition is true (fails), +then an error should be triggered. The fix is to change && to ||. + +Reported-by: Denis Efremov +Reviewed-by: Guenter Roeck +Fixes: 5d1ceb7f5e56 ("NFC: st21nfcb: Add HCI transaction event support") +Signed-off-by: Martin Faltesek +Reviewed-by: Krzysztof Kozlowski +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/nfc/st-nci/se.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nfc/st-nci/se.c b/drivers/nfc/st-nci/se.c +index 807eae04c1e3..b1ee5a38f964 100644 +--- a/drivers/nfc/st-nci/se.c ++++ b/drivers/nfc/st-nci/se.c +@@ -327,7 +327,7 @@ static int st_nci_hci_connectivity_event_received(struct nci_dev *ndev, + * AID 81 5 to 16 + * PARAMETERS 82 0 to 255 + */ +- if (skb->len < NFC_MIN_AID_LENGTH + 2 && ++ if (skb->len < NFC_MIN_AID_LENGTH + 2 || + skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG) + return -EPROTO; + +-- +2.35.1 + diff --git a/queue-5.10/nfc-st-nci-fix-memory-leaks-in-evt_transaction.patch b/queue-5.10/nfc-st-nci-fix-memory-leaks-in-evt_transaction.patch new file mode 100644 index 00000000000..9bf4f4d16bb --- /dev/null +++ b/queue-5.10/nfc-st-nci-fix-memory-leaks-in-evt_transaction.patch @@ -0,0 +1,42 @@ +From f1aed4bd4b0a60f0d4082d57eb1bf79b6a80e36a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 21 Nov 2022 18:42:45 -0600 +Subject: nfc: st-nci: fix memory leaks in EVT_TRANSACTION + +From: Martin Faltesek + +[ Upstream commit 440f2ae9c9f06e26f5dcea697a53717fc61a318c ] + +Error path does not free previously allocated memory. Add devm_kfree() to +the failure path. + +Reported-by: Denis Efremov +Reviewed-by: Guenter Roeck +Fixes: 5d1ceb7f5e56 ("NFC: st21nfcb: Add HCI transaction event support") +Signed-off-by: Martin Faltesek +Reviewed-by: Krzysztof Kozlowski +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/nfc/st-nci/se.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/nfc/st-nci/se.c b/drivers/nfc/st-nci/se.c +index b1ee5a38f964..37d397aae9b9 100644 +--- a/drivers/nfc/st-nci/se.c ++++ b/drivers/nfc/st-nci/se.c +@@ -340,8 +340,10 @@ static int st_nci_hci_connectivity_event_received(struct nci_dev *ndev, + + /* Check next byte is PARAMETERS tag (82) */ + if (skb->data[transaction->aid_len + 2] != +- NFC_EVT_TRANSACTION_PARAMS_TAG) ++ NFC_EVT_TRANSACTION_PARAMS_TAG) { ++ devm_kfree(dev, transaction); + return -EPROTO; ++ } + + transaction->params_len = skb->data[transaction->aid_len + 3]; + memcpy(transaction->params, skb->data + +-- +2.35.1 + diff --git a/queue-5.10/nfp-add-port-from-netdev-validation-for-eeprom-acces.patch b/queue-5.10/nfp-add-port-from-netdev-validation-for-eeprom-acces.patch new file mode 100644 index 00000000000..cf58e58913a --- /dev/null +++ b/queue-5.10/nfp-add-port-from-netdev-validation-for-eeprom-acces.patch @@ -0,0 +1,45 @@ +From 6396cc5fc7882c29727b6f8c35fa2ad1327407ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Nov 2022 16:37:44 +0100 +Subject: nfp: add port from netdev validation for EEPROM access + +From: Jaco Coetzee + +[ Upstream commit 0873016d46f6dfafd1bdf4d9b935b3331b226f7c ] + +Setting of the port flag `NFP_PORT_CHANGED`, introduced +to ensure the correct reading of EEPROM data, causes a +fatal kernel NULL pointer dereference in cases where +the target netdev type cannot be determined. + +Add validation of port struct pointer before attempting +to set the `NFP_PORT_CHANGED` flag. Return that operation +is not supported if the netdev type cannot be determined. + +Fixes: 4ae97cae07e1 ("nfp: ethtool: fix the display error of `ethtool -m DEVNAME`") +Signed-off-by: Jaco Coetzee +Reviewed-by: Louis Peens +Signed-off-by: Simon Horman +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +index 3977aa2f59bd..311873ff57e3 100644 +--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c ++++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +@@ -1225,6 +1225,9 @@ nfp_port_get_module_info(struct net_device *netdev, + u8 data; + + port = nfp_port_from_netdev(netdev); ++ if (!port) ++ return -EOPNOTSUPP; ++ + /* update port state to get latest interface */ + set_bit(NFP_PORT_CHANGED, &port->flags); + eth_port = nfp_port_get_eth_port(port); +-- +2.35.1 + diff --git a/queue-5.10/nfp-fill-splittable-of-devlink_port_attrs-correctly.patch b/queue-5.10/nfp-fill-splittable-of-devlink_port_attrs-correctly.patch new file mode 100644 index 00000000000..cd825109cb8 --- /dev/null +++ b/queue-5.10/nfp-fill-splittable-of-devlink_port_attrs-correctly.patch @@ -0,0 +1,48 @@ +From 2bb85c4944bf869e8fa85b5f571eec2cfb8ed8f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Nov 2022 16:37:43 +0100 +Subject: nfp: fill splittable of devlink_port_attrs correctly +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Diana Wang + +[ Upstream commit 4abd9600b9d15d3d92a9ac25cf200422a4c415ee ] + +The error is reflected in that it shows wrong splittable status of +port when executing "devlink port show". +The reason which leads the error is that the assigned operation of +splittable is just a simple negation operation of split and it does +not consider port lanes quantity. A splittable port should have +several lanes that can be split(lanes quantity > 1). +If without the judgement, it will show wrong message for some +firmware, such as 2x25G, 2x10G. + +Fixes: a0f49b548652 ("devlink: Add a new devlink port split ability attribute and pass to netlink") +Signed-off-by: Diana Wang +Reviewed-by: Louis Peens +Reviewed-by: Niklas Söderlund +Signed-off-by: Simon Horman +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/netronome/nfp/nfp_devlink.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c +index 7a8187458724..24578c48f075 100644 +--- a/drivers/net/ethernet/netronome/nfp/nfp_devlink.c ++++ b/drivers/net/ethernet/netronome/nfp/nfp_devlink.c +@@ -363,7 +363,7 @@ int nfp_devlink_port_register(struct nfp_app *app, struct nfp_port *port) + return ret; + + attrs.split = eth_port.is_split; +- attrs.splittable = !attrs.split; ++ attrs.splittable = eth_port.port_lanes > 1 && !attrs.split; + attrs.lanes = eth_port.port_lanes; + attrs.flavour = DEVLINK_PORT_FLAVOUR_PHYSICAL; + attrs.phys.port_number = eth_port.label_port; +-- +2.35.1 + diff --git a/queue-5.10/regulator-core-fix-kobject-release-warning-and-memor.patch b/queue-5.10/regulator-core-fix-kobject-release-warning-and-memor.patch new file mode 100644 index 00000000000..3eab0c59876 --- /dev/null +++ b/queue-5.10/regulator-core-fix-kobject-release-warning-and-memor.patch @@ -0,0 +1,75 @@ +From 3911271e8f9b22d094f574531e5c4714f38f97d4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Nov 2022 15:43:39 +0800 +Subject: regulator: core: fix kobject release warning and memory leak in + regulator_register() + +From: Zeng Heng + +[ Upstream commit 5f4b204b6b8153923d5be8002c5f7082985d153f ] + +Here is a warning report about lack of registered release() +from kobject lib: + +Device '(null)' does not have a release() function, it is broken and must be fixed. +WARNING: CPU: 0 PID: 48430 at drivers/base/core.c:2332 device_release+0x104/0x120 +Call Trace: + kobject_put+0xdc/0x180 + put_device+0x1b/0x30 + regulator_register+0x651/0x1170 + devm_regulator_register+0x4f/0xb0 + +When regulator_register() returns fail and directly goto `clean` symbol, +rdev->dev has not registered release() function yet (which is registered +by regulator_class in the following), so rdev needs to be freed manually. +If rdev->dev.of_node is not NULL, which means the of_node has gotten by +regulator_of_get_init_data(), it needs to call of_node_put() to avoid +refcount leak. + +Otherwise, only calling put_device() would lead memory leak of rdev +in further: + +unreferenced object 0xffff88810d0b1000 (size 2048): + comm "107-i2c-rtq6752", pid 48430, jiffies 4342258431 (age 1341.780s) + backtrace: + kmalloc_trace+0x22/0x110 + regulator_register+0x184/0x1170 + devm_regulator_register+0x4f/0xb0 + +When regulator_register() returns fail and goto `wash` symbol, +rdev->dev has registered release() function, so directly call +put_device() to cleanup everything. + +Fixes: d3c731564e09 ("regulator: plug of_node leak in regulator_register()'s error path") +Signed-off-by: Zeng Heng +Link: https://lore.kernel.org/r/20221116074339.1024240-1-zengheng4@huawei.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/regulator/core.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index bf8ba73d6c7c..f43c668e1630 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -5401,11 +5401,15 @@ regulator_register(const struct regulator_desc *regulator_desc, + mutex_lock(®ulator_list_mutex); + regulator_ena_gpio_free(rdev); + mutex_unlock(®ulator_list_mutex); ++ put_device(&rdev->dev); ++ rdev = NULL; + clean: + if (dangling_of_gpiod) + gpiod_put(config->ena_gpiod); ++ if (rdev && rdev->dev.of_node) ++ of_node_put(rdev->dev.of_node); ++ kfree(rdev); + kfree(config); +- put_device(&rdev->dev); + rinse: + if (dangling_cfg_gpiod) + gpiod_put(cfg->ena_gpiod); +-- +2.35.1 + diff --git a/queue-5.10/regulator-core-fix-uaf-in-destroy_regulator.patch b/queue-5.10/regulator-core-fix-uaf-in-destroy_regulator.patch new file mode 100644 index 00000000000..b473f03b86a --- /dev/null +++ b/queue-5.10/regulator-core-fix-uaf-in-destroy_regulator.patch @@ -0,0 +1,132 @@ +From 2f322fb850194a374c66817c9dc49236e8bc7ea6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Nov 2022 11:37:06 +0800 +Subject: regulator: core: fix UAF in destroy_regulator() + +From: Yang Yingliang + +[ Upstream commit 1f386d6894d0f1b7de8ef640c41622ddd698e7ab ] + +I got a UAF report as following: + +================================================================== +BUG: KASAN: use-after-free in __lock_acquire+0x935/0x2060 +Read of size 8 at addr ffff88810e838220 by task python3/268 +Call Trace: + + dump_stack_lvl+0x67/0x83 + print_report+0x178/0x4b0 + kasan_report+0x90/0x190 + __lock_acquire+0x935/0x2060 + lock_acquire+0x156/0x400 + _raw_spin_lock+0x2a/0x40 + lockref_get+0x11/0x30 + simple_recursive_removal+0x41/0x440 + debugfs_remove.part.12+0x32/0x50 + debugfs_remove+0x29/0x30 + _regulator_put.cold.54+0x3e/0x27f + regulator_put+0x1f/0x30 + release_nodes+0x6a/0xa0 + devres_release_all+0xf8/0x150 + +Allocated by task 37: + kasan_save_stack+0x1c/0x40 + kasan_set_track+0x21/0x30 + __kasan_slab_alloc+0x5d/0x70 + slab_post_alloc_hook+0x62/0x510 + kmem_cache_alloc_lru+0x222/0x5a0 + __d_alloc+0x31/0x440 + d_alloc+0x30/0xf0 + d_alloc_parallel+0xc4/0xd20 + __lookup_slow+0x15e/0x2f0 + lookup_one_len+0x13a/0x150 + start_creating+0xea/0x190 + debugfs_create_dir+0x1e/0x210 + create_regulator+0x254/0x4e0 + _regulator_get+0x2a1/0x467 + _devm_regulator_get+0x5a/0xb0 + regulator_virtual_probe+0xb9/0x1a0 + +Freed by task 30: + kasan_save_stack+0x1c/0x40 + kasan_set_track+0x21/0x30 + kasan_save_free_info+0x2a/0x50 + __kasan_slab_free+0x102/0x190 + kmem_cache_free+0xf6/0x600 + rcu_core+0x54c/0x12b0 + __do_softirq+0xf2/0x5e3 + +Last potentially related work creation: + kasan_save_stack+0x1c/0x40 + __kasan_record_aux_stack+0x98/0xb0 + call_rcu+0x42/0x700 + dentry_free+0x6c/0xd0 + __dentry_kill+0x23b/0x2d0 + dput.part.31+0x431/0x780 + simple_recursive_removal+0xa9/0x440 + debugfs_remove.part.12+0x32/0x50 + debugfs_remove+0x29/0x30 + regulator_unregister+0xe3/0x230 + release_nodes+0x6a/0xa0 + +================================================================== + +Here is how happened: + +processor A processor B +regulator_register() + rdev_init_debugfs() + rdev->debugfs = debugfs_create_dir() + devm_regulator_get() + rdev = regulator_dev_lookup() + create_regulator(rdev) + // using rdev->debugfs as parent + debugfs_create_dir(rdev->debugfs) + +mfd_remove_devices_fn() + release_nodes() + regulator_unregister() + // free rdev->debugfs + debugfs_remove_recursive(rdev->debugfs) + release_nodes() + destroy_regulator() + debugfs_remove_recursive() <- causes UAF + +In devm_regulator_get(), after getting rdev, the refcount +is get, so fix this by moving debugfs_remove_recursive() +to regulator_dev_release(), then it can be proctected by +the refcount, the 'rdev->debugfs' can not be freed until +the refcount is 0. + +Fixes: 5de705194e98 ("regulator: Add basic per consumer debugfs") +Signed-off-by: Yang Yingliang +Link: https://lore.kernel.org/r/20221116033706.3595812-1-yangyingliang@huawei.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/regulator/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c +index f43c668e1630..eb083b26ab4f 100644 +--- a/drivers/regulator/core.c ++++ b/drivers/regulator/core.c +@@ -4928,6 +4928,7 @@ static void regulator_dev_release(struct device *dev) + { + struct regulator_dev *rdev = dev_get_drvdata(dev); + ++ debugfs_remove_recursive(rdev->debugfs); + kfree(rdev->constraints); + of_node_put(rdev->dev.of_node); + kfree(rdev); +@@ -5438,7 +5439,6 @@ void regulator_unregister(struct regulator_dev *rdev) + + mutex_lock(®ulator_list_mutex); + +- debugfs_remove_recursive(rdev->debugfs); + WARN_ON(rdev->open_count); + regulator_remove_coupling(rdev); + unset_regulator_supplies(rdev); +-- +2.35.1 + diff --git a/queue-5.10/regulator-twl6030-re-add-twl6032_subclass.patch b/queue-5.10/regulator-twl6030-re-add-twl6032_subclass.patch new file mode 100644 index 00000000000..d590da926ef --- /dev/null +++ b/queue-5.10/regulator-twl6030-re-add-twl6032_subclass.patch @@ -0,0 +1,47 @@ +From dfd9c4e4e3547419577996400de26c9b4d7cb4f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 20 Nov 2022 23:12:07 +0100 +Subject: regulator: twl6030: re-add TWL6032_SUBCLASS + +From: Andreas Kemnade + +[ Upstream commit 3d6c982b26db94cc21bc9f7784f63e8286b7be62 ] + +In former times, info->feature was populated via the parent driver +by pdata/regulator_init_data->driver_data for all regulators when +USB_PRODUCT_ID_LSB indicates a TWL6032. +Today, the information is not set, so re-add it at the regulator +definitions. + +Fixes: 25d82337705e2 ("regulator: twl: make driver DT only") +Signed-off-by: Andreas Kemnade +Link: https://lore.kernel.org/r/20221120221208.3093727-2-andreas@kemnade.info +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/regulator/twl6030-regulator.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/regulator/twl6030-regulator.c b/drivers/regulator/twl6030-regulator.c +index 430265c404d6..7c7e3648ea4b 100644 +--- a/drivers/regulator/twl6030-regulator.c ++++ b/drivers/regulator/twl6030-regulator.c +@@ -530,6 +530,7 @@ static const struct twlreg_info TWL6030_INFO_##label = { \ + #define TWL6032_ADJUSTABLE_LDO(label, offset) \ + static const struct twlreg_info TWL6032_INFO_##label = { \ + .base = offset, \ ++ .features = TWL6032_SUBCLASS, \ + .desc = { \ + .name = #label, \ + .id = TWL6032_REG_##label, \ +@@ -562,6 +563,7 @@ static const struct twlreg_info TWLFIXED_INFO_##label = { \ + #define TWL6032_ADJUSTABLE_SMPS(label, offset) \ + static const struct twlreg_info TWLSMPS_INFO_##label = { \ + .base = offset, \ ++ .features = TWL6032_SUBCLASS, \ + .desc = { \ + .name = #label, \ + .id = TWL6032_REG_##label, \ +-- +2.35.1 + diff --git a/queue-5.10/rxrpc-allow-list-of-in-use-local-udp-endpoints-to-be.patch b/queue-5.10/rxrpc-allow-list-of-in-use-local-udp-endpoints-to-be.patch new file mode 100644 index 00000000000..756ccf10df8 --- /dev/null +++ b/queue-5.10/rxrpc-allow-list-of-in-use-local-udp-endpoints-to-be.patch @@ -0,0 +1,256 @@ +From bdca983d358d6b731eb8b6daf2792e3a52b35e0e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 May 2022 08:45:15 +0100 +Subject: rxrpc: Allow list of in-use local UDP endpoints to be viewed in /proc + +From: David Howells + +[ Upstream commit 33912c2639ad76660988c8ca97e4d18fca89b668 ] + +Allow the list of in-use local UDP endpoints in the current network +namespace to be viewed in /proc. + +To aid with this, the endpoint list is converted to an hlist and RCU-safe +manipulation is used so that the list can be read with only the RCU +read lock held. + +Signed-off-by: David Howells +cc: Marc Dionne +cc: linux-afs@lists.infradead.org +Signed-off-by: David S. Miller +Stable-dep-of: 3bcd6c7eaa53 ("rxrpc: Fix race between conn bundle lookup and bundle removal [ZDI-CAN-15975]") +Signed-off-by: Sasha Levin +--- + net/rxrpc/ar-internal.h | 5 +-- + net/rxrpc/local_object.c | 37 +++++++++++---------- + net/rxrpc/net_ns.c | 5 ++- + net/rxrpc/proc.c | 69 ++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 94 insertions(+), 22 deletions(-) + +diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h +index ccb65412b670..2d0c797a176a 100644 +--- a/net/rxrpc/ar-internal.h ++++ b/net/rxrpc/ar-internal.h +@@ -86,7 +86,7 @@ struct rxrpc_net { + struct work_struct client_conn_reaper; + struct timer_list client_conn_reap_timer; + +- struct list_head local_endpoints; ++ struct hlist_head local_endpoints; + struct mutex local_mutex; /* Lock for ->local_endpoints */ + + DECLARE_HASHTABLE (peer_hash, 10); +@@ -266,7 +266,7 @@ struct rxrpc_local { + atomic_t active_users; /* Number of users of the local endpoint */ + atomic_t usage; /* Number of references to the structure */ + struct rxrpc_net *rxnet; /* The network ns in which this resides */ +- struct list_head link; ++ struct hlist_node link; + struct socket *socket; /* my UDP socket */ + struct work_struct processor; + struct rxrpc_sock __rcu *service; /* Service(s) listening on this endpoint */ +@@ -1001,6 +1001,7 @@ void rxrpc_put_peer_locked(struct rxrpc_peer *); + extern const struct seq_operations rxrpc_call_seq_ops; + extern const struct seq_operations rxrpc_connection_seq_ops; + extern const struct seq_operations rxrpc_peer_seq_ops; ++extern const struct seq_operations rxrpc_local_seq_ops; + + /* + * recvmsg.c +diff --git a/net/rxrpc/local_object.c b/net/rxrpc/local_object.c +index ebbf1b03b62c..11db28a902f4 100644 +--- a/net/rxrpc/local_object.c ++++ b/net/rxrpc/local_object.c +@@ -81,7 +81,7 @@ static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet, + atomic_set(&local->usage, 1); + atomic_set(&local->active_users, 1); + local->rxnet = rxnet; +- INIT_LIST_HEAD(&local->link); ++ INIT_HLIST_NODE(&local->link); + INIT_WORK(&local->processor, rxrpc_local_processor); + init_rwsem(&local->defrag_sem); + skb_queue_head_init(&local->reject_queue); +@@ -199,7 +199,7 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net, + { + struct rxrpc_local *local; + struct rxrpc_net *rxnet = rxrpc_net(net); +- struct list_head *cursor; ++ struct hlist_node *cursor; + const char *age; + long diff; + int ret; +@@ -209,16 +209,12 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net, + + mutex_lock(&rxnet->local_mutex); + +- for (cursor = rxnet->local_endpoints.next; +- cursor != &rxnet->local_endpoints; +- cursor = cursor->next) { +- local = list_entry(cursor, struct rxrpc_local, link); ++ hlist_for_each(cursor, &rxnet->local_endpoints) { ++ local = hlist_entry(cursor, struct rxrpc_local, link); + + diff = rxrpc_local_cmp_key(local, srx); +- if (diff < 0) ++ if (diff != 0) + continue; +- if (diff > 0) +- break; + + /* Services aren't allowed to share transport sockets, so + * reject that here. It is possible that the object is dying - +@@ -230,9 +226,10 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net, + goto addr_in_use; + } + +- /* Found a match. We replace a dying object. Attempting to +- * bind the transport socket may still fail if we're attempting +- * to use a local address that the dying object is still using. ++ /* Found a match. We want to replace a dying object. ++ * Attempting to bind the transport socket may still fail if ++ * we're attempting to use a local address that the dying ++ * object is still using. + */ + if (!rxrpc_use_local(local)) + break; +@@ -249,10 +246,12 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net, + if (ret < 0) + goto sock_error; + +- if (cursor != &rxnet->local_endpoints) +- list_replace_init(cursor, &local->link); +- else +- list_add_tail(&local->link, cursor); ++ if (cursor) { ++ hlist_replace_rcu(cursor, &local->link); ++ cursor->pprev = NULL; ++ } else { ++ hlist_add_head_rcu(&local->link, &rxnet->local_endpoints); ++ } + age = "new"; + + found: +@@ -393,7 +392,7 @@ static void rxrpc_local_destroyer(struct rxrpc_local *local) + local->dead = true; + + mutex_lock(&rxnet->local_mutex); +- list_del_init(&local->link); ++ hlist_del_init_rcu(&local->link); + mutex_unlock(&rxnet->local_mutex); + + rxrpc_clean_up_local_conns(local); +@@ -480,9 +479,9 @@ void rxrpc_destroy_all_locals(struct rxrpc_net *rxnet) + + flush_workqueue(rxrpc_workqueue); + +- if (!list_empty(&rxnet->local_endpoints)) { ++ if (!hlist_empty(&rxnet->local_endpoints)) { + mutex_lock(&rxnet->local_mutex); +- list_for_each_entry(local, &rxnet->local_endpoints, link) { ++ hlist_for_each_entry(local, &rxnet->local_endpoints, link) { + pr_err("AF_RXRPC: Leaked local %p {%d}\n", + local, atomic_read(&local->usage)); + } +diff --git a/net/rxrpc/net_ns.c b/net/rxrpc/net_ns.c +index cc7e30733feb..34f389975a7d 100644 +--- a/net/rxrpc/net_ns.c ++++ b/net/rxrpc/net_ns.c +@@ -72,7 +72,7 @@ static __net_init int rxrpc_init_net(struct net *net) + timer_setup(&rxnet->client_conn_reap_timer, + rxrpc_client_conn_reap_timeout, 0); + +- INIT_LIST_HEAD(&rxnet->local_endpoints); ++ INIT_HLIST_HEAD(&rxnet->local_endpoints); + mutex_init(&rxnet->local_mutex); + + hash_init(rxnet->peer_hash); +@@ -98,6 +98,9 @@ static __net_init int rxrpc_init_net(struct net *net) + proc_create_net("peers", 0444, rxnet->proc_net, + &rxrpc_peer_seq_ops, + sizeof(struct seq_net_private)); ++ proc_create_net("locals", 0444, rxnet->proc_net, ++ &rxrpc_local_seq_ops, ++ sizeof(struct seq_net_private)); + return 0; + + err_proc: +diff --git a/net/rxrpc/proc.c b/net/rxrpc/proc.c +index e2f990754f88..8a8f776f91ae 100644 +--- a/net/rxrpc/proc.c ++++ b/net/rxrpc/proc.c +@@ -334,3 +334,72 @@ const struct seq_operations rxrpc_peer_seq_ops = { + .stop = rxrpc_peer_seq_stop, + .show = rxrpc_peer_seq_show, + }; ++ ++/* ++ * Generate a list of extant virtual local endpoints in /proc/net/rxrpc/locals ++ */ ++static int rxrpc_local_seq_show(struct seq_file *seq, void *v) ++{ ++ struct rxrpc_local *local; ++ char lbuff[50]; ++ ++ if (v == SEQ_START_TOKEN) { ++ seq_puts(seq, ++ "Proto Local " ++ " Use Act\n"); ++ return 0; ++ } ++ ++ local = hlist_entry(v, struct rxrpc_local, link); ++ ++ sprintf(lbuff, "%pISpc", &local->srx.transport); ++ ++ seq_printf(seq, ++ "UDP %-47.47s %3u %3u\n", ++ lbuff, ++ atomic_read(&local->usage), ++ atomic_read(&local->active_users)); ++ ++ return 0; ++} ++ ++static void *rxrpc_local_seq_start(struct seq_file *seq, loff_t *_pos) ++ __acquires(rcu) ++{ ++ struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq)); ++ unsigned int n; ++ ++ rcu_read_lock(); ++ ++ if (*_pos >= UINT_MAX) ++ return NULL; ++ ++ n = *_pos; ++ if (n == 0) ++ return SEQ_START_TOKEN; ++ ++ return seq_hlist_start_rcu(&rxnet->local_endpoints, n - 1); ++} ++ ++static void *rxrpc_local_seq_next(struct seq_file *seq, void *v, loff_t *_pos) ++{ ++ struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq)); ++ ++ if (*_pos >= UINT_MAX) ++ return NULL; ++ ++ return seq_hlist_next_rcu(v, &rxnet->local_endpoints, _pos); ++} ++ ++static void rxrpc_local_seq_stop(struct seq_file *seq, void *v) ++ __releases(rcu) ++{ ++ rcu_read_unlock(); ++} ++ ++const struct seq_operations rxrpc_local_seq_ops = { ++ .start = rxrpc_local_seq_start, ++ .next = rxrpc_local_seq_next, ++ .stop = rxrpc_local_seq_stop, ++ .show = rxrpc_local_seq_show, ++}; +-- +2.35.1 + diff --git a/queue-5.10/rxrpc-fix-race-between-conn-bundle-lookup-and-bundle.patch b/queue-5.10/rxrpc-fix-race-between-conn-bundle-lookup-and-bundle.patch new file mode 100644 index 00000000000..621c1011c43 --- /dev/null +++ b/queue-5.10/rxrpc-fix-race-between-conn-bundle-lookup-and-bundle.patch @@ -0,0 +1,173 @@ +From d0f4079e7deac7bb255c3d672b04123ecd407d55 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Nov 2022 14:02:28 +0000 +Subject: rxrpc: Fix race between conn bundle lookup and bundle removal + [ZDI-CAN-15975] + +From: David Howells + +[ Upstream commit 3bcd6c7eaa53b56c3f584da46a1f7652e759d0e5 ] + +After rxrpc_unbundle_conn() has removed a connection from a bundle, it +checks to see if there are any conns with available channels and, if not, +removes and attempts to destroy the bundle. + +Whilst it does check after grabbing client_bundles_lock that there are no +connections attached, this races with rxrpc_look_up_bundle() retrieving the +bundle, but not attaching a connection for the connection to be attached +later. + +There is therefore a window in which the bundle can get destroyed before we +manage to attach a new connection to it. + +Fix this by adding an "active" counter to struct rxrpc_bundle: + + (1) rxrpc_connect_call() obtains an active count by prepping/looking up a + bundle and ditches it before returning. + + (2) If, during rxrpc_connect_call(), a connection is added to the bundle, + this obtains an active count, which is held until the connection is + discarded. + + (3) rxrpc_deactivate_bundle() is created to drop an active count on a + bundle and destroy it when the active count reaches 0. The active + count is checked inside client_bundles_lock() to prevent a race with + rxrpc_look_up_bundle(). + + (4) rxrpc_unbundle_conn() then calls rxrpc_deactivate_bundle(). + +Fixes: 245500d853e9 ("rxrpc: Rewrite the client connection manager") +Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-15975 +Signed-off-by: David Howells +Tested-by: zdi-disclosures@trendmicro.com +cc: Marc Dionne +cc: linux-afs@lists.infradead.org +Signed-off-by: David S. Miller +Signed-off-by: Sasha Levin +--- + net/rxrpc/ar-internal.h | 1 + + net/rxrpc/conn_client.c | 38 +++++++++++++++++++++++--------------- + 2 files changed, 24 insertions(+), 15 deletions(-) + +diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h +index 08552ad82f50..d86894a1c35d 100644 +--- a/net/rxrpc/ar-internal.h ++++ b/net/rxrpc/ar-internal.h +@@ -384,6 +384,7 @@ enum rxrpc_conn_proto_state { + struct rxrpc_bundle { + struct rxrpc_conn_parameters params; + refcount_t ref; ++ atomic_t active; /* Number of active users */ + unsigned int debug_id; + bool try_upgrade; /* True if the bundle is attempting upgrade */ + bool alloc_conn; /* True if someone's getting a conn */ +diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c +index 6e2ffafcc98d..f5fa5f3083bd 100644 +--- a/net/rxrpc/conn_client.c ++++ b/net/rxrpc/conn_client.c +@@ -40,6 +40,8 @@ __read_mostly unsigned long rxrpc_conn_idle_client_fast_expiry = 2 * HZ; + DEFINE_IDR(rxrpc_client_conn_ids); + static DEFINE_SPINLOCK(rxrpc_conn_id_lock); + ++static void rxrpc_deactivate_bundle(struct rxrpc_bundle *bundle); ++ + /* + * Get a connection ID and epoch for a client connection from the global pool. + * The connection struct pointer is then recorded in the idr radix tree. The +@@ -123,6 +125,7 @@ static struct rxrpc_bundle *rxrpc_alloc_bundle(struct rxrpc_conn_parameters *cp, + bundle->params = *cp; + rxrpc_get_peer(bundle->params.peer); + refcount_set(&bundle->ref, 1); ++ atomic_set(&bundle->active, 1); + spin_lock_init(&bundle->channel_lock); + INIT_LIST_HEAD(&bundle->waiting_calls); + } +@@ -149,7 +152,7 @@ void rxrpc_put_bundle(struct rxrpc_bundle *bundle) + + dead = __refcount_dec_and_test(&bundle->ref, &r); + +- _debug("PUT B=%x %d", d, r); ++ _debug("PUT B=%x %d", d, r - 1); + if (dead) + rxrpc_free_bundle(bundle); + } +@@ -344,6 +347,7 @@ static struct rxrpc_bundle *rxrpc_look_up_bundle(struct rxrpc_conn_parameters *c + rxrpc_free_bundle(candidate); + found_bundle: + rxrpc_get_bundle(bundle); ++ atomic_inc(&bundle->active); + spin_unlock(&local->client_bundles_lock); + _leave(" = %u [found]", bundle->debug_id); + return bundle; +@@ -441,6 +445,7 @@ static void rxrpc_add_conn_to_bundle(struct rxrpc_bundle *bundle, gfp_t gfp) + if (old) + trace_rxrpc_client(old, -1, rxrpc_client_replace); + candidate->bundle_shift = shift; ++ atomic_inc(&bundle->active); + bundle->conns[i] = candidate; + for (j = 0; j < RXRPC_MAXCALLS; j++) + set_bit(shift + j, &bundle->avail_chans); +@@ -731,6 +736,7 @@ int rxrpc_connect_call(struct rxrpc_sock *rx, + smp_rmb(); + + out_put_bundle: ++ rxrpc_deactivate_bundle(bundle); + rxrpc_put_bundle(bundle); + out: + _leave(" = %d", ret); +@@ -906,9 +912,8 @@ void rxrpc_disconnect_client_call(struct rxrpc_bundle *bundle, struct rxrpc_call + static void rxrpc_unbundle_conn(struct rxrpc_connection *conn) + { + struct rxrpc_bundle *bundle = conn->bundle; +- struct rxrpc_local *local = bundle->params.local; + unsigned int bindex; +- bool need_drop = false, need_put = false; ++ bool need_drop = false; + int i; + + _enter("C=%x", conn->debug_id); +@@ -927,15 +932,22 @@ static void rxrpc_unbundle_conn(struct rxrpc_connection *conn) + } + spin_unlock(&bundle->channel_lock); + +- /* If there are no more connections, remove the bundle */ +- if (!bundle->avail_chans) { +- _debug("maybe unbundle"); +- spin_lock(&local->client_bundles_lock); ++ if (need_drop) { ++ rxrpc_deactivate_bundle(bundle); ++ rxrpc_put_connection(conn); ++ } ++} + +- for (i = 0; i < ARRAY_SIZE(bundle->conns); i++) +- if (bundle->conns[i]) +- break; +- if (i == ARRAY_SIZE(bundle->conns) && !bundle->params.exclusive) { ++/* ++ * Drop the active count on a bundle. ++ */ ++static void rxrpc_deactivate_bundle(struct rxrpc_bundle *bundle) ++{ ++ struct rxrpc_local *local = bundle->params.local; ++ bool need_put = false; ++ ++ if (atomic_dec_and_lock(&bundle->active, &local->client_bundles_lock)) { ++ if (!bundle->params.exclusive) { + _debug("erase bundle"); + rb_erase(&bundle->local_node, &local->client_bundles); + need_put = true; +@@ -945,10 +957,6 @@ static void rxrpc_unbundle_conn(struct rxrpc_connection *conn) + if (need_put) + rxrpc_put_bundle(bundle); + } +- +- if (need_drop) +- rxrpc_put_connection(conn); +- _leave(""); + } + + /* +-- +2.35.1 + diff --git a/queue-5.10/rxrpc-use-refcount_t-rather-than-atomic_t.patch b/queue-5.10/rxrpc-use-refcount_t-rather-than-atomic_t.patch new file mode 100644 index 00000000000..7c53dcffcfc --- /dev/null +++ b/queue-5.10/rxrpc-use-refcount_t-rather-than-atomic_t.patch @@ -0,0 +1,864 @@ +From 20f91a8195eaef90ceecf92aae3276d1db6ada5c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 May 2022 08:45:22 +0100 +Subject: rxrpc: Use refcount_t rather than atomic_t + +From: David Howells + +[ Upstream commit a05754295e01f006a651eec759c5dbe682ef6cef ] + +Move to using refcount_t rather than atomic_t for refcounts in rxrpc. + +Signed-off-by: David Howells +cc: Marc Dionne +cc: linux-afs@lists.infradead.org +Signed-off-by: David S. Miller +Stable-dep-of: 3bcd6c7eaa53 ("rxrpc: Fix race between conn bundle lookup and bundle removal [ZDI-CAN-15975]") +Signed-off-by: Sasha Levin +--- + include/trace/events/rxrpc.h | 2 +- + net/rxrpc/af_rxrpc.c | 2 +- + net/rxrpc/ar-internal.h | 18 ++++--------- + net/rxrpc/call_accept.c | 4 +-- + net/rxrpc/call_object.c | 44 ++++++++++++++++---------------- + net/rxrpc/conn_client.c | 30 +++++++++++----------- + net/rxrpc/conn_object.c | 49 ++++++++++++++++++------------------ + net/rxrpc/conn_service.c | 8 +++--- + net/rxrpc/input.c | 4 +-- + net/rxrpc/local_object.c | 31 ++++++++++++----------- + net/rxrpc/peer_object.c | 40 +++++++++++++++-------------- + net/rxrpc/proc.c | 8 +++--- + net/rxrpc/skbuff.c | 1 - + 13 files changed, 119 insertions(+), 122 deletions(-) + +diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h +index 1c714336b863..221856f2d295 100644 +--- a/include/trace/events/rxrpc.h ++++ b/include/trace/events/rxrpc.h +@@ -583,7 +583,7 @@ TRACE_EVENT(rxrpc_client, + TP_fast_assign( + __entry->conn = conn ? conn->debug_id : 0; + __entry->channel = channel; +- __entry->usage = conn ? atomic_read(&conn->usage) : -2; ++ __entry->usage = conn ? refcount_read(&conn->ref) : -2; + __entry->op = op; + __entry->cid = conn ? conn->proto.cid : 0; + ), +diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c +index 41671af6b33f..0354f90dc93a 100644 +--- a/net/rxrpc/af_rxrpc.c ++++ b/net/rxrpc/af_rxrpc.c +@@ -351,7 +351,7 @@ static void rxrpc_dummy_notify_rx(struct sock *sk, struct rxrpc_call *rxcall, + */ + void rxrpc_kernel_end_call(struct socket *sock, struct rxrpc_call *call) + { +- _enter("%d{%d}", call->debug_id, atomic_read(&call->usage)); ++ _enter("%d{%d}", call->debug_id, refcount_read(&call->ref)); + + mutex_lock(&call->user_mutex); + rxrpc_release_call(rxrpc_sk(sock->sk), call); +diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h +index 2d0c797a176a..08552ad82f50 100644 +--- a/net/rxrpc/ar-internal.h ++++ b/net/rxrpc/ar-internal.h +@@ -14,14 +14,6 @@ + #include + #include "protocol.h" + +-#if 0 +-#define CHECK_SLAB_OKAY(X) \ +- BUG_ON(atomic_read((X)) >> (sizeof(atomic_t) - 2) == \ +- (POISON_FREE << 8 | POISON_FREE)) +-#else +-#define CHECK_SLAB_OKAY(X) do {} while (0) +-#endif +- + #define FCRYPT_BSIZE 8 + struct rxrpc_crypt { + union { +@@ -264,7 +256,7 @@ struct rxrpc_security { + struct rxrpc_local { + struct rcu_head rcu; + atomic_t active_users; /* Number of users of the local endpoint */ +- atomic_t usage; /* Number of references to the structure */ ++ refcount_t ref; /* Number of references to the structure */ + struct rxrpc_net *rxnet; /* The network ns in which this resides */ + struct hlist_node link; + struct socket *socket; /* my UDP socket */ +@@ -289,7 +281,7 @@ struct rxrpc_local { + */ + struct rxrpc_peer { + struct rcu_head rcu; /* This must be first */ +- atomic_t usage; ++ refcount_t ref; + unsigned long hash_key; + struct hlist_node hash_link; + struct rxrpc_local *local; +@@ -391,7 +383,7 @@ enum rxrpc_conn_proto_state { + */ + struct rxrpc_bundle { + struct rxrpc_conn_parameters params; +- atomic_t usage; ++ refcount_t ref; + unsigned int debug_id; + bool try_upgrade; /* True if the bundle is attempting upgrade */ + bool alloc_conn; /* True if someone's getting a conn */ +@@ -412,7 +404,7 @@ struct rxrpc_connection { + struct rxrpc_conn_proto proto; + struct rxrpc_conn_parameters params; + +- atomic_t usage; ++ refcount_t ref; + struct rcu_head rcu; + struct list_head cache_link; + +@@ -592,7 +584,7 @@ struct rxrpc_call { + int error; /* Local error incurred */ + enum rxrpc_call_state state; /* current state of call */ + enum rxrpc_call_completion completion; /* Call completion condition */ +- atomic_t usage; ++ refcount_t ref; + u16 service_id; /* service ID */ + u8 security_ix; /* Security type */ + enum rxrpc_interruptibility interruptibility; /* At what point call may be interrupted */ +diff --git a/net/rxrpc/call_accept.c b/net/rxrpc/call_accept.c +index a0b033954cea..2a14d69b171f 100644 +--- a/net/rxrpc/call_accept.c ++++ b/net/rxrpc/call_accept.c +@@ -91,7 +91,7 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx, + (head + 1) & (size - 1)); + + trace_rxrpc_conn(conn->debug_id, rxrpc_conn_new_service, +- atomic_read(&conn->usage), here); ++ refcount_read(&conn->ref), here); + } + + /* Now it gets complicated, because calls get registered with the +@@ -104,7 +104,7 @@ static int rxrpc_service_prealloc_one(struct rxrpc_sock *rx, + call->state = RXRPC_CALL_SERVER_PREALLOC; + + trace_rxrpc_call(call->debug_id, rxrpc_call_new_service, +- atomic_read(&call->usage), ++ refcount_read(&call->ref), + here, (const void *)user_call_ID); + + write_lock(&rx->call_lock); +diff --git a/net/rxrpc/call_object.c b/net/rxrpc/call_object.c +index 150cd7b2154c..10dad2834d5b 100644 +--- a/net/rxrpc/call_object.c ++++ b/net/rxrpc/call_object.c +@@ -112,7 +112,7 @@ struct rxrpc_call *rxrpc_find_call_by_user_ID(struct rxrpc_sock *rx, + found_extant_call: + rxrpc_get_call(call, rxrpc_call_got); + read_unlock(&rx->call_lock); +- _leave(" = %p [%d]", call, atomic_read(&call->usage)); ++ _leave(" = %p [%d]", call, refcount_read(&call->ref)); + return call; + } + +@@ -160,7 +160,7 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp, + spin_lock_init(&call->notify_lock); + spin_lock_init(&call->input_lock); + rwlock_init(&call->state_lock); +- atomic_set(&call->usage, 1); ++ refcount_set(&call->ref, 1); + call->debug_id = debug_id; + call->tx_total_len = -1; + call->next_rx_timo = 20 * HZ; +@@ -301,7 +301,7 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, + call->interruptibility = p->interruptibility; + call->tx_total_len = p->tx_total_len; + trace_rxrpc_call(call->debug_id, rxrpc_call_new_client, +- atomic_read(&call->usage), ++ refcount_read(&call->ref), + here, (const void *)p->user_call_ID); + if (p->kernel) + __set_bit(RXRPC_CALL_KERNEL, &call->flags); +@@ -354,7 +354,7 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, + goto error_attached_to_socket; + + trace_rxrpc_call(call->debug_id, rxrpc_call_connected, +- atomic_read(&call->usage), here, NULL); ++ refcount_read(&call->ref), here, NULL); + + rxrpc_start_call_timer(call); + +@@ -374,7 +374,7 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, + __rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR, + RX_CALL_DEAD, -EEXIST); + trace_rxrpc_call(call->debug_id, rxrpc_call_error, +- atomic_read(&call->usage), here, ERR_PTR(-EEXIST)); ++ refcount_read(&call->ref), here, ERR_PTR(-EEXIST)); + rxrpc_release_call(rx, call); + mutex_unlock(&call->user_mutex); + rxrpc_put_call(call, rxrpc_call_put); +@@ -388,7 +388,7 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx, + */ + error_attached_to_socket: + trace_rxrpc_call(call->debug_id, rxrpc_call_error, +- atomic_read(&call->usage), here, ERR_PTR(ret)); ++ refcount_read(&call->ref), here, ERR_PTR(ret)); + set_bit(RXRPC_CALL_DISCONNECTED, &call->flags); + __rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR, + RX_CALL_DEAD, ret); +@@ -444,8 +444,9 @@ void rxrpc_incoming_call(struct rxrpc_sock *rx, + bool rxrpc_queue_call(struct rxrpc_call *call) + { + const void *here = __builtin_return_address(0); +- int n = atomic_fetch_add_unless(&call->usage, 1, 0); +- if (n == 0) ++ int n; ++ ++ if (!__refcount_inc_not_zero(&call->ref, &n)) + return false; + if (rxrpc_queue_work(&call->processor)) + trace_rxrpc_call(call->debug_id, rxrpc_call_queued, n + 1, +@@ -461,7 +462,7 @@ bool rxrpc_queue_call(struct rxrpc_call *call) + bool __rxrpc_queue_call(struct rxrpc_call *call) + { + const void *here = __builtin_return_address(0); +- int n = atomic_read(&call->usage); ++ int n = refcount_read(&call->ref); + ASSERTCMP(n, >=, 1); + if (rxrpc_queue_work(&call->processor)) + trace_rxrpc_call(call->debug_id, rxrpc_call_queued_ref, n, +@@ -478,7 +479,7 @@ void rxrpc_see_call(struct rxrpc_call *call) + { + const void *here = __builtin_return_address(0); + if (call) { +- int n = atomic_read(&call->usage); ++ int n = refcount_read(&call->ref); + + trace_rxrpc_call(call->debug_id, rxrpc_call_seen, n, + here, NULL); +@@ -488,11 +489,11 @@ void rxrpc_see_call(struct rxrpc_call *call) + bool rxrpc_try_get_call(struct rxrpc_call *call, enum rxrpc_call_trace op) + { + const void *here = __builtin_return_address(0); +- int n = atomic_fetch_add_unless(&call->usage, 1, 0); ++ int n; + +- if (n == 0) ++ if (!__refcount_inc_not_zero(&call->ref, &n)) + return false; +- trace_rxrpc_call(call->debug_id, op, n, here, NULL); ++ trace_rxrpc_call(call->debug_id, op, n + 1, here, NULL); + return true; + } + +@@ -502,9 +503,10 @@ bool rxrpc_try_get_call(struct rxrpc_call *call, enum rxrpc_call_trace op) + void rxrpc_get_call(struct rxrpc_call *call, enum rxrpc_call_trace op) + { + const void *here = __builtin_return_address(0); +- int n = atomic_inc_return(&call->usage); ++ int n; + +- trace_rxrpc_call(call->debug_id, op, n, here, NULL); ++ __refcount_inc(&call->ref, &n); ++ trace_rxrpc_call(call->debug_id, op, n + 1, here, NULL); + } + + /* +@@ -529,10 +531,10 @@ void rxrpc_release_call(struct rxrpc_sock *rx, struct rxrpc_call *call) + struct rxrpc_connection *conn = call->conn; + bool put = false; + +- _enter("{%d,%d}", call->debug_id, atomic_read(&call->usage)); ++ _enter("{%d,%d}", call->debug_id, refcount_read(&call->ref)); + + trace_rxrpc_call(call->debug_id, rxrpc_call_release, +- atomic_read(&call->usage), ++ refcount_read(&call->ref), + here, (const void *)call->flags); + + ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE); +@@ -621,14 +623,14 @@ void rxrpc_put_call(struct rxrpc_call *call, enum rxrpc_call_trace op) + struct rxrpc_net *rxnet = call->rxnet; + const void *here = __builtin_return_address(0); + unsigned int debug_id = call->debug_id; ++ bool dead; + int n; + + ASSERT(call != NULL); + +- n = atomic_dec_return(&call->usage); ++ dead = __refcount_dec_and_test(&call->ref, &n); + trace_rxrpc_call(debug_id, op, n, here, NULL); +- ASSERTCMP(n, >=, 0); +- if (n == 0) { ++ if (dead) { + _debug("call %d dead", call->debug_id); + ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE); + +@@ -718,7 +720,7 @@ void rxrpc_destroy_all_calls(struct rxrpc_net *rxnet) + list_del_init(&call->link); + + pr_err("Call %p still in use (%d,%s,%lx,%lx)!\n", +- call, atomic_read(&call->usage), ++ call, refcount_read(&call->ref), + rxrpc_call_states[call->state], + call->flags, call->events); + +diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c +index f5fb223aba82..6e2ffafcc98d 100644 +--- a/net/rxrpc/conn_client.c ++++ b/net/rxrpc/conn_client.c +@@ -102,7 +102,7 @@ void rxrpc_destroy_client_conn_ids(void) + if (!idr_is_empty(&rxrpc_client_conn_ids)) { + idr_for_each_entry(&rxrpc_client_conn_ids, conn, id) { + pr_err("AF_RXRPC: Leaked client conn %p {%d}\n", +- conn, atomic_read(&conn->usage)); ++ conn, refcount_read(&conn->ref)); + } + BUG(); + } +@@ -122,7 +122,7 @@ static struct rxrpc_bundle *rxrpc_alloc_bundle(struct rxrpc_conn_parameters *cp, + if (bundle) { + bundle->params = *cp; + rxrpc_get_peer(bundle->params.peer); +- atomic_set(&bundle->usage, 1); ++ refcount_set(&bundle->ref, 1); + spin_lock_init(&bundle->channel_lock); + INIT_LIST_HEAD(&bundle->waiting_calls); + } +@@ -131,7 +131,7 @@ static struct rxrpc_bundle *rxrpc_alloc_bundle(struct rxrpc_conn_parameters *cp, + + struct rxrpc_bundle *rxrpc_get_bundle(struct rxrpc_bundle *bundle) + { +- atomic_inc(&bundle->usage); ++ refcount_inc(&bundle->ref); + return bundle; + } + +@@ -144,10 +144,13 @@ static void rxrpc_free_bundle(struct rxrpc_bundle *bundle) + void rxrpc_put_bundle(struct rxrpc_bundle *bundle) + { + unsigned int d = bundle->debug_id; +- unsigned int u = atomic_dec_return(&bundle->usage); ++ bool dead; ++ int r; + +- _debug("PUT B=%x %u", d, u); +- if (u == 0) ++ dead = __refcount_dec_and_test(&bundle->ref, &r); ++ ++ _debug("PUT B=%x %d", d, r); ++ if (dead) + rxrpc_free_bundle(bundle); + } + +@@ -169,7 +172,7 @@ rxrpc_alloc_client_connection(struct rxrpc_bundle *bundle, gfp_t gfp) + return ERR_PTR(-ENOMEM); + } + +- atomic_set(&conn->usage, 1); ++ refcount_set(&conn->ref, 1); + conn->bundle = bundle; + conn->params = bundle->params; + conn->out_clientflag = RXRPC_CLIENT_INITIATED; +@@ -199,7 +202,7 @@ rxrpc_alloc_client_connection(struct rxrpc_bundle *bundle, gfp_t gfp) + key_get(conn->params.key); + + trace_rxrpc_conn(conn->debug_id, rxrpc_conn_new_client, +- atomic_read(&conn->usage), ++ refcount_read(&conn->ref), + __builtin_return_address(0)); + + atomic_inc(&rxnet->nr_client_conns); +@@ -972,14 +975,13 @@ void rxrpc_put_client_conn(struct rxrpc_connection *conn) + { + const void *here = __builtin_return_address(0); + unsigned int debug_id = conn->debug_id; +- int n; ++ bool dead; ++ int r; + +- n = atomic_dec_return(&conn->usage); +- trace_rxrpc_conn(debug_id, rxrpc_conn_put_client, n, here); +- if (n <= 0) { +- ASSERTCMP(n, >=, 0); ++ dead = __refcount_dec_and_test(&conn->ref, &r); ++ trace_rxrpc_conn(debug_id, rxrpc_conn_put_client, r - 1, here); ++ if (dead) + rxrpc_kill_client_conn(conn); +- } + } + + /* +diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c +index 3ef05a0e90ad..d829b97550cc 100644 +--- a/net/rxrpc/conn_object.c ++++ b/net/rxrpc/conn_object.c +@@ -105,7 +105,7 @@ struct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *local, + goto not_found; + *_peer = peer; + conn = rxrpc_find_service_conn_rcu(peer, skb); +- if (!conn || atomic_read(&conn->usage) == 0) ++ if (!conn || refcount_read(&conn->ref) == 0) + goto not_found; + _leave(" = %p", conn); + return conn; +@@ -115,7 +115,7 @@ struct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *local, + */ + conn = idr_find(&rxrpc_client_conn_ids, + sp->hdr.cid >> RXRPC_CIDSHIFT); +- if (!conn || atomic_read(&conn->usage) == 0) { ++ if (!conn || refcount_read(&conn->ref) == 0) { + _debug("no conn"); + goto not_found; + } +@@ -264,11 +264,12 @@ void rxrpc_kill_connection(struct rxrpc_connection *conn) + bool rxrpc_queue_conn(struct rxrpc_connection *conn) + { + const void *here = __builtin_return_address(0); +- int n = atomic_fetch_add_unless(&conn->usage, 1, 0); +- if (n == 0) ++ int r; ++ ++ if (!__refcount_inc_not_zero(&conn->ref, &r)) + return false; + if (rxrpc_queue_work(&conn->processor)) +- trace_rxrpc_conn(conn->debug_id, rxrpc_conn_queued, n + 1, here); ++ trace_rxrpc_conn(conn->debug_id, rxrpc_conn_queued, r + 1, here); + else + rxrpc_put_connection(conn); + return true; +@@ -281,7 +282,7 @@ void rxrpc_see_connection(struct rxrpc_connection *conn) + { + const void *here = __builtin_return_address(0); + if (conn) { +- int n = atomic_read(&conn->usage); ++ int n = refcount_read(&conn->ref); + + trace_rxrpc_conn(conn->debug_id, rxrpc_conn_seen, n, here); + } +@@ -293,9 +294,10 @@ void rxrpc_see_connection(struct rxrpc_connection *conn) + struct rxrpc_connection *rxrpc_get_connection(struct rxrpc_connection *conn) + { + const void *here = __builtin_return_address(0); +- int n = atomic_inc_return(&conn->usage); ++ int r; + +- trace_rxrpc_conn(conn->debug_id, rxrpc_conn_got, n, here); ++ __refcount_inc(&conn->ref, &r); ++ trace_rxrpc_conn(conn->debug_id, rxrpc_conn_got, r, here); + return conn; + } + +@@ -306,11 +308,11 @@ struct rxrpc_connection * + rxrpc_get_connection_maybe(struct rxrpc_connection *conn) + { + const void *here = __builtin_return_address(0); ++ int r; + + if (conn) { +- int n = atomic_fetch_add_unless(&conn->usage, 1, 0); +- if (n > 0) +- trace_rxrpc_conn(conn->debug_id, rxrpc_conn_got, n + 1, here); ++ if (__refcount_inc_not_zero(&conn->ref, &r)) ++ trace_rxrpc_conn(conn->debug_id, rxrpc_conn_got, r + 1, here); + else + conn = NULL; + } +@@ -334,12 +336,11 @@ void rxrpc_put_service_conn(struct rxrpc_connection *conn) + { + const void *here = __builtin_return_address(0); + unsigned int debug_id = conn->debug_id; +- int n; ++ int r; + +- n = atomic_dec_return(&conn->usage); +- trace_rxrpc_conn(debug_id, rxrpc_conn_put_service, n, here); +- ASSERTCMP(n, >=, 0); +- if (n == 1) ++ __refcount_dec(&conn->ref, &r); ++ trace_rxrpc_conn(debug_id, rxrpc_conn_put_service, r - 1, here); ++ if (r - 1 == 1) + rxrpc_set_service_reap_timer(conn->params.local->rxnet, + jiffies + rxrpc_connection_expiry); + } +@@ -352,9 +353,9 @@ static void rxrpc_destroy_connection(struct rcu_head *rcu) + struct rxrpc_connection *conn = + container_of(rcu, struct rxrpc_connection, rcu); + +- _enter("{%d,u=%d}", conn->debug_id, atomic_read(&conn->usage)); ++ _enter("{%d,u=%d}", conn->debug_id, refcount_read(&conn->ref)); + +- ASSERTCMP(atomic_read(&conn->usage), ==, 0); ++ ASSERTCMP(refcount_read(&conn->ref), ==, 0); + + _net("DESTROY CONN %d", conn->debug_id); + +@@ -394,8 +395,8 @@ void rxrpc_service_connection_reaper(struct work_struct *work) + + write_lock(&rxnet->conn_lock); + list_for_each_entry_safe(conn, _p, &rxnet->service_conns, link) { +- ASSERTCMP(atomic_read(&conn->usage), >, 0); +- if (likely(atomic_read(&conn->usage) > 1)) ++ ASSERTCMP(refcount_read(&conn->ref), >, 0); ++ if (likely(refcount_read(&conn->ref) > 1)) + continue; + if (conn->state == RXRPC_CONN_SERVICE_PREALLOC) + continue; +@@ -407,7 +408,7 @@ void rxrpc_service_connection_reaper(struct work_struct *work) + expire_at = idle_timestamp + rxrpc_closed_conn_expiry * HZ; + + _debug("reap CONN %d { u=%d,t=%ld }", +- conn->debug_id, atomic_read(&conn->usage), ++ conn->debug_id, refcount_read(&conn->ref), + (long)expire_at - (long)now); + + if (time_before(now, expire_at)) { +@@ -420,7 +421,7 @@ void rxrpc_service_connection_reaper(struct work_struct *work) + /* The usage count sits at 1 whilst the object is unused on the + * list; we reduce that to 0 to make the object unavailable. + */ +- if (atomic_cmpxchg(&conn->usage, 1, 0) != 1) ++ if (!refcount_dec_if_one(&conn->ref)) + continue; + trace_rxrpc_conn(conn->debug_id, rxrpc_conn_reap_service, 0, NULL); + +@@ -444,7 +445,7 @@ void rxrpc_service_connection_reaper(struct work_struct *work) + link); + list_del_init(&conn->link); + +- ASSERTCMP(atomic_read(&conn->usage), ==, 0); ++ ASSERTCMP(refcount_read(&conn->ref), ==, 0); + rxrpc_kill_connection(conn); + } + +@@ -472,7 +473,7 @@ void rxrpc_destroy_all_connections(struct rxrpc_net *rxnet) + write_lock(&rxnet->conn_lock); + list_for_each_entry_safe(conn, _p, &rxnet->service_conns, link) { + pr_err("AF_RXRPC: Leaked conn %p {%d}\n", +- conn, atomic_read(&conn->usage)); ++ conn, refcount_read(&conn->ref)); + leak = true; + } + write_unlock(&rxnet->conn_lock); +diff --git a/net/rxrpc/conn_service.c b/net/rxrpc/conn_service.c +index 6c847720494f..68508166bbc0 100644 +--- a/net/rxrpc/conn_service.c ++++ b/net/rxrpc/conn_service.c +@@ -9,7 +9,7 @@ + #include "ar-internal.h" + + static struct rxrpc_bundle rxrpc_service_dummy_bundle = { +- .usage = ATOMIC_INIT(1), ++ .ref = REFCOUNT_INIT(1), + .debug_id = UINT_MAX, + .channel_lock = __SPIN_LOCK_UNLOCKED(&rxrpc_service_dummy_bundle.channel_lock), + }; +@@ -99,7 +99,7 @@ static void rxrpc_publish_service_conn(struct rxrpc_peer *peer, + return; + + found_extant_conn: +- if (atomic_read(&cursor->usage) == 0) ++ if (refcount_read(&cursor->ref) == 0) + goto replace_old_connection; + write_sequnlock_bh(&peer->service_conn_lock); + /* We should not be able to get here. rxrpc_incoming_connection() is +@@ -132,7 +132,7 @@ struct rxrpc_connection *rxrpc_prealloc_service_connection(struct rxrpc_net *rxn + * the rxrpc_connections list. + */ + conn->state = RXRPC_CONN_SERVICE_PREALLOC; +- atomic_set(&conn->usage, 2); ++ refcount_set(&conn->ref, 2); + conn->bundle = rxrpc_get_bundle(&rxrpc_service_dummy_bundle); + + atomic_inc(&rxnet->nr_conns); +@@ -142,7 +142,7 @@ struct rxrpc_connection *rxrpc_prealloc_service_connection(struct rxrpc_net *rxn + write_unlock(&rxnet->conn_lock); + + trace_rxrpc_conn(conn->debug_id, rxrpc_conn_new_service, +- atomic_read(&conn->usage), ++ refcount_read(&conn->ref), + __builtin_return_address(0)); + } + +diff --git a/net/rxrpc/input.c b/net/rxrpc/input.c +index 1145cb14d86f..e9178115a744 100644 +--- a/net/rxrpc/input.c ++++ b/net/rxrpc/input.c +@@ -1163,8 +1163,6 @@ static void rxrpc_post_packet_to_local(struct rxrpc_local *local, + */ + static void rxrpc_reject_packet(struct rxrpc_local *local, struct sk_buff *skb) + { +- CHECK_SLAB_OKAY(&local->usage); +- + if (rxrpc_get_local_maybe(local)) { + skb_queue_tail(&local->reject_queue, skb); + rxrpc_queue_local(local); +@@ -1422,7 +1420,7 @@ int rxrpc_input_packet(struct sock *udp_sk, struct sk_buff *skb) + } + } + +- if (!call || atomic_read(&call->usage) == 0) { ++ if (!call || refcount_read(&call->ref) == 0) { + if (rxrpc_to_client(sp) || + sp->hdr.type != RXRPC_PACKET_TYPE_DATA) + goto bad_message; +diff --git a/net/rxrpc/local_object.c b/net/rxrpc/local_object.c +index 11db28a902f4..2c66ee981f39 100644 +--- a/net/rxrpc/local_object.c ++++ b/net/rxrpc/local_object.c +@@ -78,7 +78,7 @@ static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet, + + local = kzalloc(sizeof(struct rxrpc_local), GFP_KERNEL); + if (local) { +- atomic_set(&local->usage, 1); ++ refcount_set(&local->ref, 1); + atomic_set(&local->active_users, 1); + local->rxnet = rxnet; + INIT_HLIST_NODE(&local->link); +@@ -284,10 +284,10 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net, + struct rxrpc_local *rxrpc_get_local(struct rxrpc_local *local) + { + const void *here = __builtin_return_address(0); +- int n; ++ int r; + +- n = atomic_inc_return(&local->usage); +- trace_rxrpc_local(local->debug_id, rxrpc_local_got, n, here); ++ __refcount_inc(&local->ref, &r); ++ trace_rxrpc_local(local->debug_id, rxrpc_local_got, r + 1, here); + return local; + } + +@@ -297,12 +297,12 @@ struct rxrpc_local *rxrpc_get_local(struct rxrpc_local *local) + struct rxrpc_local *rxrpc_get_local_maybe(struct rxrpc_local *local) + { + const void *here = __builtin_return_address(0); ++ int r; + + if (local) { +- int n = atomic_fetch_add_unless(&local->usage, 1, 0); +- if (n > 0) ++ if (__refcount_inc_not_zero(&local->ref, &r)) + trace_rxrpc_local(local->debug_id, rxrpc_local_got, +- n + 1, here); ++ r + 1, here); + else + local = NULL; + } +@@ -316,10 +316,10 @@ void rxrpc_queue_local(struct rxrpc_local *local) + { + const void *here = __builtin_return_address(0); + unsigned int debug_id = local->debug_id; +- int n = atomic_read(&local->usage); ++ int r = refcount_read(&local->ref); + + if (rxrpc_queue_work(&local->processor)) +- trace_rxrpc_local(debug_id, rxrpc_local_queued, n, here); ++ trace_rxrpc_local(debug_id, rxrpc_local_queued, r + 1, here); + else + rxrpc_put_local(local); + } +@@ -331,15 +331,16 @@ void rxrpc_put_local(struct rxrpc_local *local) + { + const void *here = __builtin_return_address(0); + unsigned int debug_id; +- int n; ++ bool dead; ++ int r; + + if (local) { + debug_id = local->debug_id; + +- n = atomic_dec_return(&local->usage); +- trace_rxrpc_local(debug_id, rxrpc_local_put, n, here); ++ dead = __refcount_dec_and_test(&local->ref, &r); ++ trace_rxrpc_local(debug_id, rxrpc_local_put, r, here); + +- if (n == 0) ++ if (dead) + call_rcu(&local->rcu, rxrpc_local_rcu); + } + } +@@ -427,7 +428,7 @@ static void rxrpc_local_processor(struct work_struct *work) + return; + + trace_rxrpc_local(local->debug_id, rxrpc_local_processing, +- atomic_read(&local->usage), NULL); ++ refcount_read(&local->ref), NULL); + + do { + again = false; +@@ -483,7 +484,7 @@ void rxrpc_destroy_all_locals(struct rxrpc_net *rxnet) + mutex_lock(&rxnet->local_mutex); + hlist_for_each_entry(local, &rxnet->local_endpoints, link) { + pr_err("AF_RXRPC: Leaked local %p {%d}\n", +- local, atomic_read(&local->usage)); ++ local, refcount_read(&local->ref)); + } + mutex_unlock(&rxnet->local_mutex); + BUG(); +diff --git a/net/rxrpc/peer_object.c b/net/rxrpc/peer_object.c +index 0298fe2ad6d3..26d2ae9baaf2 100644 +--- a/net/rxrpc/peer_object.c ++++ b/net/rxrpc/peer_object.c +@@ -121,7 +121,7 @@ static struct rxrpc_peer *__rxrpc_lookup_peer_rcu( + + hash_for_each_possible_rcu(rxnet->peer_hash, peer, hash_link, hash_key) { + if (rxrpc_peer_cmp_key(peer, local, srx, hash_key) == 0 && +- atomic_read(&peer->usage) > 0) ++ refcount_read(&peer->ref) > 0) + return peer; + } + +@@ -140,7 +140,7 @@ struct rxrpc_peer *rxrpc_lookup_peer_rcu(struct rxrpc_local *local, + peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key); + if (peer) { + _net("PEER %d {%pISp}", peer->debug_id, &peer->srx.transport); +- _leave(" = %p {u=%d}", peer, atomic_read(&peer->usage)); ++ _leave(" = %p {u=%d}", peer, refcount_read(&peer->ref)); + } + return peer; + } +@@ -216,7 +216,7 @@ struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *local, gfp_t gfp) + + peer = kzalloc(sizeof(struct rxrpc_peer), gfp); + if (peer) { +- atomic_set(&peer->usage, 1); ++ refcount_set(&peer->ref, 1); + peer->local = rxrpc_get_local(local); + INIT_HLIST_HEAD(&peer->error_targets); + peer->service_conns = RB_ROOT; +@@ -378,7 +378,7 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_sock *rx, + + _net("PEER %d {%pISp}", peer->debug_id, &peer->srx.transport); + +- _leave(" = %p {u=%d}", peer, atomic_read(&peer->usage)); ++ _leave(" = %p {u=%d}", peer, refcount_read(&peer->ref)); + return peer; + } + +@@ -388,10 +388,10 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_sock *rx, + struct rxrpc_peer *rxrpc_get_peer(struct rxrpc_peer *peer) + { + const void *here = __builtin_return_address(0); +- int n; ++ int r; + +- n = atomic_inc_return(&peer->usage); +- trace_rxrpc_peer(peer->debug_id, rxrpc_peer_got, n, here); ++ __refcount_inc(&peer->ref, &r); ++ trace_rxrpc_peer(peer->debug_id, rxrpc_peer_got, r + 1, here); + return peer; + } + +@@ -401,11 +401,11 @@ struct rxrpc_peer *rxrpc_get_peer(struct rxrpc_peer *peer) + struct rxrpc_peer *rxrpc_get_peer_maybe(struct rxrpc_peer *peer) + { + const void *here = __builtin_return_address(0); ++ int r; + + if (peer) { +- int n = atomic_fetch_add_unless(&peer->usage, 1, 0); +- if (n > 0) +- trace_rxrpc_peer(peer->debug_id, rxrpc_peer_got, n + 1, here); ++ if (__refcount_inc_not_zero(&peer->ref, &r)) ++ trace_rxrpc_peer(peer->debug_id, rxrpc_peer_got, r + 1, here); + else + peer = NULL; + } +@@ -436,13 +436,14 @@ void rxrpc_put_peer(struct rxrpc_peer *peer) + { + const void *here = __builtin_return_address(0); + unsigned int debug_id; +- int n; ++ bool dead; ++ int r; + + if (peer) { + debug_id = peer->debug_id; +- n = atomic_dec_return(&peer->usage); +- trace_rxrpc_peer(debug_id, rxrpc_peer_put, n, here); +- if (n == 0) ++ dead = __refcount_dec_and_test(&peer->ref, &r); ++ trace_rxrpc_peer(debug_id, rxrpc_peer_put, r - 1, here); ++ if (dead) + __rxrpc_put_peer(peer); + } + } +@@ -455,11 +456,12 @@ void rxrpc_put_peer_locked(struct rxrpc_peer *peer) + { + const void *here = __builtin_return_address(0); + unsigned int debug_id = peer->debug_id; +- int n; ++ bool dead; ++ int r; + +- n = atomic_dec_return(&peer->usage); +- trace_rxrpc_peer(debug_id, rxrpc_peer_put, n, here); +- if (n == 0) { ++ dead = __refcount_dec_and_test(&peer->ref, &r); ++ trace_rxrpc_peer(debug_id, rxrpc_peer_put, r - 1, here); ++ if (dead) { + hash_del_rcu(&peer->hash_link); + list_del_init(&peer->keepalive_link); + rxrpc_free_peer(peer); +@@ -481,7 +483,7 @@ void rxrpc_destroy_all_peers(struct rxrpc_net *rxnet) + hlist_for_each_entry(peer, &rxnet->peer_hash[i], hash_link) { + pr_err("Leaked peer %u {%u} %pISp\n", + peer->debug_id, +- atomic_read(&peer->usage), ++ refcount_read(&peer->ref), + &peer->srx.transport); + } + } +diff --git a/net/rxrpc/proc.c b/net/rxrpc/proc.c +index 8a8f776f91ae..8967201fd8e5 100644 +--- a/net/rxrpc/proc.c ++++ b/net/rxrpc/proc.c +@@ -107,7 +107,7 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v) + call->cid, + call->call_id, + rxrpc_is_service_call(call) ? "Svc" : "Clt", +- atomic_read(&call->usage), ++ refcount_read(&call->ref), + rxrpc_call_states[call->state], + call->abort_code, + call->debug_id, +@@ -189,7 +189,7 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v) + conn->service_id, + conn->proto.cid, + rxrpc_conn_is_service(conn) ? "Svc" : "Clt", +- atomic_read(&conn->usage), ++ refcount_read(&conn->ref), + rxrpc_conn_states[conn->state], + key_serial(conn->params.key), + atomic_read(&conn->serial), +@@ -239,7 +239,7 @@ static int rxrpc_peer_seq_show(struct seq_file *seq, void *v) + " %3u %5u %6llus %8u %8u\n", + lbuff, + rbuff, +- atomic_read(&peer->usage), ++ refcount_read(&peer->ref), + peer->cong_cwnd, + peer->mtu, + now - peer->last_tx_at, +@@ -357,7 +357,7 @@ static int rxrpc_local_seq_show(struct seq_file *seq, void *v) + seq_printf(seq, + "UDP %-47.47s %3u %3u\n", + lbuff, +- atomic_read(&local->usage), ++ refcount_read(&local->ref), + atomic_read(&local->active_users)); + + return 0; +diff --git a/net/rxrpc/skbuff.c b/net/rxrpc/skbuff.c +index 0348d2bf6f7d..580a5acffee7 100644 +--- a/net/rxrpc/skbuff.c ++++ b/net/rxrpc/skbuff.c +@@ -71,7 +71,6 @@ void rxrpc_free_skb(struct sk_buff *skb, enum rxrpc_skb_trace op) + const void *here = __builtin_return_address(0); + if (skb) { + int n; +- CHECK_SLAB_OKAY(&skb->users); + n = atomic_dec_return(select_skb_count(skb)); + trace_rxrpc_skb(skb, op, refcount_read(&skb->users), n, + rxrpc_skb(skb)->rx_flags, here); +-- +2.35.1 + diff --git a/queue-5.10/s390-crashdump-fix-tod-programmable-field-size.patch b/queue-5.10/s390-crashdump-fix-tod-programmable-field-size.patch new file mode 100644 index 00000000000..40513527a2e --- /dev/null +++ b/queue-5.10/s390-crashdump-fix-tod-programmable-field-size.patch @@ -0,0 +1,61 @@ +From 1f46dc0fe48c6af1a82d76368c93e427d561e4f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 18 Nov 2022 13:05:39 +0100 +Subject: s390/crashdump: fix TOD programmable field size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Heiko Carstens + +[ Upstream commit f44e07a8afdd713ddc1a8832c39372fe5dd86895 ] + +The size of the TOD programmable field was incorrectly increased from +four to eight bytes with commit 1a2c5840acf9 ("s390/dump: cleanup CPU +save area handling"). +This leads to an elf notes section NT_S390_TODPREG which has a size of +eight instead of four bytes in case of kdump, however even worse is +that the contents is incorrect: it is supposed to contain only the +contents of the TOD programmable field, but in fact contains a mix of +the TOD programmable field (32 bit upper bits) and parts of the CPU +timer register (lower 32 bits). + +Fix this by simply changing the size of the todpreg field within the +save area structure. This will implicitly also fix the size of the +corresponding elf notes sections. + +This also gets rid of this compile time warning: + +in function ‘fortify_memcpy_chk’, + inlined from ‘save_area_add_regs’ at arch/s390/kernel/crash_dump.c:99:2: +./include/linux/fortify-string.h:413:25: error: call to ‘__read_overflow2_field’ + declared with attribute warning: detected read beyond size of field + (2nd parameter); maybe use struct_group()? [-Werror=attribute-warning] + 413 | __read_overflow2_field(q_size_field, size); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Fixes: 1a2c5840acf9 ("s390/dump: cleanup CPU save area handling") +Reviewed-by: Christian Borntraeger +Signed-off-by: Heiko Carstens +Signed-off-by: Alexander Gordeev +Signed-off-by: Sasha Levin +--- + arch/s390/kernel/crash_dump.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c +index 76762dc67ca9..f292c3e10671 100644 +--- a/arch/s390/kernel/crash_dump.c ++++ b/arch/s390/kernel/crash_dump.c +@@ -44,7 +44,7 @@ struct save_area { + u64 fprs[16]; + u32 fpc; + u32 prefix; +- u64 todpreg; ++ u32 todpreg; + u64 timer; + u64 todcmp; + u64 vxrs_low[16]; +-- +2.35.1 + diff --git a/queue-5.10/s390-dasd-fix-no-record-found-for-raw_track_access.patch b/queue-5.10/s390-dasd-fix-no-record-found-for-raw_track_access.patch new file mode 100644 index 00000000000..ff497b35658 --- /dev/null +++ b/queue-5.10/s390-dasd-fix-no-record-found-for-raw_track_access.patch @@ -0,0 +1,75 @@ +From 3d0f1a3b6e0a0678fe1115ccfa83b5f5bb3bb832 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 23 Nov 2022 17:07:18 +0100 +Subject: s390/dasd: fix no record found for raw_track_access + +From: Stefan Haberland + +[ Upstream commit 590ce6d96d6a224b470a3862c33a483d5022bfdb ] + +For DASD devices in raw_track_access mode only full track images are +read and written. +For this purpose it is not necessary to do search operation in the +locate record extended function. The documentation even states that +this might fail if the searched record is not found on a track. + +Currently the driver sets a value of 1 in the search field for the first +record after record zero. This is the default for disks not in +raw_track_access mode but record 1 might be missing on a completely +empty track. + +There has not been any problem with this on IBM storage servers but it +might lead to errors with DASD devices on other vendors storage servers. + +Fix this by setting the search field to 0. Record zero is always available +even on a completely empty track. + +Fixes: e4dbb0f2b5dd ("[S390] dasd: Add support for raw ECKD access.") +Signed-off-by: Stefan Haberland +Reviewed-by: Jan Hoeppner +Link: https://lore.kernel.org/r/20221123160719.3002694-4-sth@linux.ibm.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + drivers/s390/block/dasd_eckd.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c +index 7749deb614d7..53d22975a32f 100644 +--- a/drivers/s390/block/dasd_eckd.c ++++ b/drivers/s390/block/dasd_eckd.c +@@ -4627,7 +4627,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev, + struct dasd_device *basedev; + struct req_iterator iter; + struct dasd_ccw_req *cqr; +- unsigned int first_offs; + unsigned int trkcount; + unsigned long *idaws; + unsigned int size; +@@ -4661,7 +4660,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev, + last_trk = (blk_rq_pos(req) + blk_rq_sectors(req) - 1) / + DASD_RAW_SECTORS_PER_TRACK; + trkcount = last_trk - first_trk + 1; +- first_offs = 0; + + if (rq_data_dir(req) == READ) + cmd = DASD_ECKD_CCW_READ_TRACK; +@@ -4705,13 +4703,13 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev, + + if (use_prefix) { + prefix_LRE(ccw++, data, first_trk, last_trk, cmd, basedev, +- startdev, 1, first_offs + 1, trkcount, 0, 0); ++ startdev, 1, 0, trkcount, 0, 0); + } else { + define_extent(ccw++, data, first_trk, last_trk, cmd, basedev, 0); + ccw[-1].flags |= CCW_FLAG_CC; + + data += sizeof(struct DE_eckd_data); +- locate_record_ext(ccw++, data, first_trk, first_offs + 1, ++ locate_record_ext(ccw++, data, first_trk, 0, + trkcount, cmd, basedev, 0, 0); + } + +-- +2.35.1 + diff --git a/queue-5.10/scsi-storvsc-fix-handling-of-srb_status-and-capacity.patch b/queue-5.10/scsi-storvsc-fix-handling-of-srb_status-and-capacity.patch new file mode 100644 index 00000000000..61324ae4c7d --- /dev/null +++ b/queue-5.10/scsi-storvsc-fix-handling-of-srb_status-and-capacity.patch @@ -0,0 +1,148 @@ +From 72421a7b7571ff0e4ea5c7d83bcf268f2765e257 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 9 Nov 2022 10:48:42 -0800 +Subject: scsi: storvsc: Fix handling of srb_status and capacity change events + +From: Michael Kelley + +[ Upstream commit b8a5376c321b4669f7ffabc708fd30c3970f3084 ] + +Current handling of the srb_status is incorrect. Commit 52e1b3b3daa9 +("scsi: storvsc: Correctly handle multiple flags in srb_status") +is based on srb_status being a set of flags, when in fact only the +2 high order bits are flags and the remaining 6 bits are an integer +status. Because the integer values of interest mostly look like flags, +the code actually works when treated that way. + +But in the interest of correctness going forward, fix this by treating +the low 6 bits of srb_status as an integer status code. Add handling +for SRB_STATUS_INVALID_REQUEST, which was the original intent of commit +52e1b3b3daa9. Furthermore, treat the ERROR, ABORTED, and INVALID_REQUEST +srb status codes as essentially equivalent for the cases we care about. +There's no harm in doing so, and it isn't always clear which status code +current or older versions of Hyper-V report for particular conditions. + +Treating the srb status codes as equivalent has the additional benefit +of ensuring that capacity change events result in an immediate rescan +so that the new size is known to Linux. Existing code checks SCSI +sense data for capacity change events when the srb status is ABORTED. +But capacity change events are also being observed when Hyper-V reports +the srb status as ERROR. Without the immediate rescan, the new size +isn't known until something else causes a rescan (such as running +fdisk to expand a partition), and in the meantime, tools such as "lsblk" +continue to report the old size. + +Fixes: 52e1b3b3daa9 ("scsi: storvsc: Correctly handle multiple flags in srb_status") +Reported-by: Juan Tian +Signed-off-by: Michael Kelley +Link: https://lore.kernel.org/r/1668019722-1983-1-git-send-email-mikelley@microsoft.com +Signed-off-by: Wei Liu +Signed-off-by: Sasha Levin +--- + drivers/scsi/storvsc_drv.c | 69 +++++++++++++++++++------------------- + 1 file changed, 34 insertions(+), 35 deletions(-) + +diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c +index 7ac1090d4379..3fa8a0c94bdc 100644 +--- a/drivers/scsi/storvsc_drv.c ++++ b/drivers/scsi/storvsc_drv.c +@@ -356,16 +356,21 @@ enum storvsc_request_type { + }; + + /* +- * SRB status codes and masks; a subset of the codes used here. ++ * SRB status codes and masks. In the 8-bit field, the two high order bits ++ * are flags, while the remaining 6 bits are an integer status code. The ++ * definitions here include only the subset of the integer status codes that ++ * are tested for in this driver. + */ +- + #define SRB_STATUS_AUTOSENSE_VALID 0x80 + #define SRB_STATUS_QUEUE_FROZEN 0x40 +-#define SRB_STATUS_INVALID_LUN 0x20 +-#define SRB_STATUS_SUCCESS 0x01 +-#define SRB_STATUS_ABORTED 0x02 +-#define SRB_STATUS_ERROR 0x04 +-#define SRB_STATUS_DATA_OVERRUN 0x12 ++ ++/* SRB status integer codes */ ++#define SRB_STATUS_SUCCESS 0x01 ++#define SRB_STATUS_ABORTED 0x02 ++#define SRB_STATUS_ERROR 0x04 ++#define SRB_STATUS_INVALID_REQUEST 0x06 ++#define SRB_STATUS_DATA_OVERRUN 0x12 ++#define SRB_STATUS_INVALID_LUN 0x20 + + #define SRB_STATUS(status) \ + (status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN)) +@@ -995,38 +1000,25 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb, + void (*process_err_fn)(struct work_struct *work); + struct hv_host_device *host_dev = shost_priv(host); + +- /* +- * In some situations, Hyper-V sets multiple bits in the +- * srb_status, such as ABORTED and ERROR. So process them +- * individually, with the most specific bits first. +- */ +- +- if (vm_srb->srb_status & SRB_STATUS_INVALID_LUN) { +- set_host_byte(scmnd, DID_NO_CONNECT); +- process_err_fn = storvsc_remove_lun; +- goto do_work; +- } ++ switch (SRB_STATUS(vm_srb->srb_status)) { ++ case SRB_STATUS_ERROR: ++ case SRB_STATUS_ABORTED: ++ case SRB_STATUS_INVALID_REQUEST: ++ if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID) { ++ /* Check for capacity change */ ++ if ((asc == 0x2a) && (ascq == 0x9)) { ++ process_err_fn = storvsc_device_scan; ++ /* Retry the I/O that triggered this. */ ++ set_host_byte(scmnd, DID_REQUEUE); ++ goto do_work; ++ } + +- if (vm_srb->srb_status & SRB_STATUS_ABORTED) { +- if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID && +- /* Capacity data has changed */ +- (asc == 0x2a) && (ascq == 0x9)) { +- process_err_fn = storvsc_device_scan; + /* +- * Retry the I/O that triggered this. ++ * Otherwise, let upper layer deal with the ++ * error when sense message is present + */ +- set_host_byte(scmnd, DID_REQUEUE); +- goto do_work; +- } +- } +- +- if (vm_srb->srb_status & SRB_STATUS_ERROR) { +- /* +- * Let upper layer deal with error when +- * sense message is present. +- */ +- if (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID) + return; ++ } + + /* + * If there is an error; offline the device since all +@@ -1049,6 +1041,13 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb, + default: + set_host_byte(scmnd, DID_ERROR); + } ++ return; ++ ++ case SRB_STATUS_INVALID_LUN: ++ set_host_byte(scmnd, DID_NO_CONNECT); ++ process_err_fn = storvsc_remove_lun; ++ goto do_work; ++ + } + return; + +-- +2.35.1 + diff --git a/queue-5.10/series b/queue-5.10/series index 6f1d99c3114..d27313fb0b1 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -29,3 +29,63 @@ block-bfq-fix-null-pointer-dereference-in-bfq_bio_bf.patch arm64-syscall-include-asm-ptrace.h-in-syscall_wrappe.patch risc-v-vdso-do-not-add-missing-symbols-to-version-se.patch mips-pic32-treat-port-as-signed-integer.patch +xfrm-fix-disable_policy-on-ipv4-early-demux.patch +xfrm-replay-fix-esn-wrap-around-for-gso.patch +af_key-fix-send_acquire-race-with-pfkey_register.patch +arm-dts-am335x-pcm-953-define-fixed-regulators-in-ro.patch +asoc-hdac_hda-fix-hda-pcm-buffer-overflow-issue.patch +asoc-sgtl5000-reset-the-chip_clk_ctrl-reg-on-remove.patch +asoc-soc-pcm-don-t-zero-tdm-masks-in-__soc_pcm_open.patch +scsi-storvsc-fix-handling-of-srb_status-and-capacity.patch +regulator-core-fix-kobject-release-warning-and-memor.patch +spi-dw-dma-decrease-reference-count-in-dw_spi_dma_in.patch +regulator-core-fix-uaf-in-destroy_regulator.patch +bus-sunxi-rsb-support-atomic-transfers.patch +tee-optee-fix-possible-memory-leak-in-optee_register.patch +arm-dts-at91-sam9g20ek-enable-udc-vbus-gpio-pinctrl.patch +net-liquidio-simplify-if-expression.patch +rxrpc-allow-list-of-in-use-local-udp-endpoints-to-be.patch +rxrpc-use-refcount_t-rather-than-atomic_t.patch +rxrpc-fix-race-between-conn-bundle-lookup-and-bundle.patch +nfc-nci-fix-race-with-opening-and-closing.patch +net-pch_gbe-fix-potential-memleak-in-pch_gbe_tx_queu.patch +9p-fd-fix-issue-of-list_del-corruption-in-p9_fd_canc.patch +netfilter-conntrack-fix-data-races-around-ct-mark.patch +arm-mxs-fix-memory-leak-in-mxs_machine_init.patch +arm-dts-imx6q-prti6q-fix-ref-tcxo-clock-frequency-pr.patch +net-ethernet-mtk_eth_soc-fix-error-handling-in-mtk_o.patch +net-mlx4-check-retval-of-mlx4_bitmap_init.patch +net-qla3xxx-fix-potential-memleak-in-ql3xxx_send.patch +net-pch_gbe-fix-pci-device-refcount-leak-while-modul.patch +nfp-fill-splittable-of-devlink_port_attrs-correctly.patch +nfp-add-port-from-netdev-validation-for-eeprom-acces.patch +macsec-fix-invalid-error-code-set.patch +drivers-hv-vmbus-fix-double-free-in-the-error-path-o.patch +drivers-hv-vmbus-fix-possible-memory-leak-in-vmbus_d.patch +netfilter-ipset-limit-the-maximal-range-of-consecuti.patch +netfilter-ipset-regression-in-ip_set_hash_ip.c.patch +net-mlx5-fix-fw-tracer-timestamp-calculation.patch +net-mlx5-fix-handling-of-entry-refcount-when-command.patch +tipc-set-con-sock-in-tipc_conn_alloc.patch +tipc-add-an-extra-conn_get-in-tipc_conn_alloc.patch +tipc-check-skb_linearize-return-value-in-tipc_disc_r.patch +xfrm-fix-ignored-return-value-in-xfrm6_init.patch +sfc-fix-potential-memleak-in-__ef100_hard_start_xmit.patch +net-sched-allow-act_ct-to-be-built-without-nf_nat.patch +nfc-nci-fix-memory-leak-in-nci_rx_data_packet.patch +regulator-twl6030-re-add-twl6032_subclass.patch +bnx2x-fix-pci-device-refcount-leak-in-bnx2x_vf_is_pc.patch +dma-buf-fix-racing-conflict-of-dma_heap_add.patch +netfilter-flowtable_offload-add-missing-locking.patch +dccp-tcp-reset-saddr-on-failure-after-inet6-_hash_co.patch +ipv4-fix-error-return-code-in-fib_table_insert.patch +s390-dasd-fix-no-record-found-for-raw_track_access.patch +net-arcnet-fix-reset-flag-handling.patch +arcnet-fix-potential-memory-leak-in-com20020_probe.patch +nfc-st-nci-fix-incorrect-validating-logic-in-evt_tra.patch +nfc-st-nci-fix-memory-leaks-in-evt_transaction.patch +net-thunderx-fix-the-acpi-memory-leak.patch +s390-crashdump-fix-tod-programmable-field-size.patch +net-enetc-manage-enetc_f_qbv-in-priv-active_offloads.patch +net-enetc-cache-accesses-to-priv-si-hw.patch +net-enetc-preserve-tx-ring-priority-across-reconfigu.patch diff --git a/queue-5.10/sfc-fix-potential-memleak-in-__ef100_hard_start_xmit.patch b/queue-5.10/sfc-fix-potential-memleak-in-__ef100_hard_start_xmit.patch new file mode 100644 index 00000000000..c2a4ed7be5d --- /dev/null +++ b/queue-5.10/sfc-fix-potential-memleak-in-__ef100_hard_start_xmit.patch @@ -0,0 +1,38 @@ +From 7697719cef1563d289a3a8390e2d104e3daecf3f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Nov 2022 15:50:09 +0800 +Subject: sfc: fix potential memleak in __ef100_hard_start_xmit() + +From: Zhang Changzhong + +[ Upstream commit aad98abd5cb8133507f22654f56bcb443aaa2d89 ] + +The __ef100_hard_start_xmit() returns NETDEV_TX_OK without freeing skb +in error handling case, add dev_kfree_skb_any() to fix it. + +Fixes: 51b35a454efd ("sfc: skeleton EF100 PF driver") +Signed-off-by: Zhang Changzhong +Acked-by: Martin Habets +Reviewed-by: Leon Romanovsky +Link: https://lore.kernel.org/r/1668671409-10909-1-git-send-email-zhangchangzhong@huawei.com +Signed-off-by: Paolo Abeni +Signed-off-by: Sasha Levin +--- + drivers/net/ethernet/sfc/ef100_netdev.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/sfc/ef100_netdev.c b/drivers/net/ethernet/sfc/ef100_netdev.c +index 67fe44db6b61..63a44ee763be 100644 +--- a/drivers/net/ethernet/sfc/ef100_netdev.c ++++ b/drivers/net/ethernet/sfc/ef100_netdev.c +@@ -200,6 +200,7 @@ static netdev_tx_t ef100_hard_start_xmit(struct sk_buff *skb, + skb->len, skb->data_len, channel->channel); + if (!efx->n_channels || !efx->n_tx_channels || !channel) { + netif_stop_queue(net_dev); ++ dev_kfree_skb_any(skb); + goto err; + } + +-- +2.35.1 + diff --git a/queue-5.10/spi-dw-dma-decrease-reference-count-in-dw_spi_dma_in.patch b/queue-5.10/spi-dw-dma-decrease-reference-count-in-dw_spi_dma_in.patch new file mode 100644 index 00000000000..c45d32d0354 --- /dev/null +++ b/queue-5.10/spi-dw-dma-decrease-reference-count-in-dw_spi_dma_in.patch @@ -0,0 +1,47 @@ +From 246bcb58d47ee7525efc2ae7a253062eeaa28edb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Nov 2022 17:32:04 +0800 +Subject: spi: dw-dma: decrease reference count in dw_spi_dma_init_mfld() + +From: Xiongfeng Wang + +[ Upstream commit 804313b64e412a81b0b3389a10e7622452004aa6 ] + +pci_get_device() will increase the reference count for the returned +pci_dev. Since 'dma_dev' is only used to filter the channel in +dw_spi_dma_chan_filer() after using it we need to call pci_dev_put() to +decrease the reference count. Also add pci_dev_put() for the error case. + +Fixes: 7063c0d942a1 ("spi/dw_spi: add DMA support") +Signed-off-by: Xiongfeng Wang +Acked-by: Serge Semin +Link: https://lore.kernel.org/r/20221116093204.46700-1-wangxiongfeng2@huawei.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + drivers/spi/spi-dw-dma.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c +index a09831c62192..32ac8f9068e8 100644 +--- a/drivers/spi/spi-dw-dma.c ++++ b/drivers/spi/spi-dw-dma.c +@@ -127,12 +127,15 @@ static int dw_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws) + + dw_spi_dma_sg_burst_init(dws); + ++ pci_dev_put(dma_dev); ++ + return 0; + + free_rxchan: + dma_release_channel(dws->rxchan); + dws->rxchan = NULL; + err_exit: ++ pci_dev_put(dma_dev); + return -EBUSY; + } + +-- +2.35.1 + diff --git a/queue-5.10/tee-optee-fix-possible-memory-leak-in-optee_register.patch b/queue-5.10/tee-optee-fix-possible-memory-leak-in-optee_register.patch new file mode 100644 index 00000000000..bb4dedddc53 --- /dev/null +++ b/queue-5.10/tee-optee-fix-possible-memory-leak-in-optee_register.patch @@ -0,0 +1,41 @@ +From 7b9777eeaf3b4b91a6e974b4c4fbee70a88a1d5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 9 Nov 2022 22:01:24 +0800 +Subject: tee: optee: fix possible memory leak in optee_register_device() + +From: Yang Yingliang + +[ Upstream commit cce616e012c215d65c15e5d1afa73182dea49389 ] + +If device_register() returns error in optee_register_device(), +the name allocated by dev_set_name() need be freed. As comment +of device_register() says, it should use put_device() to give +up the reference in the error path. So fix this by calling +put_device(), then the name can be freed in kobject_cleanup(), +and optee_device is freed in optee_release_device(). + +Fixes: c3fa24af9244 ("tee: optee: add TEE bus device enumeration support") +Signed-off-by: Yang Yingliang +Reviewed-by: Sumit Garg +Signed-off-by: Jens Wiklander +Signed-off-by: Sasha Levin +--- + drivers/tee/optee/device.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/tee/optee/device.c b/drivers/tee/optee/device.c +index 031806468af4..60ffc54da003 100644 +--- a/drivers/tee/optee/device.c ++++ b/drivers/tee/optee/device.c +@@ -80,7 +80,7 @@ static int optee_register_device(const uuid_t *device_uuid) + rc = device_register(&optee_device->dev); + if (rc) { + pr_err("device registration failed, err: %d\n", rc); +- kfree(optee_device); ++ put_device(&optee_device->dev); + } + + return rc; +-- +2.35.1 + diff --git a/queue-5.10/tipc-add-an-extra-conn_get-in-tipc_conn_alloc.patch b/queue-5.10/tipc-add-an-extra-conn_get-in-tipc_conn_alloc.patch new file mode 100644 index 00000000000..e217153cfd8 --- /dev/null +++ b/queue-5.10/tipc-add-an-extra-conn_get-in-tipc_conn_alloc.patch @@ -0,0 +1,84 @@ +From 2d5f6e93e31f2c8f7edc15d64645fa7c0fd36dc7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 18 Nov 2022 16:45:01 -0500 +Subject: tipc: add an extra conn_get in tipc_conn_alloc + +From: Xin Long + +[ Upstream commit a7b42969d63f47320853a802efd879fbdc4e010e ] + +One extra conn_get() is needed in tipc_conn_alloc(), as after +tipc_conn_alloc() is called, tipc_conn_close() may free this +con before deferencing it in tipc_topsrv_accept(): + + tipc_conn_alloc(); + newsk = newsock->sk; + <---- tipc_conn_close(); + write_lock_bh(&sk->sk_callback_lock); + newsk->sk_data_ready = tipc_conn_data_ready; + +Then an uaf issue can be triggered: + + BUG: KASAN: use-after-free in tipc_topsrv_accept+0x1e7/0x370 [tipc] + Call Trace: + + dump_stack_lvl+0x33/0x46 + print_report+0x178/0x4b0 + kasan_report+0x8c/0x100 + kasan_check_range+0x179/0x1e0 + tipc_topsrv_accept+0x1e7/0x370 [tipc] + process_one_work+0x6a3/0x1030 + worker_thread+0x8a/0xdf0 + +This patch fixes it by holding it in tipc_conn_alloc(), then after +all accessing in tipc_topsrv_accept() releasing it. Note when does +this in tipc_topsrv_kern_subscr(), as tipc_conn_rcv_sub() returns +0 or -1 only, we don't need to check for "> 0". + +Fixes: c5fa7b3cf3cb ("tipc: introduce new TIPC server infrastructure") +Signed-off-by: Xin Long +Acked-by: Jon Maloy +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/tipc/topsrv.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/net/tipc/topsrv.c b/net/tipc/topsrv.c +index dcd4afb3640f..89d8a2bd30cd 100644 +--- a/net/tipc/topsrv.c ++++ b/net/tipc/topsrv.c +@@ -206,6 +206,7 @@ static struct tipc_conn *tipc_conn_alloc(struct tipc_topsrv *s, struct socket *s + set_bit(CF_CONNECTED, &con->flags); + con->server = s; + con->sock = sock; ++ conn_get(con); + spin_unlock_bh(&s->idr_lock); + + return con; +@@ -484,6 +485,7 @@ static void tipc_topsrv_accept(struct work_struct *work) + + /* Wake up receive process in case of 'SYN+' message */ + newsk->sk_data_ready(newsk); ++ conn_put(con); + } + } + +@@ -583,10 +585,11 @@ bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type, u32 lower, + + *conid = con->conid; + rc = tipc_conn_rcv_sub(tipc_topsrv(net), con, &sub); +- if (rc >= 0) +- return true; ++ if (rc) ++ conn_put(con); ++ + conn_put(con); +- return false; ++ return !rc; + } + + void tipc_topsrv_kern_unsubscr(struct net *net, int conid) +-- +2.35.1 + diff --git a/queue-5.10/tipc-check-skb_linearize-return-value-in-tipc_disc_r.patch b/queue-5.10/tipc-check-skb_linearize-return-value-in-tipc_disc_r.patch new file mode 100644 index 00000000000..5da95aa67ec --- /dev/null +++ b/queue-5.10/tipc-check-skb_linearize-return-value-in-tipc_disc_r.patch @@ -0,0 +1,41 @@ +From caa310eb6d1af9f98cb7111e5d0ba13e1e2be2ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 19 Nov 2022 15:28:32 +0800 +Subject: tipc: check skb_linearize() return value in tipc_disc_rcv() + +From: YueHaibing + +[ Upstream commit cd0f6421162201e4b22ce757a1966729323185eb ] + +If skb_linearize() fails in tipc_disc_rcv(), we need to free the skb instead of +handle it. + +Fixes: 25b0b9c4e835 ("tipc: handle collisions of 32-bit node address hash values") +Signed-off-by: YueHaibing +Acked-by: Jon Maloy +Link: https://lore.kernel.org/r/20221119072832.7896-1-yuehaibing@huawei.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/tipc/discover.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/net/tipc/discover.c b/net/tipc/discover.c +index 2ae268b67465..2730310249e3 100644 +--- a/net/tipc/discover.c ++++ b/net/tipc/discover.c +@@ -210,7 +210,10 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *skb, + u32 self; + int err; + +- skb_linearize(skb); ++ if (skb_linearize(skb)) { ++ kfree_skb(skb); ++ return; ++ } + hdr = buf_msg(skb); + + if (caps & TIPC_NODE_ID128) +-- +2.35.1 + diff --git a/queue-5.10/tipc-set-con-sock-in-tipc_conn_alloc.patch b/queue-5.10/tipc-set-con-sock-in-tipc_conn_alloc.patch new file mode 100644 index 00000000000..881517ed6cd --- /dev/null +++ b/queue-5.10/tipc-set-con-sock-in-tipc_conn_alloc.patch @@ -0,0 +1,106 @@ +From 1d271c6eabf8d86f95dbe51cff0d89e07f43397a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 18 Nov 2022 16:45:00 -0500 +Subject: tipc: set con sock in tipc_conn_alloc + +From: Xin Long + +[ Upstream commit 0e5d56c64afcd6fd2d132ea972605b66f8a7d3c4 ] + +A crash was reported by Wei Chen: + + BUG: kernel NULL pointer dereference, address: 0000000000000018 + RIP: 0010:tipc_conn_close+0x12/0x100 + Call Trace: + tipc_topsrv_exit_net+0x139/0x320 + ops_exit_list.isra.9+0x49/0x80 + cleanup_net+0x31a/0x540 + process_one_work+0x3fa/0x9f0 + worker_thread+0x42/0x5c0 + +It was caused by !con->sock in tipc_conn_close(). In tipc_topsrv_accept(), +con is allocated in conn_idr then its sock is set: + + con = tipc_conn_alloc(); + ... <----[1] + con->sock = newsock; + +If tipc_conn_close() is called in anytime of [1], the null-pointer-def +is triggered by con->sock->sk due to con->sock is not yet set. + +This patch fixes it by moving the con->sock setting to tipc_conn_alloc() +under s->idr_lock. So that con->sock can never be NULL when getting the +con from s->conn_idr. It will be also safer to move con->server and flag +CF_CONNECTED setting under s->idr_lock, as they should all be set before +tipc_conn_alloc() is called. + +Fixes: c5fa7b3cf3cb ("tipc: introduce new TIPC server infrastructure") +Reported-by: Wei Chen +Signed-off-by: Xin Long +Acked-by: Jon Maloy +Signed-off-by: Jakub Kicinski +Signed-off-by: Sasha Levin +--- + net/tipc/topsrv.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/net/tipc/topsrv.c b/net/tipc/topsrv.c +index 561e709ae06a..dcd4afb3640f 100644 +--- a/net/tipc/topsrv.c ++++ b/net/tipc/topsrv.c +@@ -176,7 +176,7 @@ static void tipc_conn_close(struct tipc_conn *con) + conn_put(con); + } + +-static struct tipc_conn *tipc_conn_alloc(struct tipc_topsrv *s) ++static struct tipc_conn *tipc_conn_alloc(struct tipc_topsrv *s, struct socket *sock) + { + struct tipc_conn *con; + int ret; +@@ -202,10 +202,11 @@ static struct tipc_conn *tipc_conn_alloc(struct tipc_topsrv *s) + } + con->conid = ret; + s->idr_in_use++; +- spin_unlock_bh(&s->idr_lock); + + set_bit(CF_CONNECTED, &con->flags); + con->server = s; ++ con->sock = sock; ++ spin_unlock_bh(&s->idr_lock); + + return con; + } +@@ -467,7 +468,7 @@ static void tipc_topsrv_accept(struct work_struct *work) + ret = kernel_accept(lsock, &newsock, O_NONBLOCK); + if (ret < 0) + return; +- con = tipc_conn_alloc(srv); ++ con = tipc_conn_alloc(srv, newsock); + if (IS_ERR(con)) { + ret = PTR_ERR(con); + sock_release(newsock); +@@ -479,7 +480,6 @@ static void tipc_topsrv_accept(struct work_struct *work) + newsk->sk_data_ready = tipc_conn_data_ready; + newsk->sk_write_space = tipc_conn_write_space; + newsk->sk_user_data = con; +- con->sock = newsock; + write_unlock_bh(&newsk->sk_callback_lock); + + /* Wake up receive process in case of 'SYN+' message */ +@@ -577,12 +577,11 @@ bool tipc_topsrv_kern_subscr(struct net *net, u32 port, u32 type, u32 lower, + sub.filter = filter; + *(u64 *)&sub.usr_handle = (u64)port; + +- con = tipc_conn_alloc(tipc_topsrv(net)); ++ con = tipc_conn_alloc(tipc_topsrv(net), NULL); + if (IS_ERR(con)) + return false; + + *conid = con->conid; +- con->sock = NULL; + rc = tipc_conn_rcv_sub(tipc_topsrv(net), con, &sub); + if (rc >= 0) + return true; +-- +2.35.1 + diff --git a/queue-5.10/xfrm-fix-disable_policy-on-ipv4-early-demux.patch b/queue-5.10/xfrm-fix-disable_policy-on-ipv4-early-demux.patch new file mode 100644 index 00000000000..f69fde4b61b --- /dev/null +++ b/queue-5.10/xfrm-fix-disable_policy-on-ipv4-early-demux.patch @@ -0,0 +1,54 @@ +From 5f5a5525ca2903daaf576e547a8de1e2e64c51ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 9 Oct 2022 22:16:43 +0300 +Subject: xfrm: fix "disable_policy" on ipv4 early demux + +From: Eyal Birger + +[ Upstream commit 3a5913183aa1b14148c723bda030e6102ad73008 ] + +The commit in the "Fixes" tag tried to avoid a case where policy check +is ignored due to dst caching in next hops. + +However, when the traffic is locally consumed, the dst may be cached +in a local TCP or UDP socket as part of early demux. In this case the +"disable_policy" flag is not checked as ip_route_input_noref() was only +called before caching, and thus, packets after the initial packet in a +flow will be dropped if not matching policies. + +Fix by checking the "disable_policy" flag also when a valid dst is +already available. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=216557 +Reported-by: Monil Patel +Fixes: e6175a2ed1f1 ("xfrm: fix "disable_policy" flag use when arriving from different devices") +Signed-off-by: Eyal Birger + +---- + +v2: use dev instead of skb->dev +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/ipv4/ip_input.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c +index f6b3237e88ca..eccd7897e7aa 100644 +--- a/net/ipv4/ip_input.c ++++ b/net/ipv4/ip_input.c +@@ -361,6 +361,11 @@ static int ip_rcv_finish_core(struct net *net, struct sock *sk, + iph->tos, dev); + if (unlikely(err)) + goto drop_error; ++ } else { ++ struct in_device *in_dev = __in_dev_get_rcu(dev); ++ ++ if (in_dev && IN_DEV_ORCONF(in_dev, NOPOLICY)) ++ IPCB(skb)->flags |= IPSKB_NOPOLICY; + } + + #ifdef CONFIG_IP_ROUTE_CLASSID +-- +2.35.1 + diff --git a/queue-5.10/xfrm-fix-ignored-return-value-in-xfrm6_init.patch b/queue-5.10/xfrm-fix-ignored-return-value-in-xfrm6_init.patch new file mode 100644 index 00000000000..bc5508faec8 --- /dev/null +++ b/queue-5.10/xfrm-fix-ignored-return-value-in-xfrm6_init.patch @@ -0,0 +1,59 @@ +From 91c8143a3764e9eacffa5c6c9a93306da457765a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Nov 2022 17:07:13 +0800 +Subject: xfrm: Fix ignored return value in xfrm6_init() + +From: Chen Zhongjin + +[ Upstream commit 40781bfb836eda57d19c0baa37c7e72590e05fdc ] + +When IPv6 module initializing in xfrm6_init(), register_pernet_subsys() +is possible to fail but its return value is ignored. + +If IPv6 initialization fails later and xfrm6_fini() is called, +removing uninitialized list in xfrm6_net_ops will cause null-ptr-deref: + +KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] +CPU: 1 PID: 330 Comm: insmod +RIP: 0010:unregister_pernet_operations+0xc9/0x450 +Call Trace: + + unregister_pernet_subsys+0x31/0x3e + xfrm6_fini+0x16/0x30 [ipv6] + ip6_route_init+0xcd/0x128 [ipv6] + inet6_init+0x29c/0x602 [ipv6] + ... + +Fix it by catching the error return value of register_pernet_subsys(). + +Fixes: 8d068875caca ("xfrm: make gc_thresh configurable in all namespaces") +Signed-off-by: Chen Zhongjin +Reviewed-by: Leon Romanovsky +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/ipv6/xfrm6_policy.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c +index af7a4b8b1e9c..247296e3294b 100644 +--- a/net/ipv6/xfrm6_policy.c ++++ b/net/ipv6/xfrm6_policy.c +@@ -289,9 +289,13 @@ int __init xfrm6_init(void) + if (ret) + goto out_state; + +- register_pernet_subsys(&xfrm6_net_ops); ++ ret = register_pernet_subsys(&xfrm6_net_ops); ++ if (ret) ++ goto out_protocol; + out: + return ret; ++out_protocol: ++ xfrm6_protocol_fini(); + out_state: + xfrm6_state_fini(); + out_policy: +-- +2.35.1 + diff --git a/queue-5.10/xfrm-replay-fix-esn-wrap-around-for-gso.patch b/queue-5.10/xfrm-replay-fix-esn-wrap-around-for-gso.patch new file mode 100644 index 00000000000..7e43f5a3a3d --- /dev/null +++ b/queue-5.10/xfrm-replay-fix-esn-wrap-around-for-gso.patch @@ -0,0 +1,103 @@ +From f633d393b80e9ca717f5922730eb318042f0c4a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 17 Oct 2022 08:34:47 +0200 +Subject: xfrm: replay: Fix ESN wrap around for GSO + +From: Christian Langrock + +[ Upstream commit 4b549ccce941798703f159b227aa28c716aa78fa ] + +When using GSO it can happen that the wrong seq_hi is used for the last +packets before the wrap around. This can lead to double usage of a +sequence number. To avoid this, we should serialize this last GSO +packet. + +Fixes: d7dbefc45cf5 ("xfrm: Add xfrm_replay_overflow functions for offloading") +Co-developed-by: Steffen Klassert +Signed-off-by: Christian Langrock +Signed-off-by: Steffen Klassert +Signed-off-by: Sasha Levin +--- + net/ipv4/esp4_offload.c | 3 +++ + net/ipv6/esp6_offload.c | 3 +++ + net/xfrm/xfrm_device.c | 15 ++++++++++++++- + net/xfrm/xfrm_replay.c | 2 +- + 4 files changed, 21 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/esp4_offload.c b/net/ipv4/esp4_offload.c +index 3450c9ba2728..84257678160a 100644 +--- a/net/ipv4/esp4_offload.c ++++ b/net/ipv4/esp4_offload.c +@@ -312,6 +312,9 @@ static int esp_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features_ + xo->seq.low += skb_shinfo(skb)->gso_segs; + } + ++ if (xo->seq.low < seq) ++ xo->seq.hi++; ++ + esp.seqno = cpu_to_be64(seq + ((u64)xo->seq.hi << 32)); + + ip_hdr(skb)->tot_len = htons(skb->len); +diff --git a/net/ipv6/esp6_offload.c b/net/ipv6/esp6_offload.c +index 1c3f02d05d2b..7608be04d0f5 100644 +--- a/net/ipv6/esp6_offload.c ++++ b/net/ipv6/esp6_offload.c +@@ -343,6 +343,9 @@ static int esp6_xmit(struct xfrm_state *x, struct sk_buff *skb, netdev_features + xo->seq.low += skb_shinfo(skb)->gso_segs; + } + ++ if (xo->seq.low < seq) ++ xo->seq.hi++; ++ + esp.seqno = cpu_to_be64(xo->seq.low + ((u64)xo->seq.hi << 32)); + + len = skb->len - sizeof(struct ipv6hdr); +diff --git a/net/xfrm/xfrm_device.c b/net/xfrm/xfrm_device.c +index c255aac6b816..8b8e957a69c3 100644 +--- a/net/xfrm/xfrm_device.c ++++ b/net/xfrm/xfrm_device.c +@@ -97,6 +97,18 @@ static void xfrm_outer_mode_prep(struct xfrm_state *x, struct sk_buff *skb) + } + } + ++static inline bool xmit_xfrm_check_overflow(struct sk_buff *skb) ++{ ++ struct xfrm_offload *xo = xfrm_offload(skb); ++ __u32 seq = xo->seq.low; ++ ++ seq += skb_shinfo(skb)->gso_segs; ++ if (unlikely(seq < xo->seq.low)) ++ return true; ++ ++ return false; ++} ++ + struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features, bool *again) + { + int err; +@@ -134,7 +146,8 @@ struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t featur + return skb; + } + +- if (skb_is_gso(skb) && unlikely(x->xso.dev != dev)) { ++ if (skb_is_gso(skb) && (unlikely(x->xso.dev != dev) || ++ unlikely(xmit_xfrm_check_overflow(skb)))) { + struct sk_buff *segs; + + /* Packet got rerouted, fixup features and segment it. */ +diff --git a/net/xfrm/xfrm_replay.c b/net/xfrm/xfrm_replay.c +index c6a4338a0d08..65d009e3b6bb 100644 +--- a/net/xfrm/xfrm_replay.c ++++ b/net/xfrm/xfrm_replay.c +@@ -657,7 +657,7 @@ static int xfrm_replay_overflow_offload_esn(struct xfrm_state *x, struct sk_buff + oseq += skb_shinfo(skb)->gso_segs; + } + +- if (unlikely(oseq < replay_esn->oseq)) { ++ if (unlikely(xo->seq.low < replay_esn->oseq)) { + XFRM_SKB_CB(skb)->seq.output.hi = ++oseq_hi; + xo->seq.hi = oseq_hi; + replay_esn->oseq_hi = oseq_hi; +-- +2.35.1 +