iperf3/0009-cve-2026-71217.patch
RHEL Packaging Agent 2c8669efac 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:
 - 494dd377ec.patch
Resolves: RHEL-236174

This commit was backported by Ymir, a Red Hat Enterprise Linux software maintenance AI agent.

Assisted-by: Ymir
2026-08-12 09:38:03 +00:00

269 lines
11 KiB
Diff

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);
}
+