Commit message: None
CVE: CVE-2016-2452
CWE: CWE-264
Vulnerability description: codecs/amrnb/dec/SoftAMR.cpp in libstagefright in mediaserver in Android 4.x before 4.4.4, 5.0.x before 5.0.2, 5.1.x before 5.1.1, and 6.x before 2016-05-01 does not validate buffer sizes, which allows attackers to gain privileges via a crafted application, as demonstrated by obtaining Signature or SignatureOrSystem access, aka internal bugs 27662364 and 27843673.

Project: Android

SoftAMR::SoftAMR(
 const char *name,
 const OMX_CALLBACKTYPE *callbacks,
        OMX_PTR appData,
        OMX_COMPONENTTYPE **component)
 : SimpleSoftOMXComponent(name, callbacks, appData, component),
      mMode(MODE_NARROW),
      mState(NULL),
      mDecoderBuf(NULL),
      mDecoderCookie(NULL),
      mInputBufferCount(0),
      mAnchorTimeUs(0),
      mNumSamplesOutput(0),
      mSignalledError(false),
      mOutputPortSettingsChange(NONE) {
 if (!strcmp(name, "OMX.google.amrwb.decoder")) {
        mMode = MODE_WIDE;
 } else {
        CHECK(!strcmp(name, "OMX.google.amrnb.decoder"));
 }

    initPorts();
    CHECK_EQ(initDecoder(), (status_t)OK);
}

Project: Android

android::SoftOMXComponent *createSoftOMXComponent(
 const char *name, const OMX_CALLBACKTYPE *callbacks,
        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
 return new android::SoftAMR(name, callbacks, appData, component);
}

Project: Android

static size_t getFrameSize(unsigned FT) {
 static const size_t kFrameSizeWB[10] = {
 132, 177, 253, 285, 317, 365, 397, 461, 477, 40
 };

 if (FT >= 10) {
 return 1;
 }

 size_t frameSize = kFrameSizeWB[FT];

    frameSize = (frameSize + 7) / 8 + 1;

 return frameSize;
}

Project: Android

status_t SoftAMR::initDecoder() {
 if (mMode == MODE_NARROW) {
 Word16 err = GSMInitDecode(&mState, (Word8 *)"AMRNBDecoder");

 if (err != 0) {
 return UNKNOWN_ERROR;
 }
 } else {
 int32_t memReq = pvDecoder_AmrWbMemRequirements();
        mDecoderBuf = malloc(memReq);

        pvDecoder_AmrWb_Init(&mState, mDecoderBuf, &mDecoderCookie);
 }

 return OK;
}

Project: Android

void SoftAMR::initPorts() {
    OMX_PARAM_PORTDEFINITIONTYPE def;
 InitOMXParams(&def);

    def.nPortIndex = 0;
    def.eDir = OMX_DirInput;
    def.nBufferCountMin = kNumBuffers;
    def.nBufferCountActual = def.nBufferCountMin;
    def.nBufferSize = 8192;
    def.bEnabled = OMX_TRUE;
    def.bPopulated = OMX_FALSE;
    def.eDomain = OMX_PortDomainAudio;
    def.bBuffersContiguous = OMX_FALSE;
    def.nBufferAlignment = 1;

    def.format.audio.cMIMEType =
        mMode == MODE_NARROW
 ? const_cast<char *>("audio/amr")
 : const_cast<char *>("audio/amrwb");

    def.format.audio.pNativeRender = NULL;
    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
    def.format.audio.eEncoding = OMX_AUDIO_CodingAMR;

    addPort(def);

    def.nPortIndex = 1;
    def.eDir = OMX_DirOutput;
    def.nBufferCountMin = kNumBuffers;
    def.nBufferCountActual = def.nBufferCountMin;

    def.nBufferSize =
 (mMode == MODE_NARROW ? kNumSamplesPerFrameNB : kNumSamplesPerFrameWB)
 * sizeof(int16_t);

    def.bEnabled = OMX_TRUE;
    def.bPopulated = OMX_FALSE;
    def.eDomain = OMX_PortDomainAudio;
    def.bBuffersContiguous = OMX_FALSE;
    def.nBufferAlignment = 2;

    def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
    def.format.audio.pNativeRender = NULL;
    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;

    addPort(def);
}

Project: Android

bool SoftAMR::isConfigured() const {
 return mInputBufferCount > 0;
}

Project: Android

void SoftAMR::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
 if (portIndex != 1) {
 return;
 }

 switch (mOutputPortSettingsChange) {
 case NONE:
 break;

 case AWAITING_DISABLED:
 {
            CHECK(!enabled);
            mOutputPortSettingsChange = AWAITING_ENABLED;
 break;
 }

 default:
 {
            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
            CHECK(enabled);
            mOutputPortSettingsChange = NONE;
 break;
 }
 }
}

Project: Android

void SoftAMR::onPortFlushCompleted(OMX_U32 portIndex) {
    ALOGV("onPortFlushCompleted portindex %d, resetting frame ", portIndex);
 if (portIndex == 0) {
 if (mMode == MODE_NARROW) {
 Speech_Decode_Frame_reset(mState);
 } else {
           pvDecoder_AmrWb_Reset(mState, 0 /* reset_all */);
 }
 }
}

Project: Android

void SoftAMR::onReset() {
    mSignalledError = false;
    mOutputPortSettingsChange = NONE;
}

Project: Android

SoftAMR::~SoftAMR() {
 if (mMode == MODE_NARROW) {
 GSMDecodeFrameExit(&mState);
        mState = NULL;
 } else {
        free(mDecoderBuf);
        mDecoderBuf = NULL;

        mState = NULL;
        mDecoderCookie = NULL;
 }
}