From 1d7f3b5eb27154b5d1ef698b40edfb9f74a9d4d2 Mon Sep 17 00:00:00 2001 From: Jacob Erlbeck Date: Mon, 12 Aug 2013 17:07:53 +0200 Subject: sms: Added result buffer size parameter to 7bit conv funs The 7bit<->8bit encoding/decoding functions didn't check whether there is still enough space in the destination buffer. Therefore a buffer size parameter has been added to each of the functions which is used to truncate the output if the buffer is too small. In addition, the return value of the decoding functions has been changed to number of characters written (excluding \0), so this value is always equal to strlen(decoded). The old functions are still available as wrapper functions. --- src/gsm/gsm0480.c | 11 ++-- src/gsm/gsm_utils.c | 145 ++++++++++++++++++++++++++++++++----------------- src/gsm/libosmogsm.map | 7 ++- 3 files changed, 104 insertions(+), 59 deletions(-) (limited to 'src/gsm') diff --git a/src/gsm/gsm0480.c b/src/gsm/gsm0480.c index cc693feb..92a62dcf 100644 --- a/src/gsm/gsm0480.c +++ b/src/gsm/gsm0480.c @@ -105,7 +105,7 @@ struct msgb *gsm0480_create_unstructuredSS_Notify(int alertPattern, const char * msgb_put_u8(msg, ASN1_OCTET_STRING_TAG); ussd_len_ptr = msgb_put(msg, 1); data = msgb_put(msg, 0); - gsm_7bit_encode_ussd(data, text, &len); + gsm_7bit_encode_n_ussd(data, msgb_tailroom(msg), text, &len); msgb_put(msg, len); ussd_len_ptr[0] = len; /* USSD-String } */ @@ -172,7 +172,7 @@ struct msgb *gsm0480_create_notifySS(const char *text) msgb_put_u8(msg, 0x82); tmp_len = msgb_put(msg, 1); data = msgb_put(msg, 0); - gsm_7bit_encode_ussd(data, text, &len); + gsm_7bit_encode_n_ussd(data, msgb_tailroom(msg), text, &len); tmp_len[0] = len; msgb_put(msg, len); @@ -398,10 +398,7 @@ static int parse_process_uss_req(const uint8_t *uss_req_data, uint16_t length, if ((dcs == 0x0F) && (uss_req_data[5] == ASN1_OCTET_STRING_TAG)) { num_chars = (uss_req_data[6] * 8) / 7; - /* Prevent a mobile-originated buffer-overrun! */ - if (num_chars > MAX_LEN_USSD_STRING) - num_chars = MAX_LEN_USSD_STRING; - gsm_7bit_decode_ussd(req->text, + gsm_7bit_decode_n_ussd(req->text, sizeof(req->text), &(uss_req_data[7]), num_chars); rc = 1; } @@ -423,7 +420,7 @@ struct msgb *gsm0480_create_ussd_resp(uint8_t invoke_id, uint8_t trans_id, const /* First put the payload text into the message */ ptr8 = msgb_put(msg, 0); - gsm_7bit_encode_ussd(ptr8, text, &response_len); + gsm_7bit_encode_n_ussd(ptr8, msgb_tailroom(msg), text, &response_len); msgb_put(msg, response_len); /* Then wrap it as an Octet String */ diff --git a/src/gsm/gsm_utils.c b/src/gsm/gsm_utils.c index 3dd15375..e248078f 100644 --- a/src/gsm/gsm_utils.c +++ b/src/gsm/gsm_utils.c @@ -28,7 +28,7 @@ * This library is a collection of common code used in various * GSM related sub-projects inside the Osmocom family of projects. It * includes A5/1 and A5/2 ciphers, COMP128v1, a LAPDm implementation, - * a GSM TLV parser, SMS utility routines as well as + * a GSM TLV parser, SMS utility routines as well as * protocol definitions for a series of protocols: * * Um L2 (04.06) * * Um L3 (04.08) @@ -123,12 +123,17 @@ uint8_t gsm_get_octet_len(const uint8_t sept_len){ } /* GSM 03.38 6.2.1 Character unpacking */ -int gsm_7bit_decode_hdr(char *text, const uint8_t *user_data, uint8_t septet_l, uint8_t ud_hdr_ind) +int gsm_7bit_decode_n_hdr(char *text, size_t n, const uint8_t *user_data, uint8_t septet_l, uint8_t ud_hdr_ind) { int i = 0; int shift = 0; - uint8_t c; + uint8_t c7, c8; uint8_t next_is_ext = 0; + const char *text_buf_begin = text; + const char *text_buf_end = text + n; + int nchars; + + OSMO_ASSERT (n > 0); /* skip the user data header */ if (ud_hdr_ind) { @@ -139,50 +144,49 @@ int gsm_7bit_decode_hdr(char *text, const uint8_t *user_data, uint8_t septet_l, septet_l = septet_l - shift; } - for (i = 0; i < septet_l; i++) { - c = + for (i = 0; i < septet_l && text != text_buf_end - 1; i++) { + c7 = ((user_data[((i + shift) * 7 + 7) >> 3] << (7 - (((i + shift) * 7 + 7) & 7))) | (user_data[((i + shift) * 7) >> 3] >> (((i + shift) * 7) & 7))) & 0x7f; - /* this is an extension character */ if (next_is_ext) { + /* this is an extension character */ next_is_ext = 0; - *(text++) = gsm_7bit_alphabet[0x7f + c]; - continue; - } - - if (c == 0x1b && i + 1 < septet_l) { + c8 = gsm_7bit_alphabet[0x7f + c7]; + } else if (c7 == 0x1b && i + 1 < septet_l) { next_is_ext = 1; + continue; } else { - *(text++) = gsm_septet_lookup(c); + c8 = gsm_septet_lookup(c7); } + + *(text++) = c8; } - if (ud_hdr_ind) - i += shift; + nchars = text - text_buf_begin; + *text = '\0'; - return i; + return nchars; } -int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t septet_l) +int gsm_7bit_decode_n(char *text, size_t n, const uint8_t *user_data, uint8_t septet_l) { - return gsm_7bit_decode_hdr(text, user_data, septet_l, 0); + return gsm_7bit_decode_n_hdr(text, n, user_data, septet_l, 0); } -int gsm_7bit_decode_ussd(char *text, const uint8_t *user_data, uint8_t length) +int gsm_7bit_decode_n_ussd(char *text, size_t n, const uint8_t *user_data, uint8_t length) { - int i; + int nchars; - gsm_7bit_decode_hdr(text, user_data, length, 0); - i = strlen(text); + nchars = gsm_7bit_decode_n_hdr(text, n, user_data, length, 0); /* remove last , if it fits up to the end of last octet */ - if (i && (user_data[gsm_get_octet_len(length) - 1] >> 1) == '\r') - text[--i] = '\0'; + if (nchars && (user_data[gsm_get_octet_len(length) - 1] >> 1) == '\r') + text[--nchars] = '\0'; - return i; + return nchars; } /* GSM 03.38 6.2.1 Prepare character packing */ @@ -261,38 +265,28 @@ int gsm_septets2octets(uint8_t *result, const uint8_t *rdata, uint8_t septet_len } /* GSM 03.38 6.2.1 Character packing */ -int gsm_7bit_encode(uint8_t *result, const char *data) -{ - int out; - return gsm_7bit_encode_oct(result, data, &out); -} - -int gsm_7bit_encode_ussd(uint8_t *result, const char *data, int *octets) -{ - int y; - - y = gsm_7bit_encode_oct(result, data, octets); - /* if last octet contains only one bit, add */ - if (((y * 7) & 7) == 1) - result[(*octets) - 1] |= ('\r' << 1); - /* if last character is and completely fills last octet, add - * another . */ - if (y && ((y * 7) & 7) == 0 && (result[(*octets) - 1] >> 1) == '\r') { - result[(*octets)++] = '\r'; - y++; - } - - return y; -} - -int gsm_7bit_encode_oct(uint8_t *result, const char *data, int *octets) +int gsm_7bit_encode_n(uint8_t *result, size_t n, const char *data, int *octets) { int y = 0; + int o; + int max_septets = n * 8 / 7; /* prepare for the worst case, every character expanding to two bytes */ uint8_t *rdata = calloc(strlen(data) * 2, sizeof(uint8_t)); y = gsm_septet_encode(rdata, data); - *octets = gsm_septets2octets(result, rdata, y, 0); + + if (y > max_septets) { + /* + * Limit the number of septets to avoid the generation + * of more than n octets. + */ + y = max_septets; + } + + o = gsm_septets2octets(result, rdata, y, 0); + + if (octets) + *octets = o; free(rdata); @@ -309,6 +303,24 @@ int gsm_7bit_encode_oct(uint8_t *result, const char *data, int *octets) return y; } +int gsm_7bit_encode_n_ussd(uint8_t *result, size_t n, const char *data, int *octets) +{ + int y; + + y = gsm_7bit_encode_n(result, n, data, octets); + /* if last octet contains only one bit, add */ + if (((y * 7) & 7) == 1) + result[(*octets) - 1] |= ('\r' << 1); + /* if last character is and completely fills last octet, add + * another . */ + if (y && ((y * 7) & 7) == 0 && (result[(*octets) - 1] >> 1) == '\r' && *octets < n - 1) { + result[(*octets)++] = '\r'; + y++; + } + + return y; +} + /* convert power class to dBm according to GSM TS 05.05 */ unsigned int ms_class_gmsk_dbm(enum gsm_band band, int class) { @@ -373,7 +385,7 @@ int ms_pwr_ctl_lvl(enum gsm_band band, unsigned int dbm) case GSM_BAND_1800: if (dbm >= 36) return 29; - else if (dbm >= 34) + else if (dbm >= 34) return 30; else if (dbm >= 32) return 31; @@ -662,3 +674,34 @@ uint32_t gprs_tmsi2tlli(uint32_t p_tmsi, enum gprs_tlli_type type) } return tlli; } + +/* Wrappers for deprecated functions: */ + +int gsm_7bit_decode(char *text, const uint8_t *user_data, uint8_t septet_l) +{ + gsm_7bit_decode_n(text, SIZE_MAX, user_data, septet_l); + + /* Mimic the original behaviour. */ + return septet_l; +} + +int gsm_7bit_decode_ussd(char *text, const uint8_t *user_data, uint8_t length) +{ + return gsm_7bit_decode_n_ussd(text, SIZE_MAX, user_data, length); +} + +int gsm_7bit_encode(uint8_t *result, const char *data) +{ + int out; + return gsm_7bit_encode_n(result, SIZE_MAX, data, &out); +} + +int gsm_7bit_encode_ussd(uint8_t *result, const char *data, int *octets) +{ + return gsm_7bit_encode_n_ussd(result, SIZE_MAX, data, octets); +} + +int gsm_7bit_encode_oct(uint8_t *result, const char *data, int *octets) +{ + return gsm_7bit_encode_n(result, SIZE_MAX, data, octets); +} diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index 1b985e10..9d15d668 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -133,11 +133,16 @@ gsm48_rr_att_tlvdef; gsm_7bit_decode; gsm_7bit_decode_ussd; -gsm_7bit_decode_hdr; gsm_7bit_encode; gsm_7bit_encode_ussd; gsm_7bit_encode_oct; +gsm_7bit_decode_n; +gsm_7bit_decode_n_ussd; +gsm_7bit_decode_n_hdr; +gsm_7bit_encode_n; +gsm_7bit_encode_n_ussd; + gsm_arfcn2band; gsm_arfcn2freq10; gsm_freq102arfcn; -- cgit v1.2.3