aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Tuexen <tuexen@FreeBSD.org>2026-10-12 18:55:21 +0000
committerMark Johnston <markj@FreeBSD.org>2026-10-13 17:32:51 +0000
commit5dd20a06fe9ebd45c26753b2eeca801f173b4643 (patch)
treef564d0bac4f7c815d30d120630db8f4a11c3f15e
parentcf95af02eb153c39641d0f12650ff5752619d7d5 (diff)
tcp/rack: Fix a potential overflow in rack_update_pcm_ack()
The RACK stack's path capacity measurement module maintains an array of samples, updated when the stack receives an ACK. The array grows as needed, but code which handles the expansion is susceptible to remotely triggerable overflow. This could lead to underallocation and a ~512KB out-of-bounds write. Fix this by bounding the sample array size. Approved by: so Security: FreeBSD-SA-26:70.tcp Security: CVE-2026-101307 Reviewed by: glebius, markj Reported by: Nozomi Networks Security Research
-rw-r--r--sys/netinet/tcp_stacks/rack_pcm.c17
-rw-r--r--sys/netinet/tcp_stacks/tcp_rack.h6
2 files changed, 15 insertions, 8 deletions
diff --git a/sys/netinet/tcp_stacks/rack_pcm.c b/sys/netinet/tcp_stacks/rack_pcm.c
index 1a51097f627c..66297006000e 100644
--- a/sys/netinet/tcp_stacks/rack_pcm.c
+++ b/sys/netinet/tcp_stacks/rack_pcm.c
@@ -196,17 +196,22 @@ rack_update_pcm_ack(struct tcp_rack *rack, int was_cumack, uint32_t start, uint3
} else {
/* Need to expand the array */
struct rack_pcm_stats *n;
- uint16_t new_cnt;
+ size_t new_cnt;
- new_cnt = rack->r_ctl.pcm_i.cnt_alloc * 2;
- sz = (sizeof(struct rack_pcm_stats) * new_cnt);
- n = malloc(sz,M_TCPPCM, M_NOWAIT);
- if (n == NULL) {
- /* We are dead, no memory */
+ new_cnt = (size_t)rack->r_ctl.pcm_i.cnt_alloc * 2;
+ if (new_cnt > RACK_MAX_PCM_ARRAY) {
+ /* Too many entries required. */
+stop_measurement:
rack->pcm_in_progress = 0;
rack->r_ctl.pcm_i.cnt = 0;
return;
}
+ sz = (sizeof(struct rack_pcm_stats) * new_cnt);
+ n = malloc(sz, M_TCPPCM, M_NOWAIT);
+ if (n == NULL) {
+ /* We are dead, no memory. */
+ goto stop_measurement;
+ }
sz = (sizeof(struct rack_pcm_stats) * rack->r_ctl.pcm_i.cnt_alloc);
memcpy(n, rack->r_ctl.pcm_s, sz);
free(rack->r_ctl.pcm_s, M_TCPPCM);
diff --git a/sys/netinet/tcp_stacks/tcp_rack.h b/sys/netinet/tcp_stacks/tcp_rack.h
index cac17d9aeb50..4d9e516a8b98 100644
--- a/sys/netinet/tcp_stacks/tcp_rack.h
+++ b/sys/netinet/tcp_stacks/tcp_rack.h
@@ -362,9 +362,11 @@ struct rack_pcm_info {
uint16_t cnt;
/* Maximum acks present */
uint16_t cnt_alloc;
+#define RACK_DEFAULT_PCM_ARRAY 16
+#define RACK_MAX_PCM_ARRAY 1024
};
-
-#define RACK_DEFAULT_PCM_ARRAY 16
+_Static_assert(RACK_MAX_PCM_ARRAY <= UINT16_MAX,
+ "RACK_MAX_PCM_ARRAY must fit in 16 bits");
struct rack_pcm_stats {
uint32_t sseq;