Commit message: None
CVE: CVE-2016-2499
CWE: CWE-200
Vulnerability description: AudioSource.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-06-01 does not initialize certain data, which allows attackers to obtain sensitive information via a crafted application, aka internal bug 27855172.

Project: Android

static void AudioRecordCallbackFunction(int event, void *user, void *info) {
 AudioSource *source = (AudioSource *) user;
 switch (event) {
 case AudioRecord::EVENT_MORE_DATA: {
            source->dataCallback(*((AudioRecord::Buffer *) info));
 break;
 }
 case AudioRecord::EVENT_OVERRUN: {
            ALOGW("AudioRecord reported overrun!");
 break;
 }
 default:
 break;
 }
}

Project: Android

status_t AudioSource::dataCallback(const AudioRecord::Buffer& audioBuffer) {
 int64_t timeUs = systemTime() / 1000ll;
    timeUs -= mRecord->latency() * 1000LL;

    ALOGV("dataCallbackTimestamp: %" PRId64 " us", timeUs);
 Mutex::Autolock autoLock(mLock);
 if (!mStarted) {
        ALOGW("Spurious callback from AudioRecord. Drop the audio data.");
 return OK;
 }

 if (mNumFramesReceived == 0 && timeUs < mStartTimeUs) {
 (void) mRecord->getInputFramesLost();
        ALOGV("Drop audio data at %" PRId64 "/%" PRId64 " us", timeUs, mStartTimeUs);
 return OK;
 }

 if (mNumFramesReceived == 0 && mPrevSampleTimeUs == 0) {
        mInitialReadTimeUs = timeUs;
 if (mStartTimeUs > 0) {
            mStartTimeUs = timeUs - mStartTimeUs;
 } else {
            mStartTimeUs += mRecord->latency() * 1000;
 }

        mPrevSampleTimeUs = mStartTimeUs;
 }

 size_t numLostBytes = 0;
 if (mNumFramesReceived > 0) { // Ignore earlier frame lost
        numLostBytes = mRecord->getInputFramesLost() * mRecord->frameSize();
 }

    CHECK_EQ(numLostBytes & 1, 0u);
    CHECK_EQ(audioBuffer.size & 1, 0u);
 if (numLostBytes > 0) {
        ALOGW("Lost audio record data: %zu bytes", numLostBytes);
 }

 while (numLostBytes > 0) {
 size_t bufferSize = numLostBytes;
 if (numLostBytes > kMaxBufferSize) {
            numLostBytes -= kMaxBufferSize;
            bufferSize = kMaxBufferSize;
 } else {
            numLostBytes = 0;
 }
 MediaBuffer *lostAudioBuffer = new MediaBuffer(bufferSize);
        memset(lostAudioBuffer->data(), 0, bufferSize);
        lostAudioBuffer->set_range(0, bufferSize);
        queueInputBuffer_l(lostAudioBuffer, timeUs);
 }

 if (audioBuffer.size == 0) {
        ALOGW("Nothing is available from AudioRecord callback buffer");
 return OK;
 }

 const size_t bufferSize = audioBuffer.size;
 MediaBuffer *buffer = new MediaBuffer(bufferSize);
    memcpy((uint8_t *) buffer->data(),
            audioBuffer.i16, audioBuffer.size);
    buffer->set_range(0, bufferSize);
    queueInputBuffer_l(buffer, timeUs);
 return OK;
}

Project: Android

sp<MetaData> AudioSource::getFormat() {
 Mutex::Autolock autoLock(mLock);
 if (mInitCheck != OK) {
 return 0;
 }

    sp<MetaData> meta = new MetaData;
    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
    meta->setInt32(kKeySampleRate, mSampleRate);
    meta->setInt32(kKeyChannelCount, mRecord->channelCount());
    meta->setInt32(kKeyMaxInputSize, kMaxBufferSize);

 return meta;
}

Project: Android

int16_t AudioSource::getMaxAmplitude() {
 if (!mTrackMaxAmplitude) {
        mTrackMaxAmplitude = true;
 }
 int16_t value = mMaxAmplitude;
    mMaxAmplitude = 0;
    ALOGV("max amplitude since last call: %d", value);
 return value;
}

Project: Android

status_t AudioSource::read(
 MediaBuffer **out, const ReadOptions * /* options */) {
 Mutex::Autolock autoLock(mLock);
 *out = NULL;

 if (mInitCheck != OK) {
 return NO_INIT;
 }

 while (mStarted && mBuffersReceived.empty()) {
        mFrameAvailableCondition.wait(mLock);
 }
 if (!mStarted) {
 return OK;
 }
 MediaBuffer *buffer = *mBuffersReceived.begin();
    mBuffersReceived.erase(mBuffersReceived.begin());
 ++mNumClientOwnedBuffers;
    buffer->setObserver(this);
    buffer->add_ref();

 int64_t timeUs;
    CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
 int64_t elapsedTimeUs = timeUs - mStartTimeUs;
 if (elapsedTimeUs < kAutoRampStartUs) {
        memset((uint8_t *) buffer->data(), 0, buffer->range_length());
 } else if (elapsedTimeUs < kAutoRampStartUs + kAutoRampDurationUs) {
 int32_t autoRampDurationFrames =
 ((int64_t)kAutoRampDurationUs * mSampleRate + 500000LL) / 1000000LL; //Need type casting

 int32_t autoRampStartFrames =
 ((int64_t)kAutoRampStartUs * mSampleRate + 500000LL) / 1000000LL; //Need type casting

 int32_t nFrames = mNumFramesReceived - autoRampStartFrames;
        rampVolume(nFrames, autoRampDurationFrames,
 (uint8_t *) buffer->data(), buffer->range_length());
 }

 if (mTrackMaxAmplitude) {
        trackMaxAmplitude(
 (int16_t *) buffer->data(), buffer->range_length() >> 1);
 }

 if (mSampleRate != mOutSampleRate) {
 if (mFirstSampleTimeUs < 0) {
            mFirstSampleTimeUs = timeUs;
 }
        timeUs = mFirstSampleTimeUs + (timeUs - mFirstSampleTimeUs)
 * (int64_t)mSampleRate / (int64_t)mOutSampleRate;
        buffer->meta_data()->setInt64(kKeyTime, timeUs);
 }

 *out = buffer;
 return OK;
}

Project: Android

void AudioSource::releaseQueuedFrames_l() {
    ALOGV("releaseQueuedFrames_l");
 List<MediaBuffer *>::iterator it;
 while (!mBuffersReceived.empty()) {
        it = mBuffersReceived.begin();
 (*it)->release();
        mBuffersReceived.erase(it);
 }
}

Project: Android

status_t AudioSource::reset() {
 Mutex::Autolock autoLock(mLock);
 if (!mStarted) {
 return UNKNOWN_ERROR;
 }

 if (mInitCheck != OK) {
 return NO_INIT;
 }

    mStarted = false;
    mFrameAvailableCondition.signal();

    mRecord->stop();
    waitOutstandingEncodingFrames_l();
    releaseQueuedFrames_l();

 return OK;
}

Project: Android

void AudioSource::signalBufferReturned(MediaBuffer *buffer) {
    ALOGV("signalBufferReturned: %p", buffer->data());
 Mutex::Autolock autoLock(mLock);
 --mNumClientOwnedBuffers;
    buffer->setObserver(0);
    buffer->release();
    mFrameEncodingCompletionCondition.signal();
 return;
}

Project: Android

status_t AudioSource::start(MetaData *params) {
 Mutex::Autolock autoLock(mLock);
 if (mStarted) {
 return UNKNOWN_ERROR;
 }

 if (mInitCheck != OK) {
 return NO_INIT;
 }

    mTrackMaxAmplitude = false;
    mMaxAmplitude = 0;
    mInitialReadTimeUs = 0;
    mStartTimeUs = 0;
 int64_t startTimeUs;
 if (params && params->findInt64(kKeyTime, &startTimeUs)) {
        mStartTimeUs = startTimeUs;
 }
 status_t err = mRecord->start();
 if (err == OK) {
        mStarted = true;
 } else {
        mRecord.clear();
 }


 return err;
}

Project: Android

void AudioSource::trackMaxAmplitude(int16_t *data, int nSamples) {
 for (int i = nSamples; i > 0; --i) {
 int16_t value = *data++;
 if (value < 0) {
            value = -value;
 }
 if (mMaxAmplitude < value) {
            mMaxAmplitude = value;
 }
 }
}

Project: Android

void AudioSource::waitOutstandingEncodingFrames_l() {
    ALOGV("waitOutstandingEncodingFrames_l: %" PRId64, mNumClientOwnedBuffers);
 while (mNumClientOwnedBuffers > 0) {
        mFrameEncodingCompletionCondition.wait(mLock);
 }
}

Project: Android

AudioSource::~AudioSource() {
 if (mStarted) {
        reset();
 }
}