mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-30 02:29:01 +00:00
1d8baafc43
Move it to pending, since it wasn't actually accepted upstream yet. Fixes potential issues when doing offload between multiple MACs. Signed-off-by: Felix Fietkau <nbd@nbd.name>
62 lines
1.9 KiB
Diff
62 lines
1.9 KiB
Diff
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);
|
|
}
|