get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2218172/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "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"
    ]
}