Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2218172/?format=api
{ "id": 2218172, "url": "http://patchwork.ozlabs.org/api/patches/2218172/?format=api", "web_url": "http://patchwork.ozlabs.org/project/openvswitch/patch/20260331143925.378778-1-aconole@redhat.com/", "project": { "id": 47, "url": "http://patchwork.ozlabs.org/api/projects/47/?format=api", "name": "Open vSwitch", "link_name": "openvswitch", "list_id": "ovs-dev.openvswitch.org", "list_email": "ovs-dev@openvswitch.org", "web_url": "http://openvswitch.org/", "scm_url": "git@github.com:openvswitch/ovs.git", "webscm_url": "https://github.com/openvswitch/ovs", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260331143925.378778-1-aconole@redhat.com>", "list_archive_url": null, "date": "2026-03-31T14:39:23", "name": "[ovs-dev] conntrack: Fix replace_substring to handle larger packets.", "commit_ref": "7c31be6d6c34fc8432a93e2e184fe8bb71907d22", "pull_url": null, "state": "accepted", "archived": false, "hash": "a2a9ef3af2ebdcd7da2604bb2bee97065c1d4c8f", "submitter": { "id": 67184, "url": "http://patchwork.ozlabs.org/api/people/67184/?format=api", "name": "Aaron Conole", "email": "aconole@redhat.com" }, "delegate": { "id": 57772, "url": "http://patchwork.ozlabs.org/api/users/57772/?format=api", "username": "imaximets", "first_name": "Ilya", "last_name": "Maximets", "email": "i.maximets@samsung.com" }, "mbox": "http://patchwork.ozlabs.org/project/openvswitch/patch/20260331143925.378778-1-aconole@redhat.com/mbox/", "series": [ { "id": 498212, "url": "http://patchwork.ozlabs.org/api/series/498212/?format=api", "web_url": "http://patchwork.ozlabs.org/project/openvswitch/list/?series=498212", "date": "2026-03-31T14:39:23", "name": "[ovs-dev] conntrack: Fix replace_substring to handle larger packets.", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/498212/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2218172/comments/", "check": "warning", "checks": "http://patchwork.ozlabs.org/api/patches/2218172/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<ovs-dev-bounces@openvswitch.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "dev@openvswitch.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "ovs-dev@lists.linuxfoundation.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=SmtLbAlu;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org\n (client-ip=2605:bc80:3010::133; helo=smtp2.osuosl.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org)", "smtp2.osuosl.org;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key)\n header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=SmtLbAlu", "smtp2.osuosl.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com" ], "Received": [ "from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4flW3f0JVkz1y1q\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 01 Apr 2026 01:39:41 +1100 (AEDT)", "from localhost (localhost [127.0.0.1])\n\tby smtp2.osuosl.org (Postfix) with ESMTP id E62FD406AA;\n\tTue, 31 Mar 2026 14:39:39 +0000 (UTC)", "from smtp2.osuosl.org ([127.0.0.1])\n by localhost (smtp2.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id 0Vo0w6lw6fdT; Tue, 31 Mar 2026 14:39:38 +0000 (UTC)", "from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56])\n\tby smtp2.osuosl.org (Postfix) with ESMTPS id 8FB1940051;\n\tTue, 31 Mar 2026 14:39:38 +0000 (UTC)", "from lf-lists.osuosl.org (localhost [127.0.0.1])\n\tby lists.linuxfoundation.org (Postfix) with ESMTP id 4BA9BC054A;\n\tTue, 31 Mar 2026 14:39:38 +0000 (UTC)", "from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n by lists.linuxfoundation.org (Postfix) with ESMTP id 47F98C0549\n for <dev@openvswitch.org>; Tue, 31 Mar 2026 14:39:37 +0000 (UTC)", "from localhost (localhost [127.0.0.1])\n by smtp2.osuosl.org (Postfix) with ESMTP id 289A440058\n for <dev@openvswitch.org>; Tue, 31 Mar 2026 14:39:37 +0000 (UTC)", "from smtp2.osuosl.org ([127.0.0.1])\n by localhost (smtp2.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP\n id 1WhpxtCuju8H for <dev@openvswitch.org>;\n Tue, 31 Mar 2026 14:39:36 +0000 (UTC)", "from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.129.124])\n by smtp2.osuosl.org (Postfix) with ESMTPS id F102940051\n for <dev@openvswitch.org>; Tue, 31 Mar 2026 14:39:35 +0000 (UTC)", "from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-483-keD7sQ0KNdm1JoUc8ioTSg-1; Tue,\n 31 Mar 2026 10:39:28 -0400", "from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 52DCB195608E; Tue, 31 Mar 2026 14:39:27 +0000 (UTC)", "from RHTRH0061144.redhat.com (unknown [10.22.88.33])\n by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id 7CEC6180036E; Tue, 31 Mar 2026 14:39:26 +0000 (UTC)" ], "X-Virus-Scanned": [ "amavis at osuosl.org", "amavis at osuosl.org" ], "X-Comment": "SPF check N/A for local connections - client-ip=140.211.9.56;\n helo=lists.linuxfoundation.org;\n envelope-from=ovs-dev-bounces@openvswitch.org; receiver=<UNKNOWN> ", "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 smtp2.osuosl.org 8FB1940051", "OpenDKIM Filter v2.11.0 smtp2.osuosl.org F102940051" ], "Received-SPF": "Pass (mailfrom) identity=mailfrom; client-ip=170.10.129.124;\n helo=us-smtp-delivery-124.mimecast.com; envelope-from=aconole@redhat.com;\n receiver=<UNKNOWN>", "DMARC-Filter": "OpenDMARC Filter v1.4.2 smtp2.osuosl.org F102940051", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1774967974;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n content-transfer-encoding:content-transfer-encoding;\n bh=lELbZhGBExa5kJU3jb2sGLy9QTWc/XQjVUP2GmutNIk=;\n b=SmtLbAlushv+WiAWozYo6n8YsDjgrToUHTWu5Pizy3orSD0/ECIBCKxqQzYsiTP7KXtocj\n tyAAvQwLXtQ1QJS1mUcvv2xtu3bjcacreFY7mdJKumXyFjuvrwogNq3aEBDHlIbXfPjt55\n 4R9+eGn1T5y6EJTlvmD0xaAVAXi+uek=", "X-MC-Unique": "keD7sQ0KNdm1JoUc8ioTSg-1", "X-Mimecast-MFC-AGG-ID": "keD7sQ0KNdm1JoUc8ioTSg_1774967967", "To": "dev@openvswitch.org", "Cc": "Ilya Maximets <i.maximets@ovn.org>,\n Seiji Sakurai <Seiji.Sakurai@outlook.com>", "Date": "Tue, 31 Mar 2026 10:39:23 -0400", "Message-ID": "<20260331143925.378778-1-aconole@redhat.com>", "MIME-Version": "1.0", "X-Scanned-By": "MIMEDefang 3.4.1 on 10.30.177.93", "X-Mimecast-Spam-Score": "0", "X-Mimecast-MFC-PROC-ID": "Siz7QmMHfFvHKmBkYtINIf0USodNIAJ3JOZn0AYWGA0_1774967967", "X-Mimecast-Originator": "redhat.com", "Subject": "[ovs-dev] [PATCH] conntrack: Fix replace_substring to handle larger\n packets.", "X-BeenThere": "ovs-dev@openvswitch.org", "X-Mailman-Version": "2.1.30", "Precedence": "list", "List-Id": "<ovs-dev.openvswitch.org>", "List-Unsubscribe": "<https://mail.openvswitch.org/mailman/options/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=unsubscribe>", "List-Archive": "<http://mail.openvswitch.org/pipermail/ovs-dev/>", "List-Post": "<mailto:ovs-dev@openvswitch.org>", "List-Help": "<mailto:ovs-dev-request@openvswitch.org?subject=help>", "List-Subscribe": "<https://mail.openvswitch.org/mailman/listinfo/ovs-dev>,\n <mailto:ovs-dev-request@openvswitch.org?subject=subscribe>", "From": "Aaron Conole via dev <ovs-dev@openvswitch.org>", "Reply-To": "Aaron Conole <aconole@redhat.com>", "Content-Type": "text/plain; charset=\"utf-8\"", "Content-Transfer-Encoding": "base64", "Errors-To": "ovs-dev-bounces@openvswitch.org", "Sender": "\"dev\" <ovs-dev-bounces@openvswitch.org>" }, "content": "There is a buffer size calculation issue in replace_string that can\nresult in a heap overflow with a specially crafted FTP packet. This\nis a result of integer truncation when downscaling from size_t into\nuint8_t size. Correct this by setting the types to size_t until the\nunderlying memmove to keep the sizes intact.\n\nThe total_size, substr_size, and rep_str_size are expected to all be\nsane values for the memmove, and modify_packet also expects this, so\ndocument that as well. In the case of FTP, those are enforced in\nrepl_ftp_v*_addr at the checks for MAX_FTP_V*_NAT_DELTA, and the\npacket data itself should be sanitized by the ovs_strlcpy that runs\nearly to extract a string of appropriate length.\n\nFixes: bd5e81a0e596 (\"Userspace Datapath: Add ALG infra and FTP.\")\nReported-by: Seiji Sakurai <Seiji.Sakurai@outlook.com>\nSigned-off-by: Aaron Conole <aconole@redhat.com>\n---\n AUTHORS.rst | 1 +\n lib/conntrack.c | 9 +-\n tests/library.at | 4 +\n tests/test-conntrack.c | 182 +++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 193 insertions(+), 3 deletions(-)", "diff": "diff --git a/AUTHORS.rst b/AUTHORS.rst\nindex 037851ad1e..8e1bf6c075 100644\n--- a/AUTHORS.rst\n+++ b/AUTHORS.rst\n@@ -763,6 +763,7 @@ Scott Hendricks\n Sean Brady sbrady@gtfservices.com\n Sebastian Andrzej Siewior sebastian@breakpoint.cc\n Sébastien RICCIO sr@swisscenter.com\n+Seiji Sakurai Seiji.Sakurai@outlook.com\n Shweta Seth shwseth@cisco.com\n Simon Jouet simon.jouet@gmail.com\n Spiro Kourtessis spiro@vmware.com\ndiff --git a/lib/conntrack.c b/lib/conntrack.c\nindex 921f63cfe8..e25cc25ca8 100644\n--- a/lib/conntrack.c\n+++ b/lib/conntrack.c\n@@ -3242,9 +3242,9 @@ expectation_create(struct conntrack *ct, ovs_be16 dst_port,\n }\n \n static void\n-replace_substring(char *substr, uint8_t substr_size,\n- uint8_t total_size, char *rep_str,\n- uint8_t rep_str_size)\n+replace_substring(char *substr, size_t substr_size,\n+ size_t total_size, char *rep_str,\n+ size_t rep_str_size)\n {\n memmove(substr + rep_str_size, substr + substr_size,\n total_size - substr_size);\n@@ -3266,6 +3266,9 @@ repl_bytes(char *str, char c1, char c2, int max)\n }\n }\n \n+/* Replaces a substring in the packet and rewrites the packet\n+ * size to match. This function assumes the caller has verified\n+ * the lengths to prevent under/over flow. */\n static void\n modify_packet(struct dp_packet *pkt, char *pkt_str, size_t size,\n char *repl_str, size_t repl_size,\ndiff --git a/tests/library.at b/tests/library.at\nindex 106c0abe76..449f15fd5a 100644\n--- a/tests/library.at\n+++ b/tests/library.at\n@@ -303,3 +303,7 @@ AT_CHECK([ovstest test-cooperative-multitasking-nested-yield], [0], [], [dnl\n cooperative_multitasking|ERR|Nested yield avoided, this is a bug! Enable debug logging for more details.\n ])\n AT_CLEANUP\n+\n+AT_SETUP([Conntrack Library - FTP ALG parsing])\n+AT_CHECK([ovstest test-conntrack ftp-alg-large-payload])\n+AT_CLEANUP\ndiff --git a/tests/test-conntrack.c b/tests/test-conntrack.c\nindex dc8d6cff94..81f414f39f 100644\n--- a/tests/test-conntrack.c\n+++ b/tests/test-conntrack.c\n@@ -54,6 +54,100 @@ build_packet(uint16_t udp_src, uint16_t udp_dst, ovs_be16 *dl_type)\n return pkt;\n }\n \n+/* Build an Ethernet + IPv4 packet. If 'pkt' is NULL a new buffer is\n+ * allocated with 64 bytes of extra headroom so the FTP MTU guard passes.\n+ * The buffer is populated up through the IP header; l4 is set to point\n+ * directly after the IP header. The caller is responsible for filling\n+ * the L4 header and payload that follow. */\n+static struct dp_packet *\n+build_eth_ip_packet(struct dp_packet *pkt, struct eth_addr eth_src,\n+ struct eth_addr eth_dst, ovs_be32 ip_src, ovs_be32 ip_dst,\n+ uint8_t proto, uint16_t payload_alloc)\n+{\n+ struct ip_header *iph;\n+ uint16_t proto_len;\n+\n+ switch (proto) {\n+ case IPPROTO_TCP: proto_len = TCP_HEADER_LEN; break;\n+ case IPPROTO_UDP: proto_len = UDP_HEADER_LEN; break;\n+ case IPPROTO_ICMP: proto_len = ICMP_HEADER_LEN; break;\n+ default: proto_len = 0; break;\n+ }\n+\n+ if (pkt == NULL) {\n+ /* 64-byte extra headroom keeps dp_packet_get_allocated() large enough\n+ * that the FTP V4 MTU guard (orig_used_size + 8 <= allocated) passes\n+ * even when the packet is near its maximum size. */\n+ pkt = dp_packet_new_with_headroom(ETH_HEADER_LEN + IP_HEADER_LEN\n+ + proto_len + payload_alloc, 64);\n+ }\n+\n+ eth_compose(pkt, eth_src, eth_dst, ETH_TYPE_IP,\n+ IP_HEADER_LEN + proto_len + payload_alloc);\n+ iph = dp_packet_l3(pkt);\n+ iph->ip_ihl_ver = IP_IHL_VER(5, 4);\n+ iph->ip_tot_len = htons(IP_HEADER_LEN + proto_len + payload_alloc);\n+ iph->ip_ttl = 64;\n+ iph->ip_proto = proto;\n+ packet_set_ipv4_addr(pkt, &iph->ip_src, ip_src);\n+ packet_set_ipv4_addr(pkt, &iph->ip_dst, ip_dst);\n+ iph->ip_csum = csum(iph, IP_HEADER_LEN);\n+ dp_packet_set_l4(pkt, (char *) iph + IP_HEADER_LEN);\n+ return pkt;\n+}\n+\n+/* Fill the TCP header and optional payload for a packet previously built with\n+ * build_eth_ip_packet(). The 'payload' buffer of 'payload_len' bytes is\n+ * appended after the TCP header if non-NULL. IP total-length, IP checksum,\n+ * and TCP checksum are all updated to reflect the final packet contents. */\n+static struct dp_packet *\n+build_tcp_packet(struct dp_packet *pkt, uint16_t tcp_src, uint16_t tcp_dst,\n+ uint16_t tcp_flags, const char *tcp_payload,\n+ size_t payload_len)\n+{\n+ struct tcp_header *tcph;\n+ struct ip_header *iph;\n+ uint16_t ip_tot_len;\n+ uint32_t tcp_csum;\n+ struct flow flow;\n+\n+ ovs_assert(pkt);\n+ tcph = dp_packet_l4(pkt);\n+ ovs_assert(tcph);\n+\n+ tcph->tcp_src = htons(tcp_src);\n+ tcph->tcp_dst = htons(tcp_dst);\n+ put_16aligned_be32(&tcph->tcp_seq, 0);\n+ put_16aligned_be32(&tcph->tcp_ack, 0);\n+ tcph->tcp_ctl = TCP_CTL(tcp_flags, TCP_HEADER_LEN / 4);\n+ tcph->tcp_winsz = htons(65535);\n+ tcph->tcp_csum = 0;\n+ tcph->tcp_urg = 0;\n+\n+ if (tcp_payload && payload_len > 0) {\n+ /* The caller must have pre-allocated space via build_eth_ip_packet's\n+ * payload_alloc argument. Write directly to avoid a realloc that\n+ * would lose the extra headroom required by the FTP MTU guard. */\n+ memcpy((char *) tcph + TCP_HEADER_LEN, tcp_payload, payload_len);\n+ }\n+\n+ /* Update IP total length and recompute IP checksum. */\n+ iph = dp_packet_l3(pkt);\n+ ip_tot_len = IP_HEADER_LEN + TCP_HEADER_LEN + payload_len;\n+ iph->ip_tot_len = htons(ip_tot_len);\n+ iph->ip_csum = 0;\n+ iph->ip_csum = csum(iph, IP_HEADER_LEN);\n+\n+ /* Compute TCP checksum over pseudo-header + TCP segment. */\n+ tcp_csum = packet_csum_pseudoheader(iph);\n+ tcph->tcp_csum = csum_finish(\n+ csum_continue(tcp_csum, tcph, TCP_HEADER_LEN + payload_len));\n+\n+ /* Set l3/l4 offsets so conntrack can extract a flow key. */\n+ flow_extract(pkt, &flow);\n+ return pkt;\n+}\n+\n static struct dp_packet_batch *\n prepare_packets(size_t n, bool change, unsigned tid, ovs_be16 *dl_type)\n {\n@@ -397,6 +491,87 @@ test_pcap(struct ovs_cmdl_context *ctx)\n conntrack_destroy(ct);\n ovs_pcap_close(pcap);\n }\n+\f\n+/* ALG related testing. */\n+\n+/* FTP IPv4 PORT payload for testing. */\n+#define FTP_PORT_CMD_STR \"PORT 192,168,123,2,113,42\\r\\n\"\n+#define FTP_CMD_PAD 234\n+#define FTP_PAYLOAD_LEN (sizeof FTP_PORT_CMD_STR - 1 + FTP_CMD_PAD)\n+\n+/* Test modify_packet wrapping.\n+ *\n+ * The test builds a minimal FTP control-channel exchange:\n+ * 1. A TCP SYN that creates a conntrack entry with helper=ftp and SNAT.\n+ * 2. A PSH|ACK carrying \"PORT 192,168,123,2,113,42\\r\\n\" padded to exactly\n+ * 261 bytes of TCP payload, which makes total_size == 256.\n+ *\n+ * After the PORT packet is processed the address field in the payload must\n+ * read \"192,168,1,1\" (the SNAT address with dots replaced by commas). */\n+static void\n+test_ftp_alg_large_payload(struct ovs_cmdl_context *ctx OVS_UNUSED)\n+{\n+ /* Packet endpoints. */\n+ struct eth_addr eth_src = ETH_ADDR_C(00, 01, 02, 03, 04, 05);\n+ struct eth_addr eth_dst = ETH_ADDR_C(00, 06, 07, 08, 09, 0a);\n+ ovs_be32 ip_src = inet_addr(\"192.168.123.2\"); /* FTP client */\n+ ovs_be32 ip_dst = inet_addr(\"192.168.1.1\"); /* FTP server / SNAT addr */\n+ uint16_t sport = 12345;\n+ uint16_t dport = 21; /* FTP control port */\n+\n+ /* SNAT: rewrite client address to 192.168.1.1 in PORT commands. */\n+ struct nat_action_info_t nat_info;\n+ memset(&nat_info, 0, sizeof nat_info);\n+ nat_info.nat_action = NAT_ACTION_SRC;\n+ nat_info.min_addr.ipv4 = ip_dst;\n+ nat_info.max_addr.ipv4 = ip_dst;\n+\n+ struct conntrack *ct_ = conntrack_init();\n+ conntrack_set_tcp_seq_chk(ct_, false);\n+\n+ long long now = time_msec();\n+\n+ struct dp_packet *syn = build_eth_ip_packet(NULL, eth_src, eth_dst,\n+ ip_src, ip_dst,\n+ IPPROTO_TCP, 0);\n+ build_tcp_packet(syn, sport, dport, TCP_SYN, NULL, 0);\n+\n+ struct dp_packet_batch syn_batch;\n+ dp_packet_batch_init_packet(&syn_batch, syn);\n+ conntrack_execute(ct_, &syn_batch, htons(ETH_TYPE_IP), false, true, 0,\n+ NULL, NULL, \"ftp\", &nat_info, now, 0);\n+ dp_packet_delete_batch(&syn_batch, true);\n+\n+ /* We get to skip some of the processing because the conntrack execute\n+ * above will create the required conntrack entries. */\n+\n+ /* Build the large payload: PORT command followed by padding spaces\n+ * and a final \"\\r\\n\" to reach exactly FTP_PAYLOAD_LEN bytes. The\n+ * FTP parser only looks at the first LARGEST_FTP_MSG_OF_INTEREST (128)\n+ * bytes, so the trailing spaces do not interfere with parsing. */\n+ char ftp_payload[FTP_PAYLOAD_LEN];\n+ memcpy(ftp_payload, FTP_PORT_CMD_STR, sizeof FTP_PORT_CMD_STR - 1);\n+ memset(ftp_payload + sizeof FTP_PORT_CMD_STR - 1, ' ', FTP_CMD_PAD);\n+\n+ struct dp_packet *port_pkt =\n+ build_eth_ip_packet(NULL, eth_src, eth_dst, ip_src, ip_dst,\n+ IPPROTO_TCP, FTP_PAYLOAD_LEN);\n+ build_tcp_packet(port_pkt, sport, dport, TCP_PSH | TCP_ACK,\n+ ftp_payload, FTP_PAYLOAD_LEN);\n+\n+ struct dp_packet_batch port_batch;\n+ dp_packet_batch_init_packet(&port_batch, port_pkt);\n+ conntrack_execute(ct_, &port_batch, htons(ETH_TYPE_IP), false, true, 0,\n+ NULL, NULL, \"ftp\", &nat_info, now, 0);\n+\n+ struct tcp_header *th = dp_packet_l4(port_pkt);\n+ size_t tcp_hdr_len = TCP_OFFSET(th->tcp_ctl) * 4;\n+ const char *ftp_start = (const char *) th + tcp_hdr_len;\n+ ovs_assert(!strncmp(ftp_start, \"PORT 192,168,1,1,\", 17));\n+ dp_packet_delete_batch(&port_batch, true);\n+ conntrack_destroy(ct_);\n+}\n+\n \f\n static const struct ovs_cmdl_command commands[] = {\n /* Connection tracker tests. */\n@@ -415,6 +590,13 @@ static const struct ovs_cmdl_command commands[] = {\n * and an empty zone. */\n {\"benchmark-zones\", \"n_conns n_zones iterations\", 3, 3,\n test_benchmark_zones, OVS_RO},\n+ /* Verifies that the FTP ALG replace_substring function correctly handles\n+ * a packet whose payload puts total_size at exactly 256 bytes. The\n+ * original uint8_t parameter type truncated 256 to 0, leading to a\n+ * near-SIZE_MAX memmove (heap overflow). The test confirms the address\n+ * is rewritten to the SNAT target rather than causing a crash. */\n+ {\"ftp-alg-large-payload\", \"\", 0, 0,\n+ test_ftp_alg_large_payload, OVS_RO},\n \n {NULL, NULL, 0, 0, NULL, OVS_RO},\n };\n", "prefixes": [ "ovs-dev" ] }