On 7/29/26 8:19 AM, yang zhuorao wrote:
> 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 extracting the exec_level management into helpers
> ovs_exec_level_enter() and ovs_exec_level_exit(), and calling them
> unconditionally for all synchronous clone recursion edges. When the
> limit is exceeded the packet is dropped with a net_crit_ratelimited()
> log, consistent with the existing handling in ovs_execute_actions()
> which now also uses the same helpers.
>
> 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]>
> ---
> Changes in v2:
> - Extract exec_level management into ovs_exec_level_enter() /
> ovs_exec_level_exit() helpers, consolidating the recursion
> check with ovs_execute_actions() (Aaron)
> - Add net_crit_ratelimited() log on limit hit instead of
> silently dropping (Aaron)
> - Refactor ovs_execute_actions() to use the same helpers
> - CC netdev maintainers
>
> v1:
> https://lore.kernel.org/netdev/[email protected]
Please, avoid sending new versions until the conversation on v1 is concluded.
We're all in different time zones and it takes time to analyze things and to
respond. Posting new versions right away is just wasting time and CI resources.
Also, since you're sending these patches publicly, you should not involve
the security team (moved to Bcc).
Best regards, Ilya Maximets.
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev