Commit 59b74276f2 for asterisk.org

commit 59b74276f24ba104d859f3f05897c9b8d835a28a
Author: Pengpeng Hou <pengpeng@iscas.ac.cn>
Date:   Wed Apr 1 20:20:10 2026 +0800

    app_sms: Bound protocol 1 SMS unpacking to fixed-size buffers

    The protocol 1 unpack helpers trusted externally controlled lengths and wrote
     them directly into fixed-size buffers in sms_t. Clamp the address, header,
     and body copies to the destination array sizes so malformed messages cannot
     overwrite adjacent state.

    Resolves: #GHSA-q9fr-m7g8-6ph5

diff --git a/apps/app_sms.c b/apps/app_sms.c
index 94b94a53af..dc5c11e7d1 100644
--- a/apps/app_sms.c
+++ b/apps/app_sms.c
@@ -605,20 +605,28 @@ static struct timeval unpackdate(unsigned char *i)
 /*! \brief unpacks bytes (7 bit encoding) at i, len l septets,
 	and places in udh and ud setting udhl and udl. udh not used
 	if udhi not set */
-static void unpacksms7(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
+static void unpacksms7(unsigned char *i, unsigned char l, unsigned char *udh, size_t udh_size,
+	int *udhl, unsigned short *ud, size_t ud_size, int *udl, char udhi)
 {
 	unsigned char b = 0, p = 0;
 	unsigned short *o = ud;
+	unsigned short *o_end = ud + ud_size;
+	unsigned char *h = udh;
+	unsigned char *h_end = udh + udh_size;
+	size_t stored_udhl = 0;
 	*udhl = 0;
 	if (udhi && l) {                        /* header */
-		int h = i[p];
-		*udhl = h;
-		if (h) {
+		int hlen = i[p];
+		if (hlen) {
 			b = 1;
 			p++;
 			l--;
-			while (h-- && l) {
-				*udh++ = i[p++];
+			while (hlen-- && l) {
+				if (h < h_end) {
+					*h++ = i[p];
+					stored_udhl++;
+				}
+				p++;
 				b += 8;
 				while (b >= 7) {
 					b -= 7;
@@ -650,57 +658,78 @@ static void unpacksms7(unsigned char *i, unsigned char l, unsigned char *udh, in
 		/* 0x00A0 is the encoding of ESC (27) in defaultalphabet */
 		if (o > ud && o[-1] == 0x00A0 && escapes[v]) {
 			o[-1] = escapes[v];
-		} else {
+		} else if (o < o_end) {
 			*o++ = defaultalphabet[v];
 		}
 	}
-	*udl = (o - ud);
+	*udl = o - ud;
+	*udhl = stored_udhl;
 }

 /*! \brief unpacks bytes (8 bit encoding) at i, len l septets,
  *  and places in udh and ud setting udhl and udl. udh not used
  *  if udhi not set.
  */
-static void unpacksms8(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
+static void unpacksms8(unsigned char *i, unsigned char l, unsigned char *udh, size_t udh_size,
+	int *udhl, unsigned short *ud, size_t ud_size, int *udl, char udhi)
 {
 	unsigned short *o = ud;
+	unsigned short *o_end = ud + ud_size;
+	unsigned char *h = udh;
+	unsigned char *h_end = udh + udh_size;
+	size_t stored_udhl = 0;
 	*udhl = 0;
 	if (udhi) {
 		int n = *i;
-		*udhl = n;
 		if (n) {
 			i++;
 			l--;
 			while (l && n) {
 				l--;
 				n--;
-				*udh++ = *i++;
+				if (h < h_end) {
+					*h++ = *i;
+					stored_udhl++;
+				}
+				i++;
 			}
 		}
 	}
 	while (l--) {
-		*o++ = *i++;                        /* not to UTF-8 as explicitly 8 bit coding in DCS */
+		if (o < o_end) {
+			*o++ = *i;               /* not to UTF-8 as explicitly 8 bit coding in DCS */
+		}
+		i++;
 	}
-	*udl = (o - ud);
+	*udl = o - ud;
+	*udhl = stored_udhl;
 }

 /*! \brief unpacks bytes (16 bit encoding) at i, len l septets,
-	 and places in udh and ud setting udhl and udl.
+	and places in udh and ud setting udhl and udl.
 	udh not used if udhi not set */
-static void unpacksms16(unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
+static void unpacksms16(unsigned char *i, unsigned char l, unsigned char *udh, size_t udh_size,
+	int *udhl, unsigned short *ud, size_t ud_size, int *udl, char udhi)
 {
 	unsigned short *o = ud;
+	unsigned short *o_end = ud + ud_size;
+	unsigned char *h = udh;
+	unsigned char *h_end = udh + udh_size;
+	size_t stored_udhl = 0;
 	*udhl = 0;
 	if (udhi) {
 		int n = *i;
-		*udhl = n;
 		if (n) {
 			i++;
 			l--;
 			while (l && n) {
 				l--;
 				n--;
-				*udh++ = *i++;
+				if (h < h_end) {
+					*h++ = *i;
+					stored_udhl++;
+				}
+				i++;
 			}
 		}
 	}
@@ -709,39 +738,54 @@ static void unpacksms16(unsigned char *i, unsigned char l, unsigned char *udh, i
 		if (l && l--) {
 			v = (v << 8) + *i++;
 		}
-		*o++ = v;
+		if (o < o_end) {
+			*o++ = v;
+		}
 	}
-	*udl = (o - ud);
+	*udl = o - ud;
+	*udhl = stored_udhl;
 }

 /*! \brief general unpack - starts with length byte (octet or septet) and returns number of bytes used, inc length */
-static int unpacksms(unsigned char dcs, unsigned char *i, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
+static int unpacksms(unsigned char dcs, unsigned char *i, unsigned char *udh, size_t udh_size,
+	int *udhl, unsigned short *ud, size_t ud_size, int *udl, char udhi)
 {
 	int l = *i++;
 	if (is7bit(dcs)) {
-		unpacksms7(i, l, udh, udhl, ud, udl, udhi);
+		unpacksms7(i, l, udh, udh_size, udhl, ud, ud_size, udl, udhi);
 		l = (l * 7 + 7) / 8;                /* adjust length to return */
 	} else if (is8bit(dcs)) {
-		unpacksms8(i, l, udh, udhl, ud, udl, udhi);
+		unpacksms8(i, l, udh, udh_size, udhl, ud, ud_size, udl, udhi);
 	} else {
 		l += l % 2;
-		unpacksms16(i, l, udh, udhl, ud, udl, udhi);
+		unpacksms16(i, l, udh, udh_size, udhl, ud, ud_size, udl, udhi);
 	}
 	return l + 1;
 }

 /*! \brief unpack an address from i, return byte length, unpack to o */
-static unsigned char unpackaddress(char *o, unsigned char *i)
+static unsigned char unpackaddress(char *o, size_t o_size, unsigned char *i)
 {
 	unsigned char l = i[0], p;
+	char *o_end;
+
+	if (!o_size) {
+		return (l + 5) / 2;
+	}
+
+	o_end = o + o_size - 1;
 	if (i[1] == 0x91) {
-		*o++ = '+';
+		if (o < o_end) {
+			*o++ = '+';
+		}
 	}
 	for (p = 0; p < l; p++) {
-		if (p & 1) {
-			*o++ = (i[2 + p / 2] >> 4) + '0';
-		} else {
-			*o++ = (i[2 + p / 2] & 0xF) + '0';
+		if (o < o_end) {
+			if (p & 1) {
+				*o++ = (i[2 + p / 2] >> 4) + '0';
+			} else {
+				*o++ = (i[2 + p / 2] & 0xF) + '0';
+			}
 		}
 	}
 	*o = 0;
@@ -1129,7 +1173,7 @@ static unsigned char sms_handleincoming (sms_t * h)
 			ast_copy_string(h->oa, h->cli, sizeof(h->oa));
 			h->scts = ast_tvnow();
 			h->mr = h->imsg[p++];
-			p += unpackaddress(h->da, h->imsg + p);
+			p += unpackaddress(h->da, ARRAY_LEN(h->da), h->imsg + p);
 			h->pid = h->imsg[p++];
 			h->dcs = h->imsg[p++];
 			if ((h->imsg[2] & 0x18) == 0x10) {       /* relative VP */
@@ -1146,7 +1190,7 @@ static unsigned char sms_handleincoming (sms_t * h)
 			} else if (h->imsg[2] & 0x18) {
 				p += 7;                     /* ignore enhanced / absolute VP */
 			}
-			p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
+			p += unpacksms(h->dcs, h->imsg + p, h->udh, ARRAY_LEN(h->udh), &h->udhl, h->ud, ARRAY_LEN(h->ud), &h->udl, h->udhi);
 			h->rx = 1;                      /* received message */
 			sms_writefile(h);               /* write the file */
 			if (p != h->imsg[1] + 2) {
@@ -1164,12 +1208,12 @@ static unsigned char sms_handleincoming (sms_t * h)
 			h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
 			h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
 			h->mr = -1;
-			p += unpackaddress(h->oa, h->imsg + p);
+			p += unpackaddress(h->oa, ARRAY_LEN(h->oa), h->imsg + p);
 			h->pid = h->imsg[p++];
 			h->dcs = h->imsg[p++];
 			h->scts = unpackdate(h->imsg + p);
 			p += 7;
-			p += unpacksms(h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
+			p += unpacksms(h->dcs, h->imsg + p, h->udh, ARRAY_LEN(h->udh), &h->udhl, h->ud, ARRAY_LEN(h->ud), &h->udl, h->udhi);
 			h->rx = 1;                      /* received message */
 			sms_writefile(h);               /* write the file */
 			if (p != h->imsg[1] + 2) {