diff options
author | Pau Espin Pedrol <pespin@sysmocom.de> | 2018-02-09 12:08:38 +0100 |
---|---|---|
committer | Pau Espin Pedrol <pespin@sysmocom.de> | 2018-02-09 13:15:51 +0100 |
commit | 54be46949e93e07e9e57b706388ebb832e5fad0a (patch) | |
tree | 2af7bf4127d4c474e1c35e3038c301e491f3a8e5 /src | |
parent | 98f3f700797dcbf4777210c8100af79e27ffa7f1 (diff) |
l1sap: Validate incoming RTP payload, drop bw-efficient AMR
A recurrent kernel crash in sysmobts (several kernel versions)
corrupting kernel memory in random places has been investigated and
reproduced by placing a call against an MSC sending RTP
with bandwidth-efficient AMR payload to osmo-bts-sysmo.
The osmo-bts-sysmo in turn sends the payload to the femtobts related
kernel modules via a msgq, which most probably fail to handle correctly
this bw-efficient AMR payload and corrupt the kernel memory.
First approach was to drop the bw-efficient AMR payloads lower in the
stack in sysmo specific code (l1if_tch_encode), but as there's no bts
model in osmo-bts actually supporting bw-efficient AMR, let's drop it
early in the incoming path for all models to avoid further problems.
Related: SYS#4063
Change-Id: If0c9233c628c724de4ab74e58e3e2affac79e6d0
Diffstat (limited to 'src')
-rw-r--r-- | src/common/l1sap.c | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/src/common/l1sap.c b/src/common/l1sap.c index e181a73b..1deee835 100644 --- a/src/common/l1sap.c +++ b/src/common/l1sap.c @@ -819,6 +819,47 @@ static int l1sap_handover_rach(struct gsm_bts_trx *trx, return 0; } +static bool rtppayload_is_octet_aligned(const uint8_t *rtp_pl, uint8_t payload_len) +{ + /* + * Logic: If 1st bit padding is not zero, packet is either: + * - bandwidth-efficient AMR payload. + * - malformed packet. + * However, Bandwidth-efficient AMR 4,75 frame last in payload(F=0, FT=0) + * with 4th,5ht,6th AMR payload to 0 matches padding==0. + * Furthermore, both AMR 4,75 bw-efficient and octet alignment are 14 bytes long (AMR 4,75 encodes 95b): + * bw-efficient: 95b, + 4b hdr + 6b ToC = 105b, + padding = 112b = 14B. + * octet-aligned: 1B hdr + 1B ToC + 95b = 111b, + padding = 112b = 14B. + * We cannot use other fields to match since they are inside the AMR + * payload bits which are unknown. + * As a result, this function may return false positive (true) for some AMR + * 4,75 AMR frames, but given the length, CMR and FT read is the same as a + * consequence, the damage in here is harmless other than being unable to + * decode the audio at the other side. + */ + #define AMR_PADDING1(rtp_pl) (rtp_pl[0] & 0x0f) + #define AMR_PADDING2(rtp_pl) (rtp_pl[1] & 0x03) + + if(payload_len < 2 || AMR_PADDING1(rtp_pl) || AMR_PADDING2(rtp_pl)) + return false; + + return true; +} + +static bool rtppayload_is_valid(struct gsm_lchan *lchan, struct msgb *resp_msg) +{ + /* Avoid sending bw-efficient AMR to lower layers, most bts models + * don't support it. */ + if(lchan->tch_mode == GSM48_CMODE_SPEECH_AMR && + !rtppayload_is_octet_aligned(resp_msg->data, resp_msg->len)) { + LOGP(DL1P, LOGL_NOTICE, + "%s RTP->L1: Dropping unexpected AMR encoding (bw-efficient?) %s\n", + gsm_lchan_name(lchan), osmo_hexdump(resp_msg->data, resp_msg->len)); + return false; + } + return true; +} + /* TCH-RTS-IND prim recevied from bts model */ static int l1sap_tch_rts_ind(struct gsm_bts_trx *trx, struct osmo_phsap_prim *l1sap, struct ph_tch_param *rts_ind) @@ -860,6 +901,10 @@ static int l1sap_tch_rts_ind(struct gsm_bts_trx *trx, LOGP(DL1P, LOGL_DEBUG, "%s DL TCH Tx queue underrun\n", gsm_lchan_name(lchan)); resp_l1sap = &empty_l1sap; + } else if(!rtppayload_is_valid(lchan, resp_msg)) { + msgb_free(resp_msg); + resp_msg = NULL; + resp_l1sap = &empty_l1sap; } else { /* Obtain RTP header Marker bit from control buffer */ marker = rtpmsg_marker_bit(resp_msg); |