From 2c8669efac7208c4d343b735cb8f60ec1a1427de Mon Sep 17 00:00:00 2001 From: RHEL Packaging Agent Date: Wed, 12 Aug 2026 09:38:03 +0000 Subject: [PATCH] Fix CVE-2026-71217: add JSON value bounds checks in iperf3 Backport upstream fix (commit 494dd377) for CVE-2026-71217 to iperf3 3.5. The patch adds bounds checking for all peer-controlled JSON parameters in get_parameters() and additional bounds checks in iperf_parse_arguments(), preventing malicious clients/servers from injecting out-of-range values for parameters such as num_streams, window size, MSS, TOS, bandwidth, burst, and others. CVE: CVE-2026-71217 Upstream patches: - https://github.com/esnet/iperf/commit/494dd377eca4689672becdf06a85158557db1586.patch Resolves: RHEL-236174 This commit was backported by Ymir, a Red Hat Enterprise Linux software maintenance AI agent. Assisted-by: Ymir --- 0009-cve-2026-71217.patch | 268 ++++++++++++++++++++++++++++++++++++++ iperf3.spec | 8 +- 2 files changed, 275 insertions(+), 1 deletion(-) create mode 100644 0009-cve-2026-71217.patch diff --git a/0009-cve-2026-71217.patch b/0009-cve-2026-71217.patch new file mode 100644 index 0000000..511c2f9 --- /dev/null +++ b/0009-cve-2026-71217.patch @@ -0,0 +1,268 @@ +From a17eb3444d4b2587a2c0e2285fcbfd58b133c44e Mon Sep 17 00:00:00 2001 +From: swlars <89053414+swlars@users.noreply.github.com> +Date: Wed, 20 May 2026 16:01:30 -0700 +Subject: [PATCH] Add JSON value checks for get_parameters. (#2039) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +* Add JSON value checks for get_parameters. + +Special thanks to Dirk Müller for directing our attention to this. +--- + src/iperf_api.c | 178 +++++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 145 insertions(+), 33 deletions(-) + +diff --git a/src/iperf_api.c b/src/iperf_api.c +index 3271cba..0426a78 100755 +--- a/src/iperf_api.c ++++ b/src/iperf_api.c +@@ -376,6 +376,7 @@ iperf_set_test_num_streams(struct iperf_test *ipt, int num_streams) + ipt->num_streams = num_streams; + } + ++ + static void + check_sender_has_retransmits(struct iperf_test *ipt) + { +@@ -840,7 +841,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) + break; + case 'P': + test->num_streams = atoi(optarg); +- if (test->num_streams > MAX_STREAMS) { ++ if (test->num_streams < 0 || test->num_streams > MAX_STREAMS) { + i_errno = IENUMSTREAMS; + return -1; + } +@@ -855,7 +856,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) + // Do sanity checks as double-precision floating point + // to avoid possible integer overflows. + farg = unit_atof(optarg); +- if (farg > (double) MAX_TCP_BUFFER) { ++ if (farg < 0 || farg > (double) MAX_TCP_BUFFER) { + i_errno = IEBUFSIZE; + return -1; + } +@@ -870,7 +871,7 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) + break; + case 'M': + test->settings->mss = atoi(optarg); +- if (test->settings->mss > MAX_MSS) { ++ if (test->settings->mss < 0 || test->settings->mss > MAX_MSS) { + i_errno = IEMSS; + return -1; + } +@@ -1044,6 +1045,9 @@ iperf_parse_arguments(struct iperf_test *test, int argc, char **argv) + #endif /* HAVE_SSL */ + case OPT_PACING_TIMER: + test->settings->pacing_timer = unit_atoi(optarg); ++ if (test->settings->pacing_timer < 0){ ++ return -1; ++ } + client_flag = 1; + break; + case OPT_CONNECT_TIMEOUT: +@@ -1529,6 +1533,7 @@ send_parameters(struct iperf_test *test) + return r; + } + ++ + /*************************************************************/ + + static int +@@ -1553,46 +1558,138 @@ get_parameters(struct iperf_test *test) + set_protocol(test, Pudp); + if ((j_p = iperf_cJSON_GetObjectItemType(j, "sctp", cJSON_True)) != NULL) + set_protocol(test, Psctp); +- if ((j_p = iperf_cJSON_GetObjectItemType(j, "omit", cJSON_Number)) != NULL) +- test->omit = j_p->valueint; +- if ((j_p = iperf_cJSON_GetObjectItemType(j, "server_affinity", cJSON_Number)) != NULL) +- test->server_affinity = j_p->valueint; +- if ((j_p = iperf_cJSON_GetObjectItemType(j, "time", cJSON_Number)) != NULL) +- test->duration = j_p->valueint; +- if ((j_p = iperf_cJSON_GetObjectItemType(j, "num", cJSON_Number)) != NULL) +- test->settings->bytes = j_p->valueint; +- if ((j_p = iperf_cJSON_GetObjectItemType(j, "blockcount", cJSON_Number)) != NULL) +- test->settings->blocks = j_p->valueint; +- if ((j_p = iperf_cJSON_GetObjectItemType(j, "MSS", cJSON_Number)) != NULL) +- test->settings->mss = j_p->valueint; ++ if ((j_p = iperf_cJSON_GetObjectItemType(j, "omit", cJSON_Number)) != NULL){ ++ if (j_p->valueint < 0 || j_p->valueint > 600){ ++ i_errno = IEOMIT; ++ r = -1; ++ } else { ++ test->omit = j_p->valueint; ++ } ++ } ++ if ((j_p = iperf_cJSON_GetObjectItemType(j, "server_affinity", cJSON_Number)) != NULL){ ++ if (j_p->valueint < 0 || j_p->valueint > 1024) { ++ i_errno = IEAFFINITY; ++ r = -1; ++ } else { ++ test->server_affinity = j_p->valueint; ++ } ++ } ++ if ((j_p = iperf_cJSON_GetObjectItemType(j, "time", cJSON_Number)) != NULL){ ++ if (j_p->valueint < 0 || j_p->valueint > MAX_TIME) { ++ i_errno = IEDURATION; ++ r = -1; ++ } else { ++ test->duration = j_p->valueint; ++ } ++ } ++ if ((j_p = iperf_cJSON_GetObjectItemType(j, "num", cJSON_Number)) != NULL){ ++ if (j_p->valueint < 0){ ++ i_errno = IERECVPARAMS; ++ r = -1; ++ } else { ++ test->settings->bytes = j_p->valueint; ++ } ++ } ++ if ((j_p = iperf_cJSON_GetObjectItemType(j, "blockcount", cJSON_Number)) != NULL){ ++ if (j_p->valueint < 0){ ++ i_errno = IERECVPARAMS; ++ r = -1; ++ } else { ++ test->settings->blocks = j_p->valueint; ++ } ++ } ++ if ((j_p = iperf_cJSON_GetObjectItemType(j, "MSS", cJSON_Number)) != NULL){ ++ if (j_p->valueint < 0 || j_p->valueint > MAX_MSS) { ++ i_errno = IEMSS; ++ r = -1; ++ } else { ++ test->settings->mss = j_p->valueint; ++ } ++ } + if ((j_p = iperf_cJSON_GetObjectItemType(j, "nodelay", cJSON_True)) != NULL) + test->no_delay = 1; +- if ((j_p = iperf_cJSON_GetObjectItemType(j, "parallel", cJSON_Number)) != NULL) +- test->num_streams = j_p->valueint; ++ if ((j_p = iperf_cJSON_GetObjectItemType(j, "parallel", cJSON_Number)) != NULL){ ++ if (j_p->valueint < 0 || j_p->valueint > MAX_STREAMS) { ++ i_errno = IENUMSTREAMS; ++ r = -1; ++ } else { ++ test->num_streams = j_p->valueint; ++ } ++ } + if ((j_p = iperf_cJSON_GetObjectItemType(j, "reverse", cJSON_True)) != NULL) + iperf_set_test_reverse(test, 1); +- if ((j_p = iperf_cJSON_GetObjectItemType(j, "window", cJSON_Number)) != NULL) +- test->settings->socket_bufsize = j_p->valueint; +- if ((j_p = iperf_cJSON_GetObjectItemType(j, "len", cJSON_Number)) != NULL) +- test->settings->blksize = j_p->valueint; +- if ((j_p = iperf_cJSON_GetObjectItemType(j, "bandwidth", cJSON_Number)) != NULL) +- test->settings->rate = j_p->valueint; +- if ((j_p = iperf_cJSON_GetObjectItemType(j, "fqrate", cJSON_Number)) != NULL) +- test->settings->fqrate = j_p->valueint; +- if ((j_p = iperf_cJSON_GetObjectItemType(j, "pacing_timer", cJSON_Number)) != NULL) +- test->settings->pacing_timer = j_p->valueint; +- if ((j_p = iperf_cJSON_GetObjectItemType(j, "burst", cJSON_Number)) != NULL) +- test->settings->burst = j_p->valueint; +- if ((j_p = iperf_cJSON_GetObjectItemType(j, "TOS", cJSON_Number)) != NULL) +- test->settings->tos = j_p->valueint; +- if ((j_p = iperf_cJSON_GetObjectItemType(j, "flowlabel", cJSON_Number)) != NULL) +- test->settings->flowlabel = j_p->valueint; ++ if ((j_p = iperf_cJSON_GetObjectItemType(j, "window", cJSON_Number)) != NULL){ ++ if (j_p->valueint < 0 || j_p->valueint > MAX_TCP_BUFFER){ ++ i_errno = IEBUFSIZE; ++ r = -1; ++ } ++ else { ++ test->settings->socket_bufsize = j_p->valueint; ++ } ++ } ++ if ((j_p = iperf_cJSON_GetObjectItemType(j, "len", cJSON_Number)) != NULL){ ++ if (j_p->valueint < 0){ ++ i_errno = IEBLOCKSIZE; ++ r = -1; ++ }else { ++ test->settings->blksize = j_p->valueint; ++ } ++ } ++ if ((j_p = iperf_cJSON_GetObjectItemType(j, "bandwidth", cJSON_Number)) != NULL){ ++ if (j_p->valueint < 0){ ++ i_errno = IERECVPARAMS; ++ r = -1; ++ }else { ++ test->settings->rate = j_p->valueint; ++ } ++ } ++ if ((j_p = iperf_cJSON_GetObjectItemType(j, "fqrate", cJSON_Number)) != NULL){ ++ if (j_p->valueint < 0){ ++ i_errno = IERECVPARAMS; ++ r = -1; ++ }else { ++ test->settings->fqrate = j_p->valueint; ++ } ++ } ++ if ((j_p = iperf_cJSON_GetObjectItemType(j, "pacing_timer", cJSON_Number)) != NULL){ ++ if (j_p->valueint < 0){ ++ i_errno = IERECVPARAMS; ++ r = -1; ++ }else { ++ test->settings->pacing_timer = j_p->valueint; ++ } ++ } ++ if ((j_p = iperf_cJSON_GetObjectItemType(j, "burst", cJSON_Number)) != NULL){ ++ if (j_p->valueint <= 0 || j_p->valueint > MAX_BURST){ ++ i_errno = IEBURST; ++ r = -1; ++ }else { ++ test->settings->burst = j_p->valueint; ++ } ++ } ++ if ((j_p = iperf_cJSON_GetObjectItemType(j, "TOS", cJSON_Number)) != NULL){ ++ if (j_p->valueint < 0 || j_p->valueint > 255){ ++ i_errno = IEBADTOS; ++ r = -1; ++ }else { ++ test->settings->tos = j_p->valueint; ++ } ++ } ++ if ((j_p = iperf_cJSON_GetObjectItemType(j, "flowlabel", cJSON_Number)) != NULL){ ++ if (j_p->valueint < 1 || j_p->valueint > 0xfffff ){ ++ i_errno = IESETFLOW; ++ r = -1; ++ }else { ++ test->settings->flowlabel = j_p->valueint; ++ } ++ } + if ((j_p = iperf_cJSON_GetObjectItemType(j, "title", cJSON_String)) != NULL) + test->title = strdup(j_p->valuestring); + if ((j_p = iperf_cJSON_GetObjectItemType(j, "congestion", cJSON_String)) != NULL) + test->congestion = strdup(j_p->valuestring); + if ((j_p = iperf_cJSON_GetObjectItemType(j, "congestion_used", cJSON_String)) != NULL) + test->congestion_used = strdup(j_p->valuestring); ++ // Should be TrueObject + if ((j_p = iperf_cJSON_GetObjectItemType(j, "get_server_output", cJSON_Number)) != NULL) + iperf_set_test_get_server_output(test, 1); + if ((j_p = iperf_cJSON_GetObjectItemType(j, "udp_counters_64bit", cJSON_Number)) != NULL) +@@ -1604,7 +1701,21 @@ get_parameters(struct iperf_test *test) + if (test->sender && test->protocol->id == Ptcp && has_tcpinfo_retransmits()) + test->sender_has_retransmits = 1; + cJSON_Delete(j); ++ ++ /* Check flag / role compatibility. */ ++ if ((test->protocol->id != Pudp && test->settings->blksize <= 0) ++ || test->settings->blksize > MAX_BLOCKSIZE) { ++ i_errno = IEBLOCKSIZE; ++ return -1; ++ } ++ if (test->protocol->id == Pudp && ++ (test->settings->blksize > 0 && ++ (test->settings->blksize < MIN_UDP_BLOCKSIZE || test->settings->blksize > MAX_UDP_BLOCKSIZE))) { ++ i_errno = IEUDPBLOCKSIZE; ++ return -1; ++ } + } ++ + return r; + } + +@@ -3688,3 +3799,4 @@ iflush(struct iperf_test *test) + { + return fflush(test->outfile); + } ++ diff --git a/iperf3.spec b/iperf3.spec index 8e05f42..eb16248 100644 --- a/iperf3.spec +++ b/iperf3.spec @@ -1,6 +1,6 @@ Name: iperf3 Version: 3.5 -Release: 12%{?dist} +Release: 12%{?dist}.1 Summary: Measurement tool for TCP/UDP bandwidth performance Group: Applications/Internet @@ -18,6 +18,8 @@ Patch0005: 0005-cve-2023-7250.patch Patch0006: 0006-cve-2024-26306.patch Patch0007: 0007-cve-2024-53580.patch Patch0008: 0008-cve-2025-54349.patch +# https://github.com/esnet/iperf/commit/494dd377eca4689672becdf06a85158557db1586 +Patch0009: 0009-cve-2026-71217.patch %description Iperf is a tool to measure maximum TCP bandwidth, allowing the tuning of @@ -65,6 +67,10 @@ rm -f %{buildroot}%{_libdir}/libiperf.la %{_libdir}/*.so %changelog +* Wed Aug 12 2026 RHEL Packaging Agent - 3.5-12.1 +- Resolves: RHEL-236174 - Add JSON value checks for get_parameters + (CVE-2026-71217) + * Fri Jan 23 2026 Michal Ruprich - 3.5-12 - Resolves: RHEL-136175 - iperf Heap Buffer Overflow (CVE-2025-54349)