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) {