kernel: move accepted mtk_eth_soc patches to generic-backport
[openwrt/staging/noltari.git] / target / linux / generic / backport-5.15 / 730-11-v6.3-net-ethernet-mtk_eth_soc-fix-flow_offload-related-re.patch
diff --git a/target/linux/generic/backport-5.15/730-11-v6.3-net-ethernet-mtk_eth_soc-fix-flow_offload-related-re.patch b/target/linux/generic/backport-5.15/730-11-v6.3-net-ethernet-mtk_eth_soc-fix-flow_offload-related-re.patch
new file mode 100644 (file)
index 0000000..54e48df
--- /dev/null
@@ -0,0 +1,52 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 17 Nov 2022 11:58:21 +0100
+Subject: [PATCH] net: ethernet: mtk_eth_soc: fix flow_offload related refcount
+ bug
+
+Since we call flow_block_cb_decref on FLOW_BLOCK_UNBIND, we need to call
+flow_block_cb_incref unconditionally, even for a newly allocated cb.
+Fixes a use-after-free bug
+
+Fixes: 502e84e2382d ("net: ethernet: mtk_eth_soc: add flow offloading support")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
++++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+@@ -554,6 +554,7 @@ mtk_eth_setup_tc_block(struct net_device
+       struct mtk_eth *eth = mac->hw;
+       static LIST_HEAD(block_cb_list);
+       struct flow_block_cb *block_cb;
++      bool register_block = false;
+       flow_setup_cb_t *cb;
+       if (!eth->soc->offload_version)
+@@ -568,16 +569,20 @@ mtk_eth_setup_tc_block(struct net_device
+       switch (f->command) {
+       case FLOW_BLOCK_BIND:
+               block_cb = flow_block_cb_lookup(f->block, cb, dev);
+-              if (block_cb) {
+-                      flow_block_cb_incref(block_cb);
+-                      return 0;
++              if (!block_cb) {
++                      block_cb = flow_block_cb_alloc(cb, dev, dev, NULL);
++                      if (IS_ERR(block_cb))
++                              return PTR_ERR(block_cb);
++
++                      register_block = true;
+               }
+-              block_cb = flow_block_cb_alloc(cb, dev, dev, NULL);
+-              if (IS_ERR(block_cb))
+-                      return PTR_ERR(block_cb);
+-              flow_block_cb_add(block_cb, f);
+-              list_add_tail(&block_cb->driver_list, &block_cb_list);
++              flow_block_cb_incref(block_cb);
++
++              if (register_block) {
++                      flow_block_cb_add(block_cb, f);
++                      list_add_tail(&block_cb->driver_list, &block_cb_list);
++              }
+               return 0;
+       case FLOW_BLOCK_UNBIND:
+               block_cb = flow_block_cb_lookup(f->block, cb, dev);