From 8dd97e20a635f6861f5694b34839840655c76948 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Mon, 20 Jul 2026 12:08:56 -0400 Subject: [PATCH] MT#55283 make skb copies on demand Reuse the existing skb whenever possible for normal forwarding. Make a copy only when needed: when decrypying or encrypting, or when there's not enough space. Change-Id: Ia3b020e65dcfcf0c4a63502607431144af44b1f4 --- kernel-module/nft_rtpengine.c | 70 ++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/kernel-module/nft_rtpengine.c b/kernel-module/nft_rtpengine.c index 9d5898bf0..dbeb13dd9 100644 --- a/kernel-module/nft_rtpengine.c +++ b/kernel-module/nft_rtpengine.c @@ -5439,6 +5439,14 @@ static int send_proxy_packet4(struct sk_buff *skb, const struct re_address *src, datalen = skb->len; + if (skb_headroom(skb) < sizeof(*uh) + sizeof(*ih)) { + struct sk_buff *skb2 = skb_copy_expand(skb, MAX_HEADER, MAX_SKB_TAIL_ROOM, GFP_ATOMIC); + if (!skb2) + goto drop; + kfree_skb(skb); + skb = skb2; + } + uh = (void *) skb_push(skb, sizeof(*uh)); skb_reset_transport_header(skb); ih = (void *) skb_push(skb, sizeof(*ih)); @@ -5547,6 +5555,14 @@ static int send_proxy_packet6(struct sk_buff *skb, const struct re_address *src, datalen = skb->len; + if (skb_headroom(skb) < sizeof(*uh) + sizeof(*ih)) { + struct sk_buff *skb2 = skb_copy_expand(skb, MAX_HEADER, MAX_SKB_TAIL_ROOM, GFP_ATOMIC); + if (!skb2) + goto drop; + kfree_skb(skb); + skb = skb2; + } + uh = (void *) skb_push(skb, sizeof(*uh)); skb_reset_transport_header(skb); ih = (void *) skb_push(skb, sizeof(*ih)); @@ -6672,6 +6688,15 @@ static struct sk_buff *proxy_packet_output_rtXp(struct sk_buff *skb, struct rtpe rtp->rtp_header->ssrc = o->output.ssrc_out[ssrc_idx]; } + // copy to encrypt/authenticate needed? + if (o->output.encrypt.hmac != REH_NULL || o->encrypt_rtp.cipher->encrypt_rtp) { + struct sk_buff *skb2 = rtpe_skb_cpy(skb, rtp, rtp); + if (!skb2) + goto drop; + kfree_skb(skb); + skb = skb2; + } + pkt_idx = proxy_packet_srtp_encrypt(skb, &o->encrypt_rtp, &o->output.encrypt, rtp, ssrc_idx, o->output.ssrc_stats); @@ -7136,13 +7161,6 @@ static int rtpengine46(struct sk_buff *oskb, } } - skb = rtpe_skb_cpy(oskb, &rtp, &rtp); - if (!skb) - goto out_target; - - rtpe_pull_trim(skb, datalen); - data = skb->data; - if (rtp.ok) { // RTP ok rtp_pt_idx = rtp_payload_type(rtp.rtp_header, &g->target, &g->last_pt); @@ -7161,6 +7179,15 @@ static int rtpengine46(struct sk_buff *oskb, pkt_idx = rtp_packet_index(&g->decrypt_rtp, &g->target.decrypt, rtp.rtp_header, ssrc_idx, g->target.ssrc_stats); + + // copy to decrypt/authenticate needed? + if (g->target.decrypt.hmac != REH_NULL || g->decrypt_rtp.cipher->decrypt_rtp) { + errstr = "out of memory"; + skb = rtpe_skb_cpy(oskb, &rtp, &rtp); + if (!skb) + goto out_error; + } + errstr = "SRTP authentication tag mismatch"; if (srtp_auth_validate(&g->decrypt_rtp, &g->target.decrypt, &rtp, &pkt_idx, ssrc_idx, g->target.ssrc_stats)) @@ -7186,6 +7213,16 @@ static int rtpengine46(struct sk_buff *oskb, err = srtp_decrypt(&g->decrypt_rtp, &g->target.decrypt, &rtp, &pkt_idx); if (err < 0) goto out_error; + + // everything passed, we will definitely handle this packet + nf_action = NF_DROP; + + // if we haven't made a copy yet, we can use the original skb directly + if (!skb) + skb = skb_get(oskb); + + rtpe_pull_trim(skb, datalen); + if (err == 1) update_packet_index(&g->decrypt_rtp, &g->target.decrypt, pkt_idx, ssrc_idx, g->target.ssrc_stats); @@ -7201,11 +7238,19 @@ static int rtpengine46(struct sk_buff *oskb, rtp.payload[8], rtp.payload[9], rtp.payload[10], rtp.payload[11], rtp.payload[12], rtp.payload[13], rtp.payload[14], rtp.payload[15], rtp.payload[16], rtp.payload[17], rtp.payload[18], rtp.payload[19]); - - nf_action = NF_DROP; } else if (is_rtcp != NOT_RTCP && rtp.rtcp) { pkt_idx = 0; + + // always make a copy for RTCP + // (even if technically not needed for NF_DROP case below) + errstr = "out of memory"; + skb = rtpe_skb_cpy(oskb, &rtp, &rtp); + if (!skb) + goto out_error; + + rtpe_pull_trim(skb, datalen); + err = srtcp_auth_validate(&g->decrypt_rtcp, &g->target.decrypt, &rtp, &pkt_idx); errstr = "SRTCP authentication tag mismatch"; if (err == -1) @@ -7224,9 +7269,14 @@ static int rtpengine46(struct sk_buff *oskb, else nf_action = NF_DROP; } - else + else { + // forward non-RTP/RTCP. no copy needed + skb = skb_get(oskb); nf_action = NF_DROP; + rtpe_pull_trim(skb, datalen); + } + if (g->target.do_intercept) { DBG("do_intercept is set\n"); stream = get_stream_lock(NULL, g->target.intercept_stream_idx);