clone_execute() only increments and decrements exec_level when
clone_flow_key is true. When clone_flow_key is false the optimized
path reuses the original flow key and calls do_execute_actions()
directly without updating the recursion counter, making those layers
invisible to the OVS_RECURSION_LIMIT check in ovs_execute_actions().
A single action tree allows up to OVS_COPY_ACTIONS_MAX_DEPTH (16)
nested clone actions. When the innermost clone contains a RECIRC
that selects another flow with its own 16-layer validation budget,
multiple trees of unaccounted recursion can be stacked. The deferred
action threshold (OVS_DEFERRED_ACTION_THRESHOLD =
OVS_RECURSION_LIMIT - 2 = 3) allows three synchronous recirc levels
before clone_key() forces deferral, yielding 3 x 16 = 48 layers of
synchronous, unaccounted clone recursion.
Per-layer stack usage is approximately 296 bytes (from disassembly:
do_execute_actions() allocates 0x98 bytes, clone_execute() allocates
0x20 bytes, plus saved registers and return address). 48 layers
consume ~14,208 bytes before recirc, flow lookup, Netlink, and base
call frames, exceeding the 16 KiB x86_64 task stack and hitting the
guard page.
An unprivileged user can trigger this from a private user/net
namespace (clone(CLONE_NEWUSER | CLONE_NEWNET)) by installing three
flow rules each with 16 nested clone actions linked by RECIRC, then
injecting a single packet via OVS_PACKET_CMD_EXECUTE. The result is
a kernel panic:
BUG: TASK stack guard page was hit ...
CPU: 0 UID: 1000 PID: 85 ... 7.2.0-rc5+
RIP: 0010:clone_execute+0x5a/0x2c0 [openvswitch]
[do_execute_actions / clone_execute alternating repeatedly]
Kernel panic - not syncing: Fatal exception in interrupt
Fix this by unconditionally incrementing exec_level for all
synchronous clone recursion edges and checking OVS_RECURSION_LIMIT
before calling do_execute_actions(). When the limit is exceeded the
packet is dropped and -ENETDOWN is returned, consistent with the
existing handling in ovs_execute_actions().
Tested on Linux 7.2.0-rc5+ (mainline HEAD 62cc90241548), x86_64,
CONFIG_VMAP_STACK=y, CONFIG_OPENVSWITCH=m, isolated QEMU guest.
Confirmed that the PoC (./poc_clone_overflow 2 16 3, run as UID 1000)
no longer triggers a panic with this patch applied.
Fixes: b233504033db ("openvswitch: kernel datapath clone action")
Cc: [email protected]
Reported-by: yang zhuorao <[email protected]>
Signed-off-by: yang zhuorao <[email protected]>
---
Reproducer (C, single file, available upon request):
gcc -O2 -Wall -o poc_clone_overflow poc_clone_overflow.c
./poc_clone_overflow 2 16 3 # as unprivileged user
The PoC creates a private user/net namespace, installs three flows
each with 16 nested clone actions linked by RECIRC, and injects a
triggering packet. Prerequisites: CONFIG_OPENVSWITCH=m/y loaded,
unprivileged user namespace creation allowed.
Verified unfixed in Linus mainline (62cc90241548), net (97ac08560d23),
and net-next (a50eba1e778a) as of 2026-07-27.
net/openvswitch/actions.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index 513fca6a8e8a..05fbf5c07200 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -1497,14 +1497,19 @@ static int clone_execute(struct datapath *dp, struct
sk_buff *skb,
if (clone) {
int err = 0;
if (actions) { /* Sample action */
- if (clone_flow_key)
- __this_cpu_inc(ovs_pcpu_storage->exec_level);
+ __this_cpu_inc(ovs_pcpu_storage->exec_level);
+
+ if
(unlikely(__this_cpu_read(ovs_pcpu_storage->exec_level) >
+ OVS_RECURSION_LIMIT)) {
+ __this_cpu_dec(ovs_pcpu_storage->exec_level);
+ ovs_kfree_skb_reason(skb,
OVS_DROP_RECURSION_LIMIT);
+ return -ENETDOWN;
+ }
err = do_execute_actions(dp, skb, clone,
actions, len);
- if (clone_flow_key)
- __this_cpu_dec(ovs_pcpu_storage->exec_level);
+ __this_cpu_dec(ovs_pcpu_storage->exec_level);
} else { /* Recirc action */
clone->recirc_id = recirc_id;
ovs_dp_process_packet(skb, clone);
--
2.43.0
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev