ccm_tx_work_expired() uses interval_to_us() to convert the configured exp_interval enum into a microsecond delay, then passes it to queue_delayed_work() to schedule the next iteration. The ccm_tx_dwork callback re-arms the same delayed_work struct at the end of each invocation, forming a repeating timer. interval_to_us() returns 0 for BR_CFM_CCM_INTERVAL_NONE and any out-of-range enum value. When this 0 is passed to queue_delayed_work() as the delay, the work item fires immediately and re-arms itself with zero delay again, creating an infinite tight loop. Each iteration allocates an skb via ccm_frame_build() and queues it for transmission. The skbs pile up faster than the network stack can free them because the worker never yields the CPU, rapidly exhausting all kernel memory until OOM deadlock panic. Since CC config and CCM TX are independent netlink commands that can be issued in any order, there is no single configuration entry point where rejecting interval=0 would cover all cases. Fix this by checking the interval at the start of ccm_tx_work_expired() and stopping transmission immediately if it is zero. Set period to 0 so that br_cfm_cc_ccm_tx() correctly sees transmission as stopped and can restart it later if a valid interval is configured. This also avoids transmitting a CCM frame with an invalid interval value. Fixes: a806ad8ee2aa ("bridge: cfm: Kernel space implementation of CFM. CCM frame TX added.") Reported-by: Weiming Shi Signed-off-by: Xiang Mei --- net/bridge/br_cfm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/bridge/br_cfm.c b/net/bridge/br_cfm.c index 118c7ea48c35..688c51250630 100644 --- a/net/bridge/br_cfm.c +++ b/net/bridge/br_cfm.c @@ -274,6 +274,13 @@ static void ccm_tx_work_expired(struct work_struct *work) del_work = to_delayed_work(work); mep = container_of(del_work, struct br_cfm_mep, ccm_tx_dwork); + interval_us = interval_to_us(mep->cc_config.exp_interval); + if (!interval_us) { + /* No valid interval - stop transmission */ + mep->cc_ccm_tx_info.period = 0; + return; + } + if (time_before_eq(mep->ccm_tx_end, jiffies)) { /* Transmission period has ended */ mep->cc_ccm_tx_info.period = 0; @@ -284,7 +291,6 @@ static void ccm_tx_work_expired(struct work_struct *work) if (skb) ccm_frame_tx(skb); - interval_us = interval_to_us(mep->cc_config.exp_interval); queue_delayed_work(system_percpu_wq, &mep->ccm_tx_dwork, usecs_to_jiffies(interval_us)); } -- 2.43.0