Commit message: None
CVE: CVE-2018-9503
CWE: CWE-125
Vulnerability description: In rfc_process_mx_message of rfc_ts_frames.cc, there is a possible out of bounds read due to a missing bounds check. This could lead to remote information disclosure with no additional execution privileges needed. User interaction is not needed for exploitation. Product: Android Versions: Android-7.0 Android-7.1.1 Android-7.1.2 Android-8.0 Android-8.1 Android-9.0 Android ID: A-80432928

Project: Android

void rfc_send_buf_uih(tRFC_MCB* p_mcb, uint8_t dlci, BT_HDR* p_buf) {
 uint8_t* p_data;
 uint8_t cr = RFCOMM_CR(p_mcb->is_initiator, true);
 uint8_t credits;

  p_buf->offset -= RFCOMM_CTRL_FRAME_LEN;
 if (p_buf->len > 127) p_buf->offset--;

 if (dlci)
    credits = (uint8_t)p_buf->layer_specific;
 else
    credits = 0;

 if (credits) p_buf->offset--;

  p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;

 /* UIH frame, command, PF = 0, dlci */
 *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
 *p_data++ = RFCOMM_UIH | ((credits) ? RFCOMM_PF : 0);
 if (p_buf->len <= 127) {
 *p_data++ = RFCOMM_EA | (p_buf->len << 1);
    p_buf->len += 3;
 } else {
 *p_data++ = (p_buf->len & 0x7f) << 1;
 *p_data++ = p_buf->len >> RFCOMM_SHIFT_LENGTH2;
    p_buf->len += 4;
 }

 if (credits) {
 *p_data++ = credits;
    p_buf->len++;
 }

  p_data = (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len++;

 *p_data = RFCOMM_UIH_FCS((uint8_t*)(p_buf + 1) + p_buf->offset, dlci);

 if (dlci == RFCOMM_MX_DLCI) {
    rfc_check_send_cmd(p_mcb, p_buf);
 } else {
    L2CA_DataWrite(p_mcb->lcid, p_buf);
 }
}

Project: Android

void rfc_send_credit(tRFC_MCB* p_mcb, uint8_t dlci, uint8_t credit) {
 uint8_t* p_data;
 uint8_t cr = RFCOMM_CR(p_mcb->is_initiator, true);
  BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);

  p_buf->offset = L2CAP_MIN_OFFSET;
  p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;

 *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
 *p_data++ = RFCOMM_UIH | RFCOMM_PF;
 *p_data++ = RFCOMM_EA | 0;
 *p_data++ = credit;
 *p_data = RFCOMM_UIH_FCS((uint8_t*)(p_buf + 1) + p_buf->offset, dlci);

  p_buf->len = 5;

  rfc_check_send_cmd(p_mcb, p_buf);
}

Project: Android

void rfc_send_disc(tRFC_MCB* p_mcb, uint8_t dlci) {
 uint8_t* p_data;
 uint8_t cr = RFCOMM_CR(p_mcb->is_initiator, true);
  BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);

  p_buf->offset = L2CAP_MIN_OFFSET;
  p_data = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;

 /* DISC frame, command, PF = 1, dlci */
 *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
 *p_data++ = RFCOMM_DISC | RFCOMM_PF;
 *p_data++ = RFCOMM_EA | 0;

 *p_data = RFCOMM_DISC_FCS((uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);

  p_buf->len = 4;

  rfc_check_send_cmd(p_mcb, p_buf);
}

Project: Android

void rfc_send_dm(tRFC_MCB* p_mcb, uint8_t dlci, bool pf) {
 uint8_t* p_data;
 uint8_t cr = RFCOMM_CR(p_mcb->is_initiator, false);
  BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);

  p_buf->offset = L2CAP_MIN_OFFSET;
  p_data = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;

 /* DM frame, response, PF = 1, dlci */
 *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
 *p_data++ = RFCOMM_DM | ((pf) ? RFCOMM_PF : 0);
 *p_data++ = RFCOMM_EA | 0;

 *p_data = RFCOMM_DM_FCS((uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);

  p_buf->len = 4;

  rfc_check_send_cmd(p_mcb, p_buf);
}

Project: Android

void rfc_send_fcoff(tRFC_MCB* p_mcb, bool is_command) {
 uint8_t* p_data;
  BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);

  p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
  p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;

 *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_FCOFF;
 *p_data++ = RFCOMM_EA | (RFCOMM_MX_FCOFF_LEN << 1);

 /* Total length is sizeof FCOFF data + mx header 2 */
  p_buf->len = RFCOMM_MX_FCOFF_LEN + 2;

  rfc_send_buf_uih(p_mcb, RFCOMM_MX_DLCI, p_buf);
}

Project: Android

void rfc_send_msc(tRFC_MCB* p_mcb, uint8_t dlci, bool is_command,
                  tPORT_CTRL* p_pars) {
 uint8_t* p_data;
 uint8_t signals;
 uint8_t break_duration;
 uint8_t len;
  BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);

  signals = p_pars->modem_signal;
  break_duration = p_pars->break_signal;

  p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
  p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;

 if (break_duration)
    len = RFCOMM_MX_MSC_LEN_WITH_BREAK;
 else
    len = RFCOMM_MX_MSC_LEN_NO_BREAK;

 *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_MSC;
 *p_data++ = RFCOMM_EA | (len << 1);

 *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI);
 *p_data++ = RFCOMM_EA | ((p_pars->fc) ? RFCOMM_MSC_FC : 0) |
 ((signals & MODEM_SIGNAL_DTRDSR) ? RFCOMM_MSC_RTC : 0) |
 ((signals & MODEM_SIGNAL_RTSCTS) ? RFCOMM_MSC_RTR : 0) |
 ((signals & MODEM_SIGNAL_RI) ? RFCOMM_MSC_IC : 0) |
 ((signals & MODEM_SIGNAL_DCD) ? RFCOMM_MSC_DV : 0);

 if (break_duration) {
 *p_data++ = RFCOMM_EA | RFCOMM_MSC_BREAK_PRESENT_MASK |
 (break_duration << RFCOMM_MSC_SHIFT_BREAK);
 }

 /* Total length is sizeof MSC data + mx header 2 */
  p_buf->len = len + 2;

  rfc_send_buf_uih(p_mcb, RFCOMM_MX_DLCI, p_buf);
}

Project: Android

void rfc_send_nsc(tRFC_MCB* p_mcb) {
 uint8_t* p_data;
  BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);

  p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
  p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;

 *p_data++ = RFCOMM_EA | RFCOMM_I_CR(false) | RFCOMM_MX_NSC;
 *p_data++ = RFCOMM_EA | (RFCOMM_MX_NSC_LEN << 1);

 *p_data++ = rfc_cb.rfc.rx_frame.ea |
 (rfc_cb.rfc.rx_frame.cr << RFCOMM_SHIFT_CR) |
              rfc_cb.rfc.rx_frame.type;

 /* Total length is sizeof NSC data + mx header 2 */
  p_buf->len = RFCOMM_MX_NSC_LEN + 2;

  rfc_send_buf_uih(p_mcb, RFCOMM_MX_DLCI, p_buf);
}

Project: Android

void rfc_send_pn(tRFC_MCB* p_mcb, uint8_t dlci, bool is_command, uint16_t mtu,
 uint8_t cl, uint8_t k) {
 uint8_t* p_data;
  BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);

  p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
  p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;

 *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_PN;
 *p_data++ = RFCOMM_EA | (RFCOMM_MX_PN_LEN << 1);

 *p_data++ = dlci;
 *p_data++ = RFCOMM_PN_FRAM_TYPE_UIH | cl;

 /* It appeared that we need to reply with the same priority bits as we
  *received.
  ** We will use the fact that we reply in the same context so rx_frame can
  *still be used.
  */
 if (is_command)
 *p_data++ = RFCOMM_PN_PRIORITY_0;
 else
 *p_data++ = rfc_cb.rfc.rx_frame.u.pn.priority;

 *p_data++ = RFCOMM_T1_DSEC;
 *p_data++ = mtu & 0xFF;
 *p_data++ = mtu >> 8;
 *p_data++ = RFCOMM_N2;
 *p_data = k;

 /* Total length is sizeof PN data + mx header 2 */
  p_buf->len = RFCOMM_MX_PN_LEN + 2;

  rfc_send_buf_uih(p_mcb, RFCOMM_MX_DLCI, p_buf);
}

Project: Android

void rfc_send_rls(tRFC_MCB* p_mcb, uint8_t dlci, bool is_command,
 uint8_t status) {
 uint8_t* p_data;
  BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);

  p_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_CTRL_FRAME_LEN;
  p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;

 *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_RLS;
 *p_data++ = RFCOMM_EA | (RFCOMM_MX_RLS_LEN << 1);

 *p_data++ = RFCOMM_EA | RFCOMM_CR_MASK | (dlci << RFCOMM_SHIFT_DLCI);
 *p_data++ = RFCOMM_RLS_ERROR | status;

 /* Total length is sizeof RLS data + mx header 2 */
  p_buf->len = RFCOMM_MX_RLS_LEN + 2;

  rfc_send_buf_uih(p_mcb, RFCOMM_MX_DLCI, p_buf);
}

Project: Android

void rfc_send_test(tRFC_MCB* p_mcb, bool is_command, BT_HDR* p_buf) {
 /* Shift buffer to give space for header */
 if (p_buf->offset < (L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2)) {
 uint8_t* p_src = (uint8_t*)(p_buf + 1) + p_buf->offset + p_buf->len - 1;
    BT_HDR* p_new_buf =
 (BT_HDR*)osi_malloc(p_buf->len + (L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET +
 2 + sizeof(BT_HDR) + 1));

    p_new_buf->offset = L2CAP_MIN_OFFSET + RFCOMM_MIN_OFFSET + 2;
    p_new_buf->len = p_buf->len;

 uint8_t* p_dest =
 (uint8_t*)(p_new_buf + 1) + p_new_buf->offset + p_new_buf->len - 1;

 for (uint16_t xx = 0; xx < p_buf->len; xx++) *p_dest-- = *p_src--;

    osi_free(p_buf);
    p_buf = p_new_buf;
 }

 /* Adjust offset by number of bytes we are going to fill */
  p_buf->offset -= 2;
 uint8_t* p_data = (uint8_t*)(p_buf + 1) + p_buf->offset;

 *p_data++ = RFCOMM_EA | RFCOMM_I_CR(is_command) | RFCOMM_MX_TEST;
 *p_data++ = RFCOMM_EA | (p_buf->len << 1);

  p_buf->len += 2;

  rfc_send_buf_uih(p_mcb, RFCOMM_MX_DLCI, p_buf);
}

Project: Android

void rfc_send_ua(tRFC_MCB* p_mcb, uint8_t dlci) {
 uint8_t* p_data;
 uint8_t cr = RFCOMM_CR(p_mcb->is_initiator, false);
  BT_HDR* p_buf = (BT_HDR*)osi_malloc(RFCOMM_CMD_BUF_SIZE);

  p_buf->offset = L2CAP_MIN_OFFSET;
  p_data = (uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET;

 /* ua frame, response, PF = 1, dlci */
 *p_data++ = RFCOMM_EA | cr | (dlci << RFCOMM_SHIFT_DLCI);
 *p_data++ = RFCOMM_UA | RFCOMM_PF;
 *p_data++ = RFCOMM_EA | 0;

 *p_data = RFCOMM_UA_FCS((uint8_t*)(p_buf + 1) + L2CAP_MIN_OFFSET, cr, dlci);

  p_buf->len = 4;

  rfc_check_send_cmd(p_mcb, p_buf);
}