Commit b999d2a594 for freeswitch.com

commit b999d2a594f025ac0dd4d7b137635308ef298272
Author: Dmitry Verenitsin <morbit85@gmail.com>
Date:   Sat Aug 8 23:10:24 2026 +0500

    Merge commit from fork

    In `udptl_rx_packet()`, decoded values from the error-recovery data were
    used without checking them against their destination buffers:

    - The FEC entry count is read as a single byte and drives both the
      decode loop and the stored `fec_entries` later walked by the
      reconstruction loop, allowing writes past the `fec[]`/`fec_len[]`
      arrays, which hold only `LOCAL_FAX_MAX_FEC_PACKETS` entries. Reject a
      larger count. `fec_entries` was also stored before the elements were
      decoded, so a mid-loop reject left the slot advertising a count whose
      `fec_len[]`/`fec[]` were stale or out of range; since `s->rx[]`
      persists across packets, a later reconstruction pass could copy such a
      stale length past the fixed `s->rx[].buf`. Commit the count only after
      every element is decoded and bound-checked.
    - Each redundancy secondary element length was copied into the fixed
      `LOCAL_FAX_MAX_DATAGRAM`-sized `s->rx[].buf` without a size check,
      unlike the primary packet. Reject an overlength element at decode
      time.

diff --git a/src/mod/applications/mod_spandsp/udptl.c b/src/mod/applications/mod_spandsp/udptl.c
index 35b9f29f77..ec5ff32517 100644
--- a/src/mod/applications/mod_spandsp/udptl.c
+++ b/src/mod/applications/mod_spandsp/udptl.c
@@ -230,6 +230,10 @@ int udptl_rx_packet(udptl_state_t *s, const uint8_t buf[], int len)
 			for (i = 0; i < count; i++) {
 				if (decode_open_type(buf, len, &ptr, &bufs[total_count + i], &lengths[total_count + i]) != 0)
 					return -1;
+				/* Secondary packets are copied into the fixed-size s->rx[].buf, so an overlength
+				   entry cannot be tolerated any more than an overlength primary packet. */
+				if (lengths[total_count + i] > LOCAL_FAX_MAX_DATAGRAM)
+					return -1;
 			}
 			total_count += count;
 		}
@@ -286,7 +290,10 @@ int udptl_rx_packet(udptl_state_t *s, const uint8_t buf[], int len)
 		if (ptr + 1 > len)
 			return -1;
 		entries = buf[ptr++];
-		s->rx[x].fec_entries = entries;
+		/* fec[]/fec_len[] hold only LOCAL_FAX_MAX_FEC_PACKETS entries; reject a larger
+		   count before it bounds the decode and reconstruction loops. */
+		if (entries > LOCAL_FAX_MAX_FEC_PACKETS)
+			return -1;

 		/* Decode the elements */
 		for (i = 0; i < entries; i++) {
@@ -305,6 +312,9 @@ int udptl_rx_packet(udptl_state_t *s, const uint8_t buf[], int len)
 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "\n");
 #endif
 		}
+		/* Commit the count only after all elements validate; an early return above leaves
+		   fec_entries at 0, so reconstruction never reads a partially filled slot. */
+		s->rx[x].fec_entries = entries;
 		/* We should now be exactly at the end of the packet. If not, this is a fault. */
 		if (ptr != len)
 			return -1;