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
269 lines
11 KiB
Diff
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);
|
|
}
|
|
+
|