Commit message: None
CVE: CVE-2016-3764
CWE: CWE-20
Vulnerability description: media/libmediaplayerservice/MetadataRetrieverClient.cpp 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-07-01 allows attackers to obtain sensitive pointer information via a crafted application, aka internal bug 28377502.

Project: Android

MetadataRetrieverClient::MetadataRetrieverClient(pid_t pid)
{
    ALOGV("MetadataRetrieverClient constructor pid(%d)", pid);
    mPid = pid;
    mThumbnail = NULL;
    mAlbumArt = NULL;
    mRetriever = NULL;
}

Project: Android

static sp<MediaMetadataRetrieverBase> createRetriever(player_type playerType)
{
    sp<MediaMetadataRetrieverBase> p;
 switch (playerType) {
 case STAGEFRIGHT_PLAYER:
 case NU_PLAYER:
 {
            p = new StagefrightMetadataRetriever;
 break;
 }
 default:
            ALOGE("player type %d is not supported",  playerType);
 break;
 }
 if (p == NULL) {
        ALOGE("failed to create a retriever object");
 }
 return p;
}

Project: Android

void MetadataRetrieverClient::disconnect()
{
    ALOGV("disconnect from pid %d", mPid);
 Mutex::Autolock lock(mLock);
    mRetriever.clear();
    mThumbnail.clear();
    mAlbumArt.clear();
 IPCThreadState::self()->flushCommands();
}

Project: Android

status_t MetadataRetrieverClient::dump(int fd, const Vector<String16>& /*args*/)
{
 const size_t SIZE = 256;
 char buffer[SIZE];
 String8 result;
    result.append(" MetadataRetrieverClient\n");
    snprintf(buffer, 255, "  pid(%d)\n", mPid);
    result.append(buffer);
    write(fd, result.string(), result.size());
    write(fd, "\n", 1);
 return NO_ERROR;
}

Project: Android

sp<IMemory> MetadataRetrieverClient::extractAlbumArt()
{
    ALOGV("extractAlbumArt");
 Mutex::Autolock lock(mLock);
    mAlbumArt.clear();
 if (mRetriever == NULL) {
        ALOGE("retriever is not initialized");
 return NULL;
 }
 MediaAlbumArt *albumArt = mRetriever->extractAlbumArt();
 if (albumArt == NULL) {
        ALOGE("failed to extract an album art");
 return NULL;
 }
 size_t size = sizeof(MediaAlbumArt) + albumArt->size();
    sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
 if (heap == NULL) {
        ALOGE("failed to create MemoryDealer object");
 delete albumArt;
 return NULL;
 }
    mAlbumArt = new MemoryBase(heap, 0, size);
 if (mAlbumArt == NULL) {
        ALOGE("not enough memory for MediaAlbumArt size=%u", size);
 delete albumArt;
 return NULL;
 }
 MediaAlbumArt::init((MediaAlbumArt *) mAlbumArt->pointer(),
                        albumArt->size(), albumArt->data());
 delete albumArt; // We've taken our copy.
 return mAlbumArt;
}

Project: Android

const char* MetadataRetrieverClient::extractMetadata(int keyCode)
{
    ALOGV("extractMetadata");
 Mutex::Autolock lock(mLock);
 if (mRetriever == NULL) {
        ALOGE("retriever is not initialized");
 return NULL;
 }
 return mRetriever->extractMetadata(keyCode);
}

Project: Android

status_t MetadataRetrieverClient::setDataSource(
 const sp<IMediaHTTPService> &httpService,
 const char *url,
 const KeyedVector<String8, String8> *headers)
{
    ALOGV("setDataSource(%s)", url);
 Mutex::Autolock lock(mLock);
 if (url == NULL) {
 return UNKNOWN_ERROR;
 }

    player_type playerType =
 MediaPlayerFactory::getPlayerType(NULL /* client */, url);
    ALOGV("player type = %d", playerType);
    sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
 if (p == NULL) return NO_INIT;
 status_t ret = p->setDataSource(httpService, url, headers);
 if (ret == NO_ERROR) mRetriever = p;
 return ret;
}

Project: Android

status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t length)
{
    ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
 Mutex::Autolock lock(mLock);
 struct stat sb;
 int ret = fstat(fd, &sb);
 if (ret != 0) {
        ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
 return BAD_VALUE;
 }
    ALOGV("st_dev  = %llu", static_cast<uint64_t>(sb.st_dev));
    ALOGV("st_mode = %u", sb.st_mode);
    ALOGV("st_uid  = %lu", static_cast<unsigned long>(sb.st_uid));
    ALOGV("st_gid  = %lu", static_cast<unsigned long>(sb.st_gid));
    ALOGV("st_size = %llu", sb.st_size);

 if (offset >= sb.st_size) {
        ALOGE("offset (%lld) bigger than file size (%llu)", offset, sb.st_size);
 ::close(fd);
 return BAD_VALUE;
 }
 if (offset + length > sb.st_size) {
        length = sb.st_size - offset;
        ALOGV("calculated length = %lld", length);
 }

    player_type playerType =
 MediaPlayerFactory::getPlayerType(NULL /* client */,
                                          fd,
                                          offset,
                                          length);
    ALOGV("player type = %d", playerType);
    sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
 if (p == NULL) {
 ::close(fd);
 return NO_INIT;
 }
 status_t status = p->setDataSource(fd, offset, length);
 if (status == NO_ERROR) mRetriever = p;
 ::close(fd);
 return status;
}

Project: Android

status_t MetadataRetrieverClient::setDataSource(
 const sp<IDataSource>& source)
{
    ALOGV("setDataSource(IDataSource)");
 Mutex::Autolock lock(mLock);

    sp<DataSource> dataSource = DataSource::CreateFromIDataSource(source);
    player_type playerType =
 MediaPlayerFactory::getPlayerType(NULL /* client */, dataSource);
    ALOGV("player type = %d", playerType);
    sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
 if (p == NULL) return NO_INIT;
 status_t ret = p->setDataSource(dataSource);
 if (ret == NO_ERROR) mRetriever = p;
 return ret;
}

Project: Android

MetadataRetrieverClient::~MetadataRetrieverClient()
{
    ALOGV("MetadataRetrieverClient destructor");
    disconnect();
}