From 633ae35b4f9d82e67581623b6ed29e1aa7b9f97a Mon Sep 17 00:00:00 2001 From: pkgagent Date: Wed, 12 Aug 2026 02:21:15 +0800 Subject: [PATCH] =?UTF-8?q?Fix=20CVE-2026-71217:=20validate=20control-chan?= =?UTF-8?q?nel=20JSON=20numeric=20parameters=20(parallel,=20len,=20etc.)?= =?UTF-8?q?=20in=20get=5Fp=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CVE-2026-71217.patch | 261 +++++++++++++++++++++++++++++++++++++++++++ iperf3.spec | 8 +- 2 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 CVE-2026-71217.patch diff --git a/CVE-2026-71217.patch b/CVE-2026-71217.patch new file mode 100644 index 0000000..4693d57 --- /dev/null +++ b/CVE-2026-71217.patch @@ -0,0 +1,261 @@ +From 494dd377eca4689672becdf06a85158557db1586 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 Mueller for directing our attention to this. + +Adapted-by: PkgAgent/deepseek-v4 (modified to adapt to opencloudos-stream: 3.18 has no GSO/GRO/skip_rx_copy fields, so those hunks were dropped; the JSON value validation and CLI arg checks are otherwise semantically equivalent to upstream commit 494dd377eca4689672becdf06a85158557db1586) +--- +diff --git a/src/iperf_api.c b/src/iperf_api.c +index fa06dc8..80d297e 100644 +--- a/src/iperf_api.c ++++ b/src/iperf_api.c +@@ -1339,7 +1339,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; + } +@@ -1366,7 +1366,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; + } +@@ -1404,7 +1404,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; + } +@@ -1641,6 +1641,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: +@@ -2353,44 +2356,134 @@ 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, "omit", cJSON_Number)) != NULL){ ++ if (j_p->valueint < 0 || j_p->valueint > MAX_OMIT_TIME){ ++ 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; ++ } ++ } + test->settings->bytes = 0; +- if ((j_p = iperf_cJSON_GetObjectItemType(j, "num", cJSON_Number)) != NULL) +- test->settings->bytes = 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; ++ } ++ } + test->settings->blocks = 0; +- 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, "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, "bidirectional", cJSON_True)) != NULL) + iperf_set_test_bidirectional(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, "extra_data", cJSON_String)) != NULL) +@@ -2405,11 +2498,13 @@ get_parameters(struct iperf_test *test) + iperf_set_test_udp_counters_64bit(test, 1); + if ((j_p = iperf_cJSON_GetObjectItemType(j, "repeating_payload", cJSON_Number)) != NULL) + test->repeating_payload = 1; +- if ((j_p = iperf_cJSON_GetObjectItemType(j, "zerocopy", cJSON_Number)) != NULL) +- test->zerocopy = j_p->valueint; ++ if ((j_p = iperf_cJSON_GetObjectItemType(j, "zerocopy", cJSON_Number)) != NULL){ ++ test->zerocopy = (j_p->valueint) ? 1 : 0; ++ } + #if defined(HAVE_DONT_FRAGMENT) +- if ((j_p = iperf_cJSON_GetObjectItemType(j, "dont_fragment", cJSON_Number)) != NULL) +- test->settings->dont_fragment = j_p->valueint; ++ if ((j_p = iperf_cJSON_GetObjectItemType(j, "dont_fragment", cJSON_Number)) != NULL){ ++ test->settings->dont_fragment = (j_p->valueint) ? 1 : 0; ++ } + #endif /* HAVE_DONT_FRAGMENT */ + #if defined(HAVE_SSL) + if ((j_p = iperf_cJSON_GetObjectItemType(j, "authtoken", cJSON_String)) != NULL) +@@ -2419,7 +2514,22 @@ get_parameters(struct iperf_test *test) + test->sender_has_retransmits = 1; + if (test->settings->rate) + cJSON_AddNumberToObject(test->json_start, "target_bitrate", test->settings->rate); ++ + 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; + } diff --git a/iperf3.spec b/iperf3.spec index 65d848e..177ee53 100644 --- a/iperf3.spec +++ b/iperf3.spec @@ -1,7 +1,7 @@ Summary: Measurement tool for TCP/UDP bandwidth performance Name: iperf3 Version: 3.18 -Release: 2%{?dist} +Release: 3%{?dist} License: BSD URL: https://github.com/esnet/iperf Source0: https://github.com/esnet/iperf/archive/%{version}.tar.gz @@ -10,6 +10,8 @@ Source0: https://github.com/esnet/iperf/archive/%{version}.tar.gz Patch0001: CVE-2025-54349.patch # https://github.com/esnet/iperf/commit/4eab661da0bbaac04493fa40164e928c6df7934a Patch0002: CVE-2025-54350.patch +# https://github.com/esnet/iperf/commit/494dd377eca4689672becdf06a85158557db1586 +Patch0003: CVE-2026-71217.patch BuildRequires: gcc make BuildRequires: openssl-devel libuuid-devel lksctp-tools-devel @@ -54,6 +56,10 @@ rm -f %{buildroot}%{_libdir}/libiperf.la %{_libdir}/*.so %changelog +* Tue Aug 11 2026 PkgAgent Robot - 3.18-3 +- [Type] security +- [DESC] Fix CVE-2026-71217: validate control-channel JSON numeric parameters (parallel, len, etc.) in get_parameters to prevent resource exhaustion DoS + * Fri Aug 08 2025 Miaojun Dong - 3.18-2 - Fix CVE-2025-54349 and CVE-2025-54350 -- Gitee