From: Ruide Cao nsh_gso_segment() currently redispatches the inner payload through skb_mac_gso_segment() after stripping one NSH header. For nested NSH payloads, this can recurse back into nsh_gso_segment() through repeated GSO redispatch. The existing validation added by commit af50e4ba34f4 ("nsh: fix infinite loop") only covers invalid header lengths and does not prevent recursive redispatch across nested NSH payload chains. Use the existing dev_xmit_recursion mechanism to bound recursive redispatch, as with other nested tunnel-like paths in the networking stack. If the recursion limit is exceeded, abort segmentation and unwind the skb state through the existing error path. This keeps the existing protocol behavior for normal packets while preventing pathological recursion without adding NSH-specific protocol unrolling. Fixes: c411ed854584 ("nsh: add GSO support") Cc: stable@kernel.org Reported-by: Yuan Tan Reported-by: Yifan Wu Reported-by: Juefei Pu Reported-by: Xin Liu Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202604302359.kU59LnTI-lkp@intel.com/ Co-developed-by: Xiao Liu Signed-off-by: Xiao Liu Signed-off-by: Ruide Cao Signed-off-by: Ren Wei --- changes in v2: - Rework the fix to use dev_xmit_recursion() instead of iteratively unwrapping nested NSH payloads. - Abort segmentation when the recursion limit is exceeded and unwind skb state through skb_gso_error_unwind(). - Rewrite the commit message to reflect the recursion-limit approach. - v1 link: https://lore.kernel.org/all/6112cce99b4e3571444a616d0fb19e91e2fcca72.1776597598.git.caoruide123@gmail.com/ net/nsh/nsh.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/net/nsh/nsh.c b/net/nsh/nsh.c index bfb7758063f3..d83e4e2da41e 100644 --- a/net/nsh/nsh.c +++ b/net/nsh/nsh.c @@ -107,12 +107,14 @@ static struct sk_buff *nsh_gso_segment(struct sk_buff *skb, skb->protocol = proto; features &= NETIF_F_SG; + if (dev_xmit_recursion()) + goto err; + + dev_xmit_recursion_inc(); segs = skb_mac_gso_segment(skb, features); - if (IS_ERR_OR_NULL(segs)) { - skb_gso_error_unwind(skb, htons(ETH_P_NSH), nsh_len, - mac_offset, mac_len); - goto out; - } + dev_xmit_recursion_dec(); + if (IS_ERR_OR_NULL(segs)) + goto err; for (skb = segs; skb; skb = skb->next) { skb->protocol = outer_proto; @@ -122,6 +124,11 @@ static struct sk_buff *nsh_gso_segment(struct sk_buff *skb, skb->mac_len = mac_len; } + goto out; + +err: + skb_gso_error_unwind(skb, outer_proto, nsh_len, mac_offset, mac_len); + out: return segs; } -- 2.34.1