diff options
Diffstat (limited to 'target/linux/generic/pending-5.15')
-rw-r--r-- | target/linux/generic/pending-5.15/735-net-ethernet-mtk_eth_soc-fix-flow_offload-related-re.patch | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/target/linux/generic/pending-5.15/735-net-ethernet-mtk_eth_soc-fix-flow_offload-related-re.patch b/target/linux/generic/pending-5.15/735-net-ethernet-mtk_eth_soc-fix-flow_offload-related-re.patch new file mode 100644 index 0000000000..acbdec2159 --- /dev/null +++ b/target/linux/generic/pending-5.15/735-net-ethernet-mtk_eth_soc-fix-flow_offload-related-re.patch @@ -0,0 +1,61 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Mon, 20 Mar 2023 15:49:15 +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. Also fix the accidentally inverted refcount +check on unbind. + +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 +@@ -561,6 +561,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) +@@ -575,23 +576,27 @@ 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); + if (!block_cb) + return -ENOENT; + +- if (flow_block_cb_decref(block_cb)) { ++ if (!flow_block_cb_decref(block_cb)) { + flow_block_cb_remove(block_cb, f); + list_del(&block_cb->driver_list); + } |