aboutsummaryrefslogtreecommitdiffstats
path: root/src/libmsc/gsm_04_11.c
diff options
context:
space:
mode:
authorVadim Yanitskiy <axilirator@gmail.com>2019-04-16 15:18:33 +0700
committerVadim Yanitskiy <axilirator@gmail.com>2019-05-10 03:22:32 +0700
commit4eca09fdb116e347746dc635d3f644bf188ec5a9 (patch)
treece3beaaef6d4df3d8c784be151580ce6d1b4d3ef /src/libmsc/gsm_04_11.c
parent53d3e0e54a6d9fe4356c6076cb8d064fba3b4e87 (diff)
libmsc/gsm_04_11.c: properly handle TP-User-Data-Length
As per 3GPP TS 03.40, section 9.2.3.16 "TP-User-Data-Length (TP-UDL)", if the TP-User-Data is coded using the GSM 7-bit default alphabet, the TP-User-Data-Length field indicates the *number of septets* within the TP-User-Data field to follow. Otherwise, i.e. in case of 8-bit or UCS-2 encoded data, the *number of octets* is indicated. Since we store the original TP-UDL value (as received), we might need to convert septets to octets before passing it to memcpy(). Otherwise this would lead to a buffer overrun. Also, as we receive TPDU from untrusted source (i.e. subscriber), the TP-UDL value needs to be checked against the corresponding maximum (160 septets or 140 octets) and truncated if needed. Please note that buffer overrun is still possible, e.g. when an indicated TP-UDL value is grather than the remaining TPDU length. Preventing this would require adding an additional check. Change-Id: I4b08db7665e854a045129e7695e2bdf296df1688 Depends-on: (core) I54f88d2908ac47228813fb8c049f4264e5145241
Diffstat (limited to 'src/libmsc/gsm_04_11.c')
-rw-r--r--src/libmsc/gsm_04_11.c41
1 files changed, 29 insertions, 12 deletions
diff --git a/src/libmsc/gsm_04_11.c b/src/libmsc/gsm_04_11.c
index ff5576f44..22e55dd95 100644
--- a/src/libmsc/gsm_04_11.c
+++ b/src/libmsc/gsm_04_11.c
@@ -42,6 +42,7 @@
#include <osmocom/gsm/gsm_utils.h>
#include <osmocom/gsm/gsm0411_utils.h>
#include <osmocom/gsm/protocol/gsm_04_11.h>
+#include <osmocom/gsm/protocol/gsm_03_40.h>
#include <osmocom/msc/debug.h>
#include <osmocom/msc/gsm_data.h>
@@ -545,19 +546,35 @@ static int gsm340_rx_tpdu(struct gsm_trans *trans, struct msgb *msg,
rc = GSM411_RP_CAUSE_MO_NET_OUT_OF_ORDER;
goto out;
}
+
+ /* As per 3GPP TS 03.40, section 9.2.3.16, TP-User-Data-Length (TP-UDL)
+ * may indicate either the number of septets, or the number of octets,
+ * depending on Data Coding Scheme. We store TP-UDL value as-is,
+ * so this should be kept in mind to avoid buffer overruns. */
gsms->user_data_len = *smsp++;
- if (gsms->user_data_len) {
- memcpy(gsms->user_data, smsp, gsms->user_data_len);
-
- switch (sms_alphabet) {
- case DCS_7BIT_DEFAULT:
- gsm_7bit_decode_n(gsms->text, sizeof(gsms->text), smsp,
- gsms->user_data_len);
- break;
- case DCS_8BIT_DATA:
- case DCS_UCS2:
- case DCS_NONE:
- break;
+ if (gsms->user_data_len > 0) {
+ if (sms_alphabet == DCS_7BIT_DEFAULT) {
+ /* TP-UDL is indicated in septets (up to 160) */
+ if (gsms->user_data_len > GSM340_UDL_SPT_MAX) {
+ LOG_TRANS(trans, LOGL_NOTICE,
+ "TP-User-Data-Length %u (septets) "
+ "is too big, truncating to %u\n",
+ gsms->user_data_len, GSM340_UDL_SPT_MAX);
+ gsms->user_data_len = GSM340_UDL_SPT_MAX;
+ }
+ memcpy(gsms->user_data, smsp, gsm_get_octet_len(gsms->user_data_len));
+ gsm_7bit_decode_n(gsms->text, sizeof(gsms->text),
+ smsp, gsms->user_data_len);
+ } else {
+ /* TP-UDL is indicated in octets (up to 140) */
+ if (gsms->user_data_len > GSM340_UDL_OCT_MAX) {
+ LOG_TRANS(trans, LOGL_NOTICE,
+ "TP-User-Data-Length %u (octets) "
+ "is too big, truncating to %u\n",
+ gsms->user_data_len, GSM340_UDL_OCT_MAX);
+ gsms->user_data_len = GSM340_UDL_OCT_MAX;
+ }
+ memcpy(gsms->user_data, smsp, gsms->user_data_len);
}
}