sp<IMemoryHeap> BpMemory::getMemory(ssize_t* offset, size_t* size) const
{
 if (mHeap == 0) {
 Parcel data, reply;
        data.writeInterfaceToken(IMemory::getInterfaceDescriptor());
 if (remote()->transact(GET_MEMORY, data, &reply) == NO_ERROR) {
            sp<IBinder> heap = reply.readStrongBinder();
 ssize_t o = reply.readInt32();
 size_t s = reply.readInt32();

             if (heap != 0) {
                 mHeap = interface_cast<IMemoryHeap>(heap);
                 if (mHeap != 0) {
                    size_t heapSize = mHeap->getSize();
                    if (s <= heapSize
                            && o >= 0
                            && (static_cast<size_t>(o) <= heapSize - s)) {
                        mOffset = o;
                        mSize = s;
                    } else {
                        // Hm.
                        android_errorWriteWithInfoLog(0x534e4554,
                            "26877992", -1, NULL, 0);
                        mOffset = 0;
                        mSize = 0;
                    }
                 }
             }
         }
     }
     if (offset) *offset = mOffset;
     if (size) *size = mSize;
    return (mSize > 0) ? mHeap : 0;
 }


static int vol_prc_lib_release(effect_handle_t handle)
{

     struct listnode *node, *temp_node_next;
     vol_listener_context_t *context = NULL;
     vol_listener_context_t *recv_contex = (vol_listener_context_t *)handle;
    int status = -1;
     bool recompute_flag = false;
     int active_stream_count = 0;
     ALOGV("%s context %p", __func__, handle);
     pthread_mutex_lock(&vol_listner_init_lock);

     list_for_each_safe(node, temp_node_next, &vol_effect_list) {
         context = node_to_item(node, struct vol_listener_context_s, effect_list_node);
        if ((memcmp(&(context->desc->uuid), &(recv_contex->desc->uuid), sizeof(effect_uuid_t)) == 0)
            && (context->session_id == recv_contex->session_id)
            && (context->stream_type == recv_contex->stream_type)) {
             ALOGV("--- Found something to remove ---");
            list_remove(&context->effect_list_node);
             PRINT_STREAM_TYPE(context->stream_type);
             if (context->dev_id && AUDIO_DEVICE_OUT_SPEAKER) {
                 recompute_flag = true;
 }
            free(context);
            status = 0;
 } else {
 ++active_stream_count;
 }
 }

     if (status != 0) {
         ALOGE("something wrong ... <<<--- Found NOTHING to remove ... ???? --->>>>>");
     }

 if (active_stream_count == 0) {
        current_gain_dep_cal_level = -1;
        current_vol = 0.0;
 }

 if (recompute_flag) {
        check_and_set_gain_dep_cal();
 }

 if (dumping_enabled) {
        dump_list_l();
 }
    pthread_mutex_unlock(&vol_listner_init_lock);
 return status;
}

post_proc/volume_listener.c in mediaserver in Android 6.x before 2016-04-01 mishandles deleted effect context, which allows remote attackers to execute arbitrary code or cause a denial of service (memory corruption) via a crafted media file, aka internal bug 25753245.


static int vol_prc_lib_release(effect_handle_t handle)
{

     struct listnode *node, *temp_node_next;
     vol_listener_context_t *context = NULL;
     vol_listener_context_t *recv_contex = (vol_listener_context_t *)handle;
    int status = -EINVAL;
     bool recompute_flag = false;
     int active_stream_count = 0;
    uint32_t session_id;
    uint32_t stream_type;
    effect_uuid_t uuid;

     ALOGV("%s context %p", __func__, handle);

    if (recv_contex == NULL) {
        return status;
    }
     pthread_mutex_lock(&vol_listner_init_lock);
    session_id = recv_contex->session_id;
    stream_type = recv_contex->stream_type;
    uuid = recv_contex->desc->uuid;

     list_for_each_safe(node, temp_node_next, &vol_effect_list) {
         context = node_to_item(node, struct vol_listener_context_s, effect_list_node);
        if ((memcmp(&(context->desc->uuid), &uuid, sizeof(effect_uuid_t)) == 0)
            && (context->session_id == session_id)
            && (context->stream_type == stream_type)) {
             ALOGV("--- Found something to remove ---");
            list_remove(node);
             PRINT_STREAM_TYPE(context->stream_type);
             if (context->dev_id && AUDIO_DEVICE_OUT_SPEAKER) {
                 recompute_flag = true;
 }
            free(context);
            status = 0;
 } else {
 ++active_stream_count;
 }
 }

     if (status != 0) {
         ALOGE("something wrong ... <<<--- Found NOTHING to remove ... ???? --->>>>>");
        pthread_mutex_unlock(&vol_listner_init_lock);
        return status;
     }

 if (active_stream_count == 0) {
        current_gain_dep_cal_level = -1;
        current_vol = 0.0;
 }

 if (recompute_flag) {
        check_and_set_gain_dep_cal();
 }

 if (dumping_enabled) {
        dump_list_l();
 }
    pthread_mutex_unlock(&vol_listner_init_lock);
 return status;
}


status_t BnGraphicBufferProducer::onTransact(
 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
 switch(code) {
 case REQUEST_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
 int bufferIdx   = data.readInt32();
            sp<GraphicBuffer> buffer;
 int result = requestBuffer(bufferIdx, &buffer);
            reply->writeInt32(buffer != 0);
 if (buffer != 0) {
                reply->write(*buffer);
 }
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case SET_BUFFER_COUNT: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
 int bufferCount = data.readInt32();
 int result = setBufferCount(bufferCount);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case DEQUEUE_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
 bool async      = data.readInt32();
 uint32_t w      = data.readInt32();
 uint32_t h      = data.readInt32();
 uint32_t format = data.readInt32();
 uint32_t usage  = data.readInt32();
 int buf = 0;
            sp<Fence> fence;
 int result = dequeueBuffer(&buf, &fence, async, w, h, format, usage);
            reply->writeInt32(buf);
            reply->writeInt32(fence != NULL);
 if (fence != NULL) {
                reply->write(*fence);
 }
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case QUEUE_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
 int buf = data.readInt32();
 QueueBufferInput input(data);

             QueueBufferOutput* const output =
                     reinterpret_cast<QueueBufferOutput *>(
                             reply->writeInplace(sizeof(QueueBufferOutput)));
             status_t result = queueBuffer(buf, input, output);
             reply->writeInt32(result);
             return NO_ERROR;
 } break;
 case CANCEL_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
 int buf = data.readInt32();
            sp<Fence> fence = new Fence();
            data.read(*fence.get());
            cancelBuffer(buf, fence);
 return NO_ERROR;
 } break;
 case QUERY: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
 int value = 0;
 int what = data.readInt32();
 int res = query(what, &value);
            reply->writeInt32(value);
            reply->writeInt32(res);
 return NO_ERROR;
 } break;
 case CONNECT: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
            sp<IBinder> token = data.readStrongBinder();
 int api = data.readInt32();
 bool producerControlledByApp = data.readInt32();
 QueueBufferOutput* const output =
 reinterpret_cast<QueueBufferOutput *>(
                            reply->writeInplace(sizeof(QueueBufferOutput)));
 status_t res = connect(token, api, producerControlledByApp, output);
            reply->writeInt32(res);
 return NO_ERROR;
 } break;
 case DISCONNECT: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
 int api = data.readInt32();
 status_t res = disconnect(api);
            reply->writeInt32(res);
 return NO_ERROR;
 } break;
 }
 return BBinder::onTransact(code, data, reply, flags);
}

The BnGraphicBufferProducer::onTransact function in libs/gui/IGraphicBufferConsumer.cpp in mediaserver in Android 4.x before 4.4.4, 5.x before 5.1.1 LMY49H, and 6.x before 2016-03-01 does not initialize a certain output data structure, which allows attackers to obtain sensitive information, and consequently bypass an unspecified protection mechanism, by triggering a QUEUE_BUFFER action, as demonstrated by obtaining Signature or SignatureOrSystem access, aka internal bug 26338109.


status_t BnGraphicBufferProducer::onTransact(
 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
 switch(code) {
 case REQUEST_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
 int bufferIdx   = data.readInt32();
            sp<GraphicBuffer> buffer;
 int result = requestBuffer(bufferIdx, &buffer);
            reply->writeInt32(buffer != 0);
 if (buffer != 0) {
                reply->write(*buffer);
 }
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case SET_BUFFER_COUNT: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
 int bufferCount = data.readInt32();
 int result = setBufferCount(bufferCount);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case DEQUEUE_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
 bool async      = data.readInt32();
 uint32_t w      = data.readInt32();
 uint32_t h      = data.readInt32();
 uint32_t format = data.readInt32();
 uint32_t usage  = data.readInt32();
 int buf = 0;
            sp<Fence> fence;
 int result = dequeueBuffer(&buf, &fence, async, w, h, format, usage);
            reply->writeInt32(buf);
            reply->writeInt32(fence != NULL);
 if (fence != NULL) {
                reply->write(*fence);
 }
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case QUEUE_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
 int buf = data.readInt32();
 QueueBufferInput input(data);

             QueueBufferOutput* const output =
                     reinterpret_cast<QueueBufferOutput *>(
                             reply->writeInplace(sizeof(QueueBufferOutput)));
            memset(output, 0, sizeof(QueueBufferOutput));
             status_t result = queueBuffer(buf, input, output);
             reply->writeInt32(result);
             return NO_ERROR;
 } break;
 case CANCEL_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
 int buf = data.readInt32();
            sp<Fence> fence = new Fence();
            data.read(*fence.get());
            cancelBuffer(buf, fence);
 return NO_ERROR;
 } break;
 case QUERY: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
 int value = 0;
 int what = data.readInt32();
 int res = query(what, &value);
            reply->writeInt32(value);
            reply->writeInt32(res);
 return NO_ERROR;
 } break;
 case CONNECT: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
            sp<IBinder> token = data.readStrongBinder();
 int api = data.readInt32();
 bool producerControlledByApp = data.readInt32();
 QueueBufferOutput* const output =
 reinterpret_cast<QueueBufferOutput *>(
                            reply->writeInplace(sizeof(QueueBufferOutput)));
 status_t res = connect(token, api, producerControlledByApp, output);
            reply->writeInt32(res);
 return NO_ERROR;
 } break;
 case DISCONNECT: {
            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
 int api = data.readInt32();
 status_t res = disconnect(api);
            reply->writeInt32(res);
 return NO_ERROR;
 } break;
 }
 return BBinder::onTransact(code, data, reply, flags);
}


status_t BnGraphicBufferConsumer::onTransact(
 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
 switch(code) {
 case ACQUIRE_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 BufferItem item;
 int64_t presentWhen = data.readInt64();
 status_t result = acquireBuffer(&item, presentWhen);
 status_t err = reply->write(item);
 if (err) return err;
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case DETACH_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 int slot = data.readInt32();
 int result = detachBuffer(slot);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case ATTACH_BUFFER: {

             CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
             sp<GraphicBuffer> buffer = new GraphicBuffer();
             data.read(*buffer.get());
            int slot;
             int result = attachBuffer(&slot, buffer);
             reply->writeInt32(slot);
             reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case RELEASE_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 int buf = data.readInt32();
 uint64_t frameNumber = data.readInt64();
            sp<Fence> releaseFence = new Fence();
 status_t err = data.read(*releaseFence);
 if (err) return err;
 status_t result = releaseBuffer(buf, frameNumber,
                    EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case CONSUMER_CONNECT: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
            sp<IConsumerListener> consumer = IConsumerListener::asInterface( data.readStrongBinder() );
 bool controlledByApp = data.readInt32();
 status_t result = consumerConnect(consumer, controlledByApp);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case CONSUMER_DISCONNECT: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 status_t result = consumerDisconnect();
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case GET_RELEASED_BUFFERS: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 uint64_t slotMask;
 status_t result = getReleasedBuffers(&slotMask);
            reply->writeInt64(slotMask);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case SET_DEFAULT_BUFFER_SIZE: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 uint32_t w = data.readInt32();
 uint32_t h = data.readInt32();
 status_t result = setDefaultBufferSize(w, h);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case SET_DEFAULT_MAX_BUFFER_COUNT: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 uint32_t bufferCount = data.readInt32();
 status_t result = setDefaultMaxBufferCount(bufferCount);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case DISABLE_ASYNC_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 status_t result = disableAsyncBuffer();
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case SET_MAX_ACQUIRED_BUFFER_COUNT: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 uint32_t maxAcquiredBuffers = data.readInt32();
 status_t result = setMaxAcquiredBufferCount(maxAcquiredBuffers);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case SET_CONSUMER_NAME: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
            setConsumerName( data.readString8() );
 return NO_ERROR;
 } break;
 case SET_DEFAULT_BUFFER_FORMAT: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 uint32_t defaultFormat = data.readInt32();
 status_t result = setDefaultBufferFormat(defaultFormat);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case SET_CONSUMER_USAGE_BITS: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 uint32_t usage = data.readInt32();
 status_t result = setConsumerUsageBits(usage);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case SET_TRANSFORM_HINT: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 uint32_t hint = data.readInt32();
 status_t result = setTransformHint(hint);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case DUMP: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 String8 result = data.readString8();
 String8 prefix = data.readString8();
 static_cast<IGraphicBufferConsumer*>(this)->dump(result, prefix);
            reply->writeString8(result);
 return NO_ERROR;
 }
 }
 return BBinder::onTransact(code, data, reply, flags);
}

The BnGraphicBufferConsumer::onTransact function in libs/gui/IGraphicBufferConsumer.cpp in mediaserver in Android 5.x before 5.1.1 LMY49H and 6.x before 2016-03-01 does not initialize a certain slot variable, which allows attackers to obtain sensitive information, and consequently bypass an unspecified protection mechanism, by triggering an ATTACH_BUFFER action, as demonstrated by obtaining Signature or SignatureOrSystem access, aka internal bug 26338113.


status_t BnGraphicBufferConsumer::onTransact(
 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
 switch(code) {
 case ACQUIRE_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 BufferItem item;
 int64_t presentWhen = data.readInt64();
 status_t result = acquireBuffer(&item, presentWhen);
 status_t err = reply->write(item);
 if (err) return err;
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case DETACH_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 int slot = data.readInt32();
 int result = detachBuffer(slot);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case ATTACH_BUFFER: {

             CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
             sp<GraphicBuffer> buffer = new GraphicBuffer();
             data.read(*buffer.get());
            int slot = -1;
             int result = attachBuffer(&slot, buffer);
             reply->writeInt32(slot);
             reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case RELEASE_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 int buf = data.readInt32();
 uint64_t frameNumber = data.readInt64();
            sp<Fence> releaseFence = new Fence();
 status_t err = data.read(*releaseFence);
 if (err) return err;
 status_t result = releaseBuffer(buf, frameNumber,
                    EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, releaseFence);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case CONSUMER_CONNECT: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
            sp<IConsumerListener> consumer = IConsumerListener::asInterface( data.readStrongBinder() );
 bool controlledByApp = data.readInt32();
 status_t result = consumerConnect(consumer, controlledByApp);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case CONSUMER_DISCONNECT: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 status_t result = consumerDisconnect();
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case GET_RELEASED_BUFFERS: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 uint64_t slotMask;
 status_t result = getReleasedBuffers(&slotMask);
            reply->writeInt64(slotMask);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case SET_DEFAULT_BUFFER_SIZE: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 uint32_t w = data.readInt32();
 uint32_t h = data.readInt32();
 status_t result = setDefaultBufferSize(w, h);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case SET_DEFAULT_MAX_BUFFER_COUNT: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 uint32_t bufferCount = data.readInt32();
 status_t result = setDefaultMaxBufferCount(bufferCount);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case DISABLE_ASYNC_BUFFER: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 status_t result = disableAsyncBuffer();
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case SET_MAX_ACQUIRED_BUFFER_COUNT: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 uint32_t maxAcquiredBuffers = data.readInt32();
 status_t result = setMaxAcquiredBufferCount(maxAcquiredBuffers);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case SET_CONSUMER_NAME: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
            setConsumerName( data.readString8() );
 return NO_ERROR;
 } break;
 case SET_DEFAULT_BUFFER_FORMAT: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 uint32_t defaultFormat = data.readInt32();
 status_t result = setDefaultBufferFormat(defaultFormat);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case SET_CONSUMER_USAGE_BITS: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 uint32_t usage = data.readInt32();
 status_t result = setConsumerUsageBits(usage);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case SET_TRANSFORM_HINT: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 uint32_t hint = data.readInt32();
 status_t result = setTransformHint(hint);
            reply->writeInt32(result);
 return NO_ERROR;
 } break;
 case DUMP: {
            CHECK_INTERFACE(IGraphicBufferConsumer, data, reply);
 String8 result = data.readString8();
 String8 prefix = data.readString8();
 static_cast<IGraphicBufferConsumer*>(this)->dump(result, prefix);
            reply->writeString8(result);
 return NO_ERROR;
 }
 }
 return BBinder::onTransact(code, data, reply, flags);
}


status_t CameraService::dump(int fd, const Vector<String16>& args) {
 String8 result;
 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
        result.appendFormat("Permission Denial: "
 "can't dump CameraService from pid=%d, uid=%d\n",
                getCallingPid(),
                getCallingUid());
        write(fd, result.string(), result.size());
 } else {
 bool locked = tryLock(mServiceLock);
 if (!locked) {
            result.append("CameraService may be deadlocked\n");
            write(fd, result.string(), result.size());
 }

 bool hasClient = false;
 if (!mModule) {
            result = String8::format("No camera module available!\n");
            write(fd, result.string(), result.size());
 return NO_ERROR;
 }

        result = String8::format("Camera module HAL API version: 0x%x\n",
                mModule->common.hal_api_version);
        result.appendFormat("Camera module API version: 0x%x\n",
                mModule->common.module_api_version);
        result.appendFormat("Camera module name: %s\n",
                mModule->common.name);
        result.appendFormat("Camera module author: %s\n",
                mModule->common.author);
        result.appendFormat("Number of camera devices: %d\n\n", mNumberOfCameras);
        write(fd, result.string(), result.size());
 for (int i = 0; i < mNumberOfCameras; i++) {
            result = String8::format("Camera %d static information:\n", i);
            camera_info info;

 status_t rc = mModule->get_camera_info(i, &info);
 if (rc != OK) {
                result.appendFormat("  Error reading static information!\n");
                write(fd, result.string(), result.size());
 } else {
                result.appendFormat("  Facing: %s\n",
                        info.facing == CAMERA_FACING_BACK ? "BACK" : "FRONT");
                result.appendFormat("  Orientation: %d\n", info.orientation);
 int deviceVersion;
 if (mModule->common.module_api_version <
                        CAMERA_MODULE_API_VERSION_2_0) {
                    deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
 } else {
                    deviceVersion = info.device_version;
 }
                result.appendFormat("  Device version: 0x%x\n", deviceVersion);
 if (deviceVersion >= CAMERA_DEVICE_API_VERSION_2_0) {
                    result.appendFormat("  Device static metadata:\n");
                    write(fd, result.string(), result.size());
                    dump_indented_camera_metadata(info.static_camera_characteristics,
                            fd, 2, 4);
 } else {
                    write(fd, result.string(), result.size());
 }
 }

            sp<BasicClient> client = mClient[i].promote();
 if (client == 0) {
                result = String8::format("  Device is closed, no client instance\n");
                write(fd, result.string(), result.size());
 continue;
 }

             hasClient = true;
             result = String8::format("  Device is open. Client instance dump:\n");
             write(fd, result.string(), result.size());
            client->dump(fd, args);
         }
         if (!hasClient) {
             result = String8::format("\nNo active camera clients yet.\n");
            write(fd, result.string(), result.size());
 }

 if (locked) mServiceLock.unlock();

        write(fd, "\n", 1);
        camera3::CameraTraces::dump(fd, args);

 int n = args.size();
 for (int i = 0; i + 1 < n; i++) {
 String16 verboseOption("-v");
 if (args[i] == verboseOption) {
 String8 levelStr(args[i+1]);
 int level = atoi(levelStr.string());
                result = String8::format("\nSetting log level to %d.\n", level);
                setLogLevel(level);
                write(fd, result.string(), result.size());
 }
 }

 }
 return NO_ERROR;
}

libcameraservice in mediaserver in Android 4.x before 4.4.4, 5.x before 5.1.1 LMY49H, and 6.x before 2016-03-01 does not require use of the ICameraService::dump method for a camera service dump, which allows attackers to gain privileges via a crafted application that directly dumps, as demonstrated by obtaining Signature or SignatureOrSystem access, aka internal bug 26265403.


status_t CameraService::dump(int fd, const Vector<String16>& args) {
 String8 result;
 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
        result.appendFormat("Permission Denial: "
 "can't dump CameraService from pid=%d, uid=%d\n",
                getCallingPid(),
                getCallingUid());
        write(fd, result.string(), result.size());
 } else {
 bool locked = tryLock(mServiceLock);
 if (!locked) {
            result.append("CameraService may be deadlocked\n");
            write(fd, result.string(), result.size());
 }

 bool hasClient = false;
 if (!mModule) {
            result = String8::format("No camera module available!\n");
            write(fd, result.string(), result.size());
 return NO_ERROR;
 }

        result = String8::format("Camera module HAL API version: 0x%x\n",
                mModule->common.hal_api_version);
        result.appendFormat("Camera module API version: 0x%x\n",
                mModule->common.module_api_version);
        result.appendFormat("Camera module name: %s\n",
                mModule->common.name);
        result.appendFormat("Camera module author: %s\n",
                mModule->common.author);
        result.appendFormat("Number of camera devices: %d\n\n", mNumberOfCameras);
        write(fd, result.string(), result.size());
 for (int i = 0; i < mNumberOfCameras; i++) {
            result = String8::format("Camera %d static information:\n", i);
            camera_info info;

 status_t rc = mModule->get_camera_info(i, &info);
 if (rc != OK) {
                result.appendFormat("  Error reading static information!\n");
                write(fd, result.string(), result.size());
 } else {
                result.appendFormat("  Facing: %s\n",
                        info.facing == CAMERA_FACING_BACK ? "BACK" : "FRONT");
                result.appendFormat("  Orientation: %d\n", info.orientation);
 int deviceVersion;
 if (mModule->common.module_api_version <
                        CAMERA_MODULE_API_VERSION_2_0) {
                    deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
 } else {
                    deviceVersion = info.device_version;
 }
                result.appendFormat("  Device version: 0x%x\n", deviceVersion);
 if (deviceVersion >= CAMERA_DEVICE_API_VERSION_2_0) {
                    result.appendFormat("  Device static metadata:\n");
                    write(fd, result.string(), result.size());
                    dump_indented_camera_metadata(info.static_camera_characteristics,
                            fd, 2, 4);
 } else {
                    write(fd, result.string(), result.size());
 }
 }

            sp<BasicClient> client = mClient[i].promote();
 if (client == 0) {
                result = String8::format("  Device is closed, no client instance\n");
                write(fd, result.string(), result.size());
 continue;
 }

             hasClient = true;
             result = String8::format("  Device is open. Client instance dump:\n");
             write(fd, result.string(), result.size());
            client->dumpClient(fd, args);
         }
         if (!hasClient) {
             result = String8::format("\nNo active camera clients yet.\n");
            write(fd, result.string(), result.size());
 }

 if (locked) mServiceLock.unlock();

        write(fd, "\n", 1);
        camera3::CameraTraces::dump(fd, args);

 int n = args.size();
 for (int i = 0; i + 1 < n; i++) {
 String16 verboseOption("-v");
 if (args[i] == verboseOption) {
 String8 levelStr(args[i+1]);
 int level = atoi(levelStr.string());
                result = String8::format("\nSetting log level to %d.\n", level);
                setLogLevel(level);
                write(fd, result.string(), result.size());
 }
 }

 }
 return NO_ERROR;
}


 status_t Camera2Client::dump(int fd, const Vector<String16>& args) {
     String8 result;
     result.appendFormat("Client2[%d] (%p) Client: %s PID: %d, dump:\n",
             mCameraId,
            getRemoteCallback()->asBinder().get(),
 String8(mClientPackageName).string(),
            mClientPid);
    result.append("  State: ");
#define CASE_APPEND_ENUM(x) case x: result.append(#x "\n"); break;

 const Parameters& p = mParameters.unsafeAccess();

    result.append(Parameters::getStateName(p.state));

    result.append("\n  Current parameters:\n");
    result.appendFormat("    Preview size: %d x %d\n",
            p.previewWidth, p.previewHeight);
    result.appendFormat("    Preview FPS range: %d - %d\n",
            p.previewFpsRange[0], p.previewFpsRange[1]);
    result.appendFormat("    Preview HAL pixel format: 0x%x\n",
            p.previewFormat);
    result.appendFormat("    Preview transform: %x\n",
            p.previewTransform);
    result.appendFormat("    Picture size: %d x %d\n",
            p.pictureWidth, p.pictureHeight);
    result.appendFormat("    Jpeg thumbnail size: %d x %d\n",
            p.jpegThumbSize[0], p.jpegThumbSize[1]);
    result.appendFormat("    Jpeg quality: %d, thumbnail quality: %d\n",
            p.jpegQuality, p.jpegThumbQuality);
    result.appendFormat("    Jpeg rotation: %d\n", p.jpegRotation);
    result.appendFormat("    GPS tags %s\n",
            p.gpsEnabled ? "enabled" : "disabled");
 if (p.gpsEnabled) {
        result.appendFormat("    GPS lat x long x alt: %f x %f x %f\n",
                p.gpsCoordinates[0], p.gpsCoordinates[1],
                p.gpsCoordinates[2]);
        result.appendFormat("    GPS timestamp: %lld\n",
                p.gpsTimestamp);
        result.appendFormat("    GPS processing method: %s\n",
                p.gpsProcessingMethod.string());
 }

    result.append("    White balance mode: ");
 switch (p.wbMode) {
        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_MODE_AUTO)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_MODE_INCANDESCENT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_MODE_FLUORESCENT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_MODE_WARM_FLUORESCENT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_MODE_DAYLIGHT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_MODE_CLOUDY_DAYLIGHT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_MODE_TWILIGHT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_MODE_SHADE)
 default: result.append("UNKNOWN\n");
 }

    result.append("    Effect mode: ");
 switch (p.effectMode) {
        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MODE_OFF)
        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MODE_MONO)
        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MODE_NEGATIVE)
        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MODE_SOLARIZE)
        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MODE_SEPIA)
        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MODE_POSTERIZE)
        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MODE_WHITEBOARD)
        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MODE_BLACKBOARD)
        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MODE_AQUA)
 default: result.append("UNKNOWN\n");
 }

    result.append("    Antibanding mode: ");
 switch (p.antibandingMode) {
        CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ)
 default: result.append("UNKNOWN\n");
 }

    result.append("    Scene mode: ");
 switch (p.sceneMode) {
 case ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED:
            result.append("AUTO\n"); break;
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_ACTION)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_PORTRAIT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_LANDSCAPE)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_NIGHT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_NIGHT_PORTRAIT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_THEATRE)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_BEACH)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_SNOW)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_SUNSET)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_STEADYPHOTO)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_FIREWORKS)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_SPORTS)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_PARTY)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_BARCODE)
 default: result.append("UNKNOWN\n");
 }

    result.append("    Flash mode: ");
 switch (p.flashMode) {
        CASE_APPEND_ENUM(Parameters::FLASH_MODE_OFF)
        CASE_APPEND_ENUM(Parameters::FLASH_MODE_AUTO)
        CASE_APPEND_ENUM(Parameters::FLASH_MODE_ON)
        CASE_APPEND_ENUM(Parameters::FLASH_MODE_TORCH)
        CASE_APPEND_ENUM(Parameters::FLASH_MODE_RED_EYE)
        CASE_APPEND_ENUM(Parameters::FLASH_MODE_INVALID)
 default: result.append("UNKNOWN\n");
 }

    result.append("    Focus mode: ");
 switch (p.focusMode) {
        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_AUTO)
        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_MACRO)
        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_CONTINUOUS_VIDEO)
        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_CONTINUOUS_PICTURE)
        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_EDOF)
        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_INFINITY)
        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_FIXED)
        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_INVALID)
 default: result.append("UNKNOWN\n");
 }

    result.append("   Focus state: ");
 switch (p.focusState) {
        CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_INACTIVE)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_PASSIVE_UNFOCUSED)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED)
 default: result.append("UNKNOWN\n");
 }

    result.append("    Focusing areas:\n");
 for (size_t i = 0; i < p.focusingAreas.size(); i++) {
        result.appendFormat("      [ (%d, %d, %d, %d), weight %d ]\n",
                p.focusingAreas[i].left,
                p.focusingAreas[i].top,
                p.focusingAreas[i].right,
                p.focusingAreas[i].bottom,
                p.focusingAreas[i].weight);
 }

    result.appendFormat("    Exposure compensation index: %d\n",
            p.exposureCompensation);

    result.appendFormat("    AE lock %s, AWB lock %s\n",
            p.autoExposureLock ? "enabled" : "disabled",
            p.autoWhiteBalanceLock ? "enabled" : "disabled" );

    result.appendFormat("    Metering areas:\n");
 for (size_t i = 0; i < p.meteringAreas.size(); i++) {
        result.appendFormat("      [ (%d, %d, %d, %d), weight %d ]\n",
                p.meteringAreas[i].left,
                p.meteringAreas[i].top,
                p.meteringAreas[i].right,
                p.meteringAreas[i].bottom,
                p.meteringAreas[i].weight);
 }

    result.appendFormat("    Zoom index: %d\n", p.zoom);
    result.appendFormat("    Video size: %d x %d\n", p.videoWidth,
            p.videoHeight);

    result.appendFormat("    Recording hint is %s\n",
            p.recordingHint ? "set" : "not set");

    result.appendFormat("    Video stabilization is %s\n",
            p.videoStabilization ? "enabled" : "disabled");

    result.appendFormat("    Selected still capture FPS range: %d - %d\n",
            p.fastInfo.bestStillCaptureFpsRange[0],
            p.fastInfo.bestStillCaptureFpsRange[1]);

    result.append("  Current streams:\n");
    result.appendFormat("    Preview stream ID: %d\n",
            getPreviewStreamId());
    result.appendFormat("    Capture stream ID: %d\n",
            getCaptureStreamId());
    result.appendFormat("    Recording stream ID: %d\n",
            getRecordingStreamId());

    result.append("  Quirks for this camera:\n");
 bool haveQuirk = false;
 if (p.quirks.triggerAfWithAuto) {
        result.appendFormat("    triggerAfWithAuto\n");
        haveQuirk = true;
 }
 if (p.quirks.useZslFormat) {
        result.appendFormat("    useZslFormat\n");
        haveQuirk = true;
 }
 if (p.quirks.meteringCropRegion) {
        result.appendFormat("    meteringCropRegion\n");
        haveQuirk = true;
 }
 if (p.quirks.partialResults) {
        result.appendFormat("    usePartialResult\n");
        haveQuirk = true;
 }
 if (!haveQuirk) {
        result.appendFormat("    none\n");
 }

    write(fd, result.string(), result.size());

    mStreamingProcessor->dump(fd, args);

    mCaptureSequencer->dump(fd, args);

    mFrameProcessor->dump(fd, args);

    mZslProcessor->dump(fd, args);

 return dumpDevice(fd, args);
#undef CASE_APPEND_ENUM
}


 status_t Camera2Client::dump(int fd, const Vector<String16>& args) {
    return BasicClient::dump(fd, args);
}

status_t Camera2Client::dumpClient(int fd, const Vector<String16>& args) {
     String8 result;
     result.appendFormat("Client2[%d] (%p) Client: %s PID: %d, dump:\n",
             mCameraId,
            getRemoteCallback()->asBinder().get(),
 String8(mClientPackageName).string(),
            mClientPid);
    result.append("  State: ");
#define CASE_APPEND_ENUM(x) case x: result.append(#x "\n"); break;

 const Parameters& p = mParameters.unsafeAccess();

    result.append(Parameters::getStateName(p.state));

    result.append("\n  Current parameters:\n");
    result.appendFormat("    Preview size: %d x %d\n",
            p.previewWidth, p.previewHeight);
    result.appendFormat("    Preview FPS range: %d - %d\n",
            p.previewFpsRange[0], p.previewFpsRange[1]);
    result.appendFormat("    Preview HAL pixel format: 0x%x\n",
            p.previewFormat);
    result.appendFormat("    Preview transform: %x\n",
            p.previewTransform);
    result.appendFormat("    Picture size: %d x %d\n",
            p.pictureWidth, p.pictureHeight);
    result.appendFormat("    Jpeg thumbnail size: %d x %d\n",
            p.jpegThumbSize[0], p.jpegThumbSize[1]);
    result.appendFormat("    Jpeg quality: %d, thumbnail quality: %d\n",
            p.jpegQuality, p.jpegThumbQuality);
    result.appendFormat("    Jpeg rotation: %d\n", p.jpegRotation);
    result.appendFormat("    GPS tags %s\n",
            p.gpsEnabled ? "enabled" : "disabled");
 if (p.gpsEnabled) {
        result.appendFormat("    GPS lat x long x alt: %f x %f x %f\n",
                p.gpsCoordinates[0], p.gpsCoordinates[1],
                p.gpsCoordinates[2]);
        result.appendFormat("    GPS timestamp: %lld\n",
                p.gpsTimestamp);
        result.appendFormat("    GPS processing method: %s\n",
                p.gpsProcessingMethod.string());
 }

    result.append("    White balance mode: ");
 switch (p.wbMode) {
        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_MODE_AUTO)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_MODE_INCANDESCENT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_MODE_FLUORESCENT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_MODE_WARM_FLUORESCENT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_MODE_DAYLIGHT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_MODE_CLOUDY_DAYLIGHT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_MODE_TWILIGHT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_MODE_SHADE)
 default: result.append("UNKNOWN\n");
 }

    result.append("    Effect mode: ");
 switch (p.effectMode) {
        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MODE_OFF)
        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MODE_MONO)
        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MODE_NEGATIVE)
        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MODE_SOLARIZE)
        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MODE_SEPIA)
        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MODE_POSTERIZE)
        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MODE_WHITEBOARD)
        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MODE_BLACKBOARD)
        CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MODE_AQUA)
 default: result.append("UNKNOWN\n");
 }

    result.append("    Antibanding mode: ");
 switch (p.antibandingMode) {
        CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ)
 default: result.append("UNKNOWN\n");
 }

    result.append("    Scene mode: ");
 switch (p.sceneMode) {
 case ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED:
            result.append("AUTO\n"); break;
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_ACTION)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_PORTRAIT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_LANDSCAPE)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_NIGHT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_NIGHT_PORTRAIT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_THEATRE)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_BEACH)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_SNOW)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_SUNSET)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_STEADYPHOTO)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_FIREWORKS)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_SPORTS)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_PARTY)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_CANDLELIGHT)
        CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_BARCODE)
 default: result.append("UNKNOWN\n");
 }

    result.append("    Flash mode: ");
 switch (p.flashMode) {
        CASE_APPEND_ENUM(Parameters::FLASH_MODE_OFF)
        CASE_APPEND_ENUM(Parameters::FLASH_MODE_AUTO)
        CASE_APPEND_ENUM(Parameters::FLASH_MODE_ON)
        CASE_APPEND_ENUM(Parameters::FLASH_MODE_TORCH)
        CASE_APPEND_ENUM(Parameters::FLASH_MODE_RED_EYE)
        CASE_APPEND_ENUM(Parameters::FLASH_MODE_INVALID)
 default: result.append("UNKNOWN\n");
 }

    result.append("    Focus mode: ");
 switch (p.focusMode) {
        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_AUTO)
        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_MACRO)
        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_CONTINUOUS_VIDEO)
        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_CONTINUOUS_PICTURE)
        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_EDOF)
        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_INFINITY)
        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_FIXED)
        CASE_APPEND_ENUM(Parameters::FOCUS_MODE_INVALID)
 default: result.append("UNKNOWN\n");
 }

    result.append("   Focus state: ");
 switch (p.focusState) {
        CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_INACTIVE)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_PASSIVE_SCAN)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_PASSIVE_UNFOCUSED)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_ACTIVE_SCAN)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED)
        CASE_APPEND_ENUM(ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED)
 default: result.append("UNKNOWN\n");
 }

    result.append("    Focusing areas:\n");
 for (size_t i = 0; i < p.focusingAreas.size(); i++) {
        result.appendFormat("      [ (%d, %d, %d, %d), weight %d ]\n",
                p.focusingAreas[i].left,
                p.focusingAreas[i].top,
                p.focusingAreas[i].right,
                p.focusingAreas[i].bottom,
                p.focusingAreas[i].weight);
 }

    result.appendFormat("    Exposure compensation index: %d\n",
            p.exposureCompensation);

    result.appendFormat("    AE lock %s, AWB lock %s\n",
            p.autoExposureLock ? "enabled" : "disabled",
            p.autoWhiteBalanceLock ? "enabled" : "disabled" );

    result.appendFormat("    Metering areas:\n");
 for (size_t i = 0; i < p.meteringAreas.size(); i++) {
        result.appendFormat("      [ (%d, %d, %d, %d), weight %d ]\n",
                p.meteringAreas[i].left,
                p.meteringAreas[i].top,
                p.meteringAreas[i].right,
                p.meteringAreas[i].bottom,
                p.meteringAreas[i].weight);
 }

    result.appendFormat("    Zoom index: %d\n", p.zoom);
    result.appendFormat("    Video size: %d x %d\n", p.videoWidth,
            p.videoHeight);

    result.appendFormat("    Recording hint is %s\n",
            p.recordingHint ? "set" : "not set");

    result.appendFormat("    Video stabilization is %s\n",
            p.videoStabilization ? "enabled" : "disabled");

    result.appendFormat("    Selected still capture FPS range: %d - %d\n",
            p.fastInfo.bestStillCaptureFpsRange[0],
            p.fastInfo.bestStillCaptureFpsRange[1]);

    result.append("  Current streams:\n");
    result.appendFormat("    Preview stream ID: %d\n",
            getPreviewStreamId());
    result.appendFormat("    Capture stream ID: %d\n",
            getCaptureStreamId());
    result.appendFormat("    Recording stream ID: %d\n",
            getRecordingStreamId());

    result.append("  Quirks for this camera:\n");
 bool haveQuirk = false;
 if (p.quirks.triggerAfWithAuto) {
        result.appendFormat("    triggerAfWithAuto\n");
        haveQuirk = true;
 }
 if (p.quirks.useZslFormat) {
        result.appendFormat("    useZslFormat\n");
        haveQuirk = true;
 }
 if (p.quirks.meteringCropRegion) {
        result.appendFormat("    meteringCropRegion\n");
        haveQuirk = true;
 }
 if (p.quirks.partialResults) {
        result.appendFormat("    usePartialResult\n");
        haveQuirk = true;
 }
 if (!haveQuirk) {
        result.appendFormat("    none\n");
 }

    write(fd, result.string(), result.size());

    mStreamingProcessor->dump(fd, args);

    mCaptureSequencer->dump(fd, args);

    mFrameProcessor->dump(fd, args);

    mZslProcessor->dump(fd, args);

 return dumpDevice(fd, args);
#undef CASE_APPEND_ENUM
}


 status_t CameraClient::dump(int fd, const Vector<String16>& args) {
     const size_t SIZE = 256;
     char buffer[SIZE];

 size_t len = snprintf(buffer, SIZE, "Client[%d] (%p) PID: %d\n",
            mCameraId,
            getRemoteCallback()->asBinder().get(),
            mClientPid);
    len = (len > SIZE - 1) ? SIZE - 1 : len;
    write(fd, buffer, len);
 return mHardware->dump(fd, args);
}


 status_t CameraClient::dump(int fd, const Vector<String16>& args) {
    return BasicClient::dump(fd, args);
}

status_t CameraClient::dumpClient(int fd, const Vector<String16>& args) {
     const size_t SIZE = 256;
     char buffer[SIZE];

 size_t len = snprintf(buffer, SIZE, "Client[%d] (%p) PID: %d\n",
            mCameraId,
            getRemoteCallback()->asBinder().get(),
            mClientPid);
    len = (len > SIZE - 1) ? SIZE - 1 : len;
    write(fd, buffer, len);
 return mHardware->dump(fd, args);
}


 status_t CameraDeviceClient::dump(int fd, const Vector<String16>& args) {
     String8 result;
     result.appendFormat("CameraDeviceClient[%d] (%p) PID: %d, dump:\n",
             mCameraId,
            getRemoteCallback()->asBinder().get(),
            mClientPid);
    result.append("  State: ");

    mFrameProcessor->dump(fd, args);

 return dumpDevice(fd, args);
}


 status_t CameraDeviceClient::dump(int fd, const Vector<String16>& args) {
    return BasicClient::dump(fd, args);
}

status_t CameraDeviceClient::dumpClient(int fd, const Vector<String16>& args) {
     String8 result;
     result.appendFormat("CameraDeviceClient[%d] (%p) PID: %d, dump:\n",
             mCameraId,
            getRemoteCallback()->asBinder().get(),
            mClientPid);
    result.append("  State: ");

    mFrameProcessor->dump(fd, args);

 return dumpDevice(fd, args);
}


 status_t ProCamera2Client::dump(int fd, const Vector<String16>& args) {
     String8 result;
     result.appendFormat("ProCamera2Client[%d] (%p) PID: %d, dump:\n",
             mCameraId,
            getRemoteCallback()->asBinder().get(),
            mClientPid);
    result.append("  State: ");

    mFrameProcessor->dump(fd, args);

 return dumpDevice(fd, args);
}


 status_t ProCamera2Client::dump(int fd, const Vector<String16>& args) {
    return BasicClient::dump(fd, args);
}

status_t ProCamera2Client::dumpClient(int fd, const Vector<String16>& args) {
     String8 result;
     result.appendFormat("ProCamera2Client[%d] (%p) PID: %d, dump:\n",
             mCameraId,
            getRemoteCallback()->asBinder().get(),
            mClientPid);
    result.append("  State: ");

    mFrameProcessor->dump(fd, args);

 return dumpDevice(fd, args);
}


status_t MPEG4Source::fragmentedRead(
 MediaBuffer **out, const ReadOptions *options) {

    ALOGV("MPEG4Source::fragmentedRead");

    CHECK(mStarted);

 *out = NULL;

 int64_t targetSampleTimeUs = -1;

 int64_t seekTimeUs;
 ReadOptions::SeekMode mode;
 if (options && options->getSeekTo(&seekTimeUs, &mode)) {

 int numSidxEntries = mSegments.size();
 if (numSidxEntries != 0) {
 int64_t totalTime = 0;
 off64_t totalOffset = mFirstMoofOffset;
 for (int i = 0; i < numSidxEntries; i++) {
 const SidxEntry *se = &mSegments[i];
 if (totalTime + se->mDurationUs > seekTimeUs) {
 if ((mode == ReadOptions::SEEK_NEXT_SYNC) ||
 (mode == ReadOptions::SEEK_CLOSEST_SYNC &&
 (seekTimeUs - totalTime) > (totalTime + se->mDurationUs - seekTimeUs))) {
                        totalTime += se->mDurationUs;
                        totalOffset += se->mSize;
 }
 break;
 }
                totalTime += se->mDurationUs;
                totalOffset += se->mSize;
 }
        mCurrentMoofOffset = totalOffset;
        mCurrentSamples.clear();
        mCurrentSampleIndex = 0;
        parseChunk(&totalOffset);
        mCurrentTime = totalTime * mTimescale / 1000000ll;
 }

 if (mBuffer != NULL) {
            mBuffer->release();
            mBuffer = NULL;
 }

 }

 off64_t offset = 0;
 size_t size;
 uint32_t cts = 0;
 bool isSyncSample = false;
 bool newBuffer = false;
 if (mBuffer == NULL) {
        newBuffer = true;

 if (mCurrentSampleIndex >= mCurrentSamples.size()) {
 Sample lastSample = mCurrentSamples[mCurrentSamples.size() - 1];
 off64_t nextMoof = mNextMoofOffset; // lastSample.offset + lastSample.size;
            mCurrentMoofOffset = nextMoof;
            mCurrentSamples.clear();
            mCurrentSampleIndex = 0;
            parseChunk(&nextMoof);
 if (mCurrentSampleIndex >= mCurrentSamples.size()) {
 return ERROR_END_OF_STREAM;
 }
 }

 const Sample *smpl = &mCurrentSamples[mCurrentSampleIndex];
        offset = smpl->offset;
        size = smpl->size;
        cts = mCurrentTime;
        mCurrentTime += smpl->duration;
        isSyncSample = (mCurrentSampleIndex == 0); // XXX

 status_t err = mGroup->acquire_buffer(&mBuffer);

 if (err != OK) {
            CHECK(mBuffer == NULL);
            ALOGV("acquire_buffer returned %d", err);
 return err;
 }
 if (size > mBuffer->size()) {
            ALOGE("buffer too small: %zu > %zu", size, mBuffer->size());
 return ERROR_BUFFER_TOO_SMALL;
 }
 }

 const Sample *smpl = &mCurrentSamples[mCurrentSampleIndex];
 const sp<MetaData> bufmeta = mBuffer->meta_data();
    bufmeta->clear();
 if (smpl->encryptedsizes.size()) {
        bufmeta->setData(kKeyPlainSizes, 0,
                smpl->clearsizes.array(), smpl->clearsizes.size() * 4);
        bufmeta->setData(kKeyEncryptedSizes, 0,
                smpl->encryptedsizes.array(), smpl->encryptedsizes.size() * 4);
        bufmeta->setData(kKeyCryptoIV, 0, smpl->iv, 16); // use 16 or the actual size?
        bufmeta->setInt32(kKeyCryptoDefaultIVSize, mDefaultIVSize);
        bufmeta->setInt32(kKeyCryptoMode, mCryptoMode);
        bufmeta->setData(kKeyCryptoKey, 0, mCryptoKey, 16);
 }

 if (!mIsAVC || mWantsNALFragments) {
 if (newBuffer) {
 if (!isInRange((size_t)0u, mBuffer->size(), size)) {
                mBuffer->release();
                mBuffer = NULL;

                ALOGE("fragmentedRead ERROR_MALFORMED size %zu", size);
 return ERROR_MALFORMED;
 }

 ssize_t num_bytes_read =
                mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);

 if (num_bytes_read < (ssize_t)size) {
                mBuffer->release();
                mBuffer = NULL;

                ALOGE("i/o error");
 return ERROR_IO;
 }

            CHECK(mBuffer != NULL);
            mBuffer->set_range(0, size);
            mBuffer->meta_data()->setInt64(
                    kKeyTime, ((int64_t)cts * 1000000) / mTimescale);

 if (targetSampleTimeUs >= 0) {
                mBuffer->meta_data()->setInt64(
                        kKeyTargetTime, targetSampleTimeUs);
 }

 if (isSyncSample) {
                mBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
 }

 ++mCurrentSampleIndex;
 }

 if (!mIsAVC) {
 *out = mBuffer;
            mBuffer = NULL;

 return OK;
 }

        CHECK(mBuffer->range_length() >= mNALLengthSize);

 const uint8_t *src =
 (const uint8_t *)mBuffer->data() + mBuffer->range_offset();

 size_t nal_size = parseNALSize(src);
 if (mNALLengthSize > SIZE_MAX - nal_size) {
            ALOGE("b/24441553, b/24445122");
 }

 if (mBuffer->range_length() - mNALLengthSize < nal_size) {
            ALOGE("incomplete NAL unit.");

            mBuffer->release();
            mBuffer = NULL;

 return ERROR_MALFORMED;
 }

 MediaBuffer *clone = mBuffer->clone();
        CHECK(clone != NULL);
        clone->set_range(mBuffer->range_offset() + mNALLengthSize, nal_size);

        CHECK(mBuffer != NULL);
        mBuffer->set_range(
                mBuffer->range_offset() + mNALLengthSize + nal_size,
                mBuffer->range_length() - mNALLengthSize - nal_size);

 if (mBuffer->range_length() == 0) {
            mBuffer->release();
            mBuffer = NULL;
 }

 *out = clone;

 return OK;
 } else {
        ALOGV("whole NAL");
 ssize_t num_bytes_read = 0;
 int32_t drm = 0;
 bool usesDRM = (mFormat->findInt32(kKeyIsDRM, &drm) && drm != 0);
 void *data = NULL;
 bool isMalFormed = false;
 if (usesDRM) {
 if (mBuffer == NULL || !isInRange((size_t)0u, mBuffer->size(), size)) {
                isMalFormed = true;
 } else {
                data = mBuffer->data();
 }
 } else {
 int32_t max_size;
 if (mFormat == NULL
 || !mFormat->findInt32(kKeyMaxInputSize, &max_size)
 || !isInRange((size_t)0u, (size_t)max_size, size)) {
                isMalFormed = true;
 } else {
                data = mSrcBuffer;
 }
 }

 if (isMalFormed || data == NULL) {
            ALOGE("isMalFormed size %zu", size);
 if (mBuffer != NULL) {
                mBuffer->release();
                mBuffer = NULL;
 }
 return ERROR_MALFORMED;
 }
        num_bytes_read = mDataSource->readAt(offset, data, size);

 if (num_bytes_read < (ssize_t)size) {
            mBuffer->release();
            mBuffer = NULL;

            ALOGE("i/o error");
 return ERROR_IO;
 }

 if (usesDRM) {
            CHECK(mBuffer != NULL);
            mBuffer->set_range(0, size);

 } else {
 uint8_t *dstData = (uint8_t *)mBuffer->data();
 size_t srcOffset = 0;
 size_t dstOffset = 0;

 while (srcOffset < size) {
                isMalFormed = !isInRange((size_t)0u, size, srcOffset, mNALLengthSize);
 size_t nalLength = 0;
 if (!isMalFormed) {
                    nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
                    srcOffset += mNALLengthSize;
                    isMalFormed = !isInRange((size_t)0u, size, srcOffset, nalLength)
 || !isInRange((size_t)0u, mBuffer->size(), dstOffset, (size_t)4u)
 || !isInRange((size_t)0u, mBuffer->size(), dstOffset + 4, nalLength);
 }

 if (isMalFormed) {
                    ALOGE("Video is malformed; nalLength %zu", nalLength);
                    mBuffer->release();
                    mBuffer = NULL;
 return ERROR_MALFORMED;
 }

 if (nalLength == 0) {

                     continue;
                 }

                CHECK(dstOffset + 4 <= mBuffer->size());

                 dstData[dstOffset++] = 0;
                 dstData[dstOffset++] = 0;
                dstData[dstOffset++] = 0;
                dstData[dstOffset++] = 1;
                memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
                srcOffset += nalLength;
                dstOffset += nalLength;
 }
            CHECK_EQ(srcOffset, size);
            CHECK(mBuffer != NULL);
            mBuffer->set_range(0, dstOffset);
 }

        mBuffer->meta_data()->setInt64(
                kKeyTime, ((int64_t)cts * 1000000) / mTimescale);

 if (targetSampleTimeUs >= 0) {
            mBuffer->meta_data()->setInt64(
                    kKeyTargetTime, targetSampleTimeUs);
 }

 if (isSyncSample) {
            mBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
 }

 ++mCurrentSampleIndex;

 *out = mBuffer;
        mBuffer = NULL;

 return OK;
 }
}

The MPEG4Source::fragmentedRead function in MPEG4Extractor.cpp in libstagefright in mediaserver in Android 4.x before 4.4.4, 5.x before 5.1.1 LMY49H, and 6.x before 2016-03-01 allows remote attackers to execute arbitrary code or cause a denial of service (memory corruption) via a crafted media file, aka internal bug 26365349.


status_t MPEG4Source::fragmentedRead(
 MediaBuffer **out, const ReadOptions *options) {

    ALOGV("MPEG4Source::fragmentedRead");

    CHECK(mStarted);

 *out = NULL;

 int64_t targetSampleTimeUs = -1;

 int64_t seekTimeUs;
 ReadOptions::SeekMode mode;
 if (options && options->getSeekTo(&seekTimeUs, &mode)) {

 int numSidxEntries = mSegments.size();
 if (numSidxEntries != 0) {
 int64_t totalTime = 0;
 off64_t totalOffset = mFirstMoofOffset;
 for (int i = 0; i < numSidxEntries; i++) {
 const SidxEntry *se = &mSegments[i];
 if (totalTime + se->mDurationUs > seekTimeUs) {
 if ((mode == ReadOptions::SEEK_NEXT_SYNC) ||
 (mode == ReadOptions::SEEK_CLOSEST_SYNC &&
 (seekTimeUs - totalTime) > (totalTime + se->mDurationUs - seekTimeUs))) {
                        totalTime += se->mDurationUs;
                        totalOffset += se->mSize;
 }
 break;
 }
                totalTime += se->mDurationUs;
                totalOffset += se->mSize;
 }
        mCurrentMoofOffset = totalOffset;
        mCurrentSamples.clear();
        mCurrentSampleIndex = 0;
        parseChunk(&totalOffset);
        mCurrentTime = totalTime * mTimescale / 1000000ll;
 }

 if (mBuffer != NULL) {
            mBuffer->release();
            mBuffer = NULL;
 }

 }

 off64_t offset = 0;
 size_t size;
 uint32_t cts = 0;
 bool isSyncSample = false;
 bool newBuffer = false;
 if (mBuffer == NULL) {
        newBuffer = true;

 if (mCurrentSampleIndex >= mCurrentSamples.size()) {
 Sample lastSample = mCurrentSamples[mCurrentSamples.size() - 1];
 off64_t nextMoof = mNextMoofOffset; // lastSample.offset + lastSample.size;
            mCurrentMoofOffset = nextMoof;
            mCurrentSamples.clear();
            mCurrentSampleIndex = 0;
            parseChunk(&nextMoof);
 if (mCurrentSampleIndex >= mCurrentSamples.size()) {
 return ERROR_END_OF_STREAM;
 }
 }

 const Sample *smpl = &mCurrentSamples[mCurrentSampleIndex];
        offset = smpl->offset;
        size = smpl->size;
        cts = mCurrentTime;
        mCurrentTime += smpl->duration;
        isSyncSample = (mCurrentSampleIndex == 0); // XXX

 status_t err = mGroup->acquire_buffer(&mBuffer);

 if (err != OK) {
            CHECK(mBuffer == NULL);
            ALOGV("acquire_buffer returned %d", err);
 return err;
 }
 if (size > mBuffer->size()) {
            ALOGE("buffer too small: %zu > %zu", size, mBuffer->size());
 return ERROR_BUFFER_TOO_SMALL;
 }
 }

 const Sample *smpl = &mCurrentSamples[mCurrentSampleIndex];
 const sp<MetaData> bufmeta = mBuffer->meta_data();
    bufmeta->clear();
 if (smpl->encryptedsizes.size()) {
        bufmeta->setData(kKeyPlainSizes, 0,
                smpl->clearsizes.array(), smpl->clearsizes.size() * 4);
        bufmeta->setData(kKeyEncryptedSizes, 0,
                smpl->encryptedsizes.array(), smpl->encryptedsizes.size() * 4);
        bufmeta->setData(kKeyCryptoIV, 0, smpl->iv, 16); // use 16 or the actual size?
        bufmeta->setInt32(kKeyCryptoDefaultIVSize, mDefaultIVSize);
        bufmeta->setInt32(kKeyCryptoMode, mCryptoMode);
        bufmeta->setData(kKeyCryptoKey, 0, mCryptoKey, 16);
 }

 if (!mIsAVC || mWantsNALFragments) {
 if (newBuffer) {
 if (!isInRange((size_t)0u, mBuffer->size(), size)) {
                mBuffer->release();
                mBuffer = NULL;

                ALOGE("fragmentedRead ERROR_MALFORMED size %zu", size);
 return ERROR_MALFORMED;
 }

 ssize_t num_bytes_read =
                mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);

 if (num_bytes_read < (ssize_t)size) {
                mBuffer->release();
                mBuffer = NULL;

                ALOGE("i/o error");
 return ERROR_IO;
 }

            CHECK(mBuffer != NULL);
            mBuffer->set_range(0, size);
            mBuffer->meta_data()->setInt64(
                    kKeyTime, ((int64_t)cts * 1000000) / mTimescale);

 if (targetSampleTimeUs >= 0) {
                mBuffer->meta_data()->setInt64(
                        kKeyTargetTime, targetSampleTimeUs);
 }

 if (isSyncSample) {
                mBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
 }

 ++mCurrentSampleIndex;
 }

 if (!mIsAVC) {
 *out = mBuffer;
            mBuffer = NULL;

 return OK;
 }

        CHECK(mBuffer->range_length() >= mNALLengthSize);

 const uint8_t *src =
 (const uint8_t *)mBuffer->data() + mBuffer->range_offset();

 size_t nal_size = parseNALSize(src);
 if (mNALLengthSize > SIZE_MAX - nal_size) {
            ALOGE("b/24441553, b/24445122");
 }

 if (mBuffer->range_length() - mNALLengthSize < nal_size) {
            ALOGE("incomplete NAL unit.");

            mBuffer->release();
            mBuffer = NULL;

 return ERROR_MALFORMED;
 }

 MediaBuffer *clone = mBuffer->clone();
        CHECK(clone != NULL);
        clone->set_range(mBuffer->range_offset() + mNALLengthSize, nal_size);

        CHECK(mBuffer != NULL);
        mBuffer->set_range(
                mBuffer->range_offset() + mNALLengthSize + nal_size,
                mBuffer->range_length() - mNALLengthSize - nal_size);

 if (mBuffer->range_length() == 0) {
            mBuffer->release();
            mBuffer = NULL;
 }

 *out = clone;

 return OK;
 } else {
        ALOGV("whole NAL");
 ssize_t num_bytes_read = 0;
 int32_t drm = 0;
 bool usesDRM = (mFormat->findInt32(kKeyIsDRM, &drm) && drm != 0);
 void *data = NULL;
 bool isMalFormed = false;
 if (usesDRM) {
 if (mBuffer == NULL || !isInRange((size_t)0u, mBuffer->size(), size)) {
                isMalFormed = true;
 } else {
                data = mBuffer->data();
 }
 } else {
 int32_t max_size;
 if (mFormat == NULL
 || !mFormat->findInt32(kKeyMaxInputSize, &max_size)
 || !isInRange((size_t)0u, (size_t)max_size, size)) {
                isMalFormed = true;
 } else {
                data = mSrcBuffer;
 }
 }

 if (isMalFormed || data == NULL) {
            ALOGE("isMalFormed size %zu", size);
 if (mBuffer != NULL) {
                mBuffer->release();
                mBuffer = NULL;
 }
 return ERROR_MALFORMED;
 }
        num_bytes_read = mDataSource->readAt(offset, data, size);

 if (num_bytes_read < (ssize_t)size) {
            mBuffer->release();
            mBuffer = NULL;

            ALOGE("i/o error");
 return ERROR_IO;
 }

 if (usesDRM) {
            CHECK(mBuffer != NULL);
            mBuffer->set_range(0, size);

 } else {
 uint8_t *dstData = (uint8_t *)mBuffer->data();
 size_t srcOffset = 0;
 size_t dstOffset = 0;

 while (srcOffset < size) {
                isMalFormed = !isInRange((size_t)0u, size, srcOffset, mNALLengthSize);
 size_t nalLength = 0;
 if (!isMalFormed) {
                    nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
                    srcOffset += mNALLengthSize;
                    isMalFormed = !isInRange((size_t)0u, size, srcOffset, nalLength)
 || !isInRange((size_t)0u, mBuffer->size(), dstOffset, (size_t)4u)
 || !isInRange((size_t)0u, mBuffer->size(), dstOffset + 4, nalLength);
 }

 if (isMalFormed) {
                    ALOGE("Video is malformed; nalLength %zu", nalLength);
                    mBuffer->release();
                    mBuffer = NULL;
 return ERROR_MALFORMED;
 }

 if (nalLength == 0) {

                     continue;
                 }

                if (dstOffset > SIZE_MAX - 4 ||
                        dstOffset + 4 > SIZE_MAX - nalLength ||
                        dstOffset + 4 + nalLength > mBuffer->size()) {
                    ALOGE("b/26365349 : %zu %zu", dstOffset, mBuffer->size());
                    android_errorWriteLog(0x534e4554, "26365349");
                    mBuffer->release();
                    mBuffer = NULL;
                    return ERROR_MALFORMED;
                }

                 dstData[dstOffset++] = 0;
                 dstData[dstOffset++] = 0;
                dstData[dstOffset++] = 0;
                dstData[dstOffset++] = 1;
                memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
                srcOffset += nalLength;
                dstOffset += nalLength;
 }
            CHECK_EQ(srcOffset, size);
            CHECK(mBuffer != NULL);
            mBuffer->set_range(0, dstOffset);
 }

        mBuffer->meta_data()->setInt64(
                kKeyTime, ((int64_t)cts * 1000000) / mTimescale);

 if (targetSampleTimeUs >= 0) {
            mBuffer->meta_data()->setInt64(
                    kKeyTargetTime, targetSampleTimeUs);
 }

 if (isSyncSample) {
            mBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
 }

 ++mCurrentSampleIndex;

 *out = mBuffer;
        mBuffer = NULL;

 return OK;
 }
}


status_t BnCrypto::onTransact(
 uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
 switch (code) {
 case INIT_CHECK:
 {
            CHECK_INTERFACE(ICrypto, data, reply);
            reply->writeInt32(initCheck());

 return OK;
 }

 case IS_CRYPTO_SUPPORTED:
 {
            CHECK_INTERFACE(ICrypto, data, reply);
 uint8_t uuid[16];
            data.read(uuid, sizeof(uuid));
            reply->writeInt32(isCryptoSchemeSupported(uuid));

 return OK;
 }

 case CREATE_PLUGIN:
 {
            CHECK_INTERFACE(ICrypto, data, reply);

 uint8_t uuid[16];
            data.read(uuid, sizeof(uuid));

 size_t opaqueSize = data.readInt32();
 void *opaqueData = NULL;

 if (opaqueSize > 0) {
                opaqueData = malloc(opaqueSize);
                data.read(opaqueData, opaqueSize);
 }

            reply->writeInt32(createPlugin(uuid, opaqueData, opaqueSize));

 if (opaqueData != NULL) {
                free(opaqueData);
                opaqueData = NULL;
 }

 return OK;
 }

 case DESTROY_PLUGIN:
 {
            CHECK_INTERFACE(ICrypto, data, reply);
            reply->writeInt32(destroyPlugin());

 return OK;
 }

 case REQUIRES_SECURE_COMPONENT:
 {
            CHECK_INTERFACE(ICrypto, data, reply);

 const char *mime = data.readCString();
            reply->writeInt32(requiresSecureDecoderComponent(mime));

 return OK;
 }

 case DECRYPT:
 {
            CHECK_INTERFACE(ICrypto, data, reply);

 bool secure = data.readInt32() != 0;
 CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32();

 uint8_t key[16];
            data.read(key, sizeof(key));

 uint8_t iv[16];
            data.read(iv, sizeof(iv));

 size_t totalSize = data.readInt32();
            sp<IMemory> sharedBuffer =
                interface_cast<IMemory>(data.readStrongBinder());
 int32_t offset = data.readInt32();

 int32_t numSubSamples = data.readInt32();

 CryptoPlugin::SubSample *subSamples =
 new CryptoPlugin::SubSample[numSubSamples];

            data.read(
                    subSamples,
 sizeof(CryptoPlugin::SubSample) * numSubSamples);

 void *secureBufferId, *dstPtr;
 if (secure) {
                secureBufferId = reinterpret_cast<void *>(static_cast<uintptr_t>(data.readInt64()));
 } else {
                dstPtr = calloc(1, totalSize);
 }

 AString errorDetailMsg;
 ssize_t result;

 size_t sumSubsampleSizes = 0;
 bool overflow = false;
 for (int32_t i = 0; i < numSubSamples; ++i) {
 CryptoPlugin::SubSample &ss = subSamples[i];
 if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfEncryptedData) {
                    sumSubsampleSizes += ss.mNumBytesOfEncryptedData;
 } else {
                    overflow = true;
 }
 if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfClearData) {
                    sumSubsampleSizes += ss.mNumBytesOfClearData;
 } else {
                    overflow = true;
 }
 }

             if (overflow || sumSubsampleSizes != totalSize) {
                 result = -EINVAL;
            } else if (offset + totalSize > sharedBuffer->size()) {
                 result = -EINVAL;
             } else {
                 result = decrypt(
                    secure,
                    key,
                    iv,
                    mode,
                    sharedBuffer, offset,
                    subSamples, numSubSamples,
                    secure ? secureBufferId : dstPtr,
 &errorDetailMsg);
 }

            reply->writeInt32(result);

 if (isCryptoError(result)) {
                reply->writeCString(errorDetailMsg.c_str());
 }

 if (!secure) {
 if (result >= 0) {
                    CHECK_LE(result, static_cast<ssize_t>(totalSize));
                    reply->write(dstPtr, result);
 }
                free(dstPtr);
                dstPtr = NULL;
 }

 delete[] subSamples;
            subSamples = NULL;

 return OK;
 }

 case NOTIFY_RESOLUTION:
 {
            CHECK_INTERFACE(ICrypto, data, reply);

 int32_t width = data.readInt32();
 int32_t height = data.readInt32();
            notifyResolution(width, height);

 return OK;
 }

 case SET_MEDIADRM_SESSION:
 {
            CHECK_INTERFACE(IDrm, data, reply);
 Vector<uint8_t> sessionId;
            readVector(data, sessionId);
            reply->writeInt32(setMediaDrmSession(sessionId));
 return OK;
 }

 default:
 return BBinder::onTransact(code, data, reply, flags);
 }
}

Integer overflow in the BnCrypto::onTransact function in media/libmedia/ICrypto.cpp in libmediaplayerservice in Android 6.x before 2016-02-01 allows attackers to obtain sensitive information, and consequently bypass an unspecified protection mechanism, by triggering an improper size calculation, as demonstrated by obtaining Signature or SignatureOrSystem access, aka internal bug 25800375.


status_t BnCrypto::onTransact(
 uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
 switch (code) {
 case INIT_CHECK:
 {
            CHECK_INTERFACE(ICrypto, data, reply);
            reply->writeInt32(initCheck());

 return OK;
 }

 case IS_CRYPTO_SUPPORTED:
 {
            CHECK_INTERFACE(ICrypto, data, reply);
 uint8_t uuid[16];
            data.read(uuid, sizeof(uuid));
            reply->writeInt32(isCryptoSchemeSupported(uuid));

 return OK;
 }

 case CREATE_PLUGIN:
 {
            CHECK_INTERFACE(ICrypto, data, reply);

 uint8_t uuid[16];
            data.read(uuid, sizeof(uuid));

 size_t opaqueSize = data.readInt32();
 void *opaqueData = NULL;

 if (opaqueSize > 0) {
                opaqueData = malloc(opaqueSize);
                data.read(opaqueData, opaqueSize);
 }

            reply->writeInt32(createPlugin(uuid, opaqueData, opaqueSize));

 if (opaqueData != NULL) {
                free(opaqueData);
                opaqueData = NULL;
 }

 return OK;
 }

 case DESTROY_PLUGIN:
 {
            CHECK_INTERFACE(ICrypto, data, reply);
            reply->writeInt32(destroyPlugin());

 return OK;
 }

 case REQUIRES_SECURE_COMPONENT:
 {
            CHECK_INTERFACE(ICrypto, data, reply);

 const char *mime = data.readCString();
            reply->writeInt32(requiresSecureDecoderComponent(mime));

 return OK;
 }

 case DECRYPT:
 {
            CHECK_INTERFACE(ICrypto, data, reply);

 bool secure = data.readInt32() != 0;
 CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32();

 uint8_t key[16];
            data.read(key, sizeof(key));

 uint8_t iv[16];
            data.read(iv, sizeof(iv));

 size_t totalSize = data.readInt32();
            sp<IMemory> sharedBuffer =
                interface_cast<IMemory>(data.readStrongBinder());
 int32_t offset = data.readInt32();

 int32_t numSubSamples = data.readInt32();

 CryptoPlugin::SubSample *subSamples =
 new CryptoPlugin::SubSample[numSubSamples];

            data.read(
                    subSamples,
 sizeof(CryptoPlugin::SubSample) * numSubSamples);

 void *secureBufferId, *dstPtr;
 if (secure) {
                secureBufferId = reinterpret_cast<void *>(static_cast<uintptr_t>(data.readInt64()));
 } else {
                dstPtr = calloc(1, totalSize);
 }

 AString errorDetailMsg;
 ssize_t result;

 size_t sumSubsampleSizes = 0;
 bool overflow = false;
 for (int32_t i = 0; i < numSubSamples; ++i) {
 CryptoPlugin::SubSample &ss = subSamples[i];
 if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfEncryptedData) {
                    sumSubsampleSizes += ss.mNumBytesOfEncryptedData;
 } else {
                    overflow = true;
 }
 if (sumSubsampleSizes <= SIZE_MAX - ss.mNumBytesOfClearData) {
                    sumSubsampleSizes += ss.mNumBytesOfClearData;
 } else {
                    overflow = true;
 }
 }

             if (overflow || sumSubsampleSizes != totalSize) {
                 result = -EINVAL;
            } else if (totalSize > sharedBuffer->size()) {
                result = -EINVAL;
            } else if ((size_t)offset > sharedBuffer->size() - totalSize) {
                 result = -EINVAL;
             } else {
                 result = decrypt(
                    secure,
                    key,
                    iv,
                    mode,
                    sharedBuffer, offset,
                    subSamples, numSubSamples,
                    secure ? secureBufferId : dstPtr,
 &errorDetailMsg);
 }

            reply->writeInt32(result);

 if (isCryptoError(result)) {
                reply->writeCString(errorDetailMsg.c_str());
 }

 if (!secure) {
 if (result >= 0) {
                    CHECK_LE(result, static_cast<ssize_t>(totalSize));
                    reply->write(dstPtr, result);
 }
                free(dstPtr);
                dstPtr = NULL;
 }

 delete[] subSamples;
            subSamples = NULL;

 return OK;
 }

 case NOTIFY_RESOLUTION:
 {
            CHECK_INTERFACE(ICrypto, data, reply);

 int32_t width = data.readInt32();
 int32_t height = data.readInt32();
            notifyResolution(width, height);

 return OK;
 }

 case SET_MEDIADRM_SESSION:
 {
            CHECK_INTERFACE(IDrm, data, reply);
 Vector<uint8_t> sessionId;
            readVector(data, sessionId);
            reply->writeInt32(setMediaDrmSession(sessionId));
 return OK;
 }

 default:
 return BBinder::onTransact(code, data, reply, flags);
 }
}


void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler)
{
    hal_info *info = getHalInfo(handle);
 char buf[64];

    info->cleaned_up_handler = handler;
 if (write(info->cleanup_socks[0], "Exit", 4) < 1) {
        ALOGE("could not write to the cleanup socket");
 } else {
        memset(buf, 0, sizeof(buf));
 int result = read(info->cleanup_socks[0], buf, sizeof(buf));
        ALOGE("%s: Read after POLL returned %d, error no = %d", __FUNCTION__, result, errno);
 if (strncmp(buf, "Done", 4) == 0) {
            ALOGE("Event processing terminated");
 } else {
            ALOGD("Rx'ed %s", buf);
 }
 }
    info->clean_up = true;
    pthread_mutex_lock(&info->cb_lock);

 int bad_commands = 0;

 for (int i = 0; i < info->num_event_cb; i++) {
        cb_info *cbi = &(info->event_cb[i]);
 WifiCommand *cmd = (WifiCommand *)cbi->cb_arg;
        ALOGI("Command left in event_cb %p:%s", cmd, (cmd ? cmd->getType(): ""));
 }

 while (info->num_cmd > bad_commands) {
 int num_cmd = info->num_cmd;
        cmd_info *cmdi = &(info->cmd[bad_commands]);
 WifiCommand *cmd = cmdi->cmd;
 if (cmd != NULL) {
            ALOGI("Cancelling command %p:%s", cmd, cmd->getType());

             pthread_mutex_unlock(&info->cb_lock);
             cmd->cancel();
             pthread_mutex_lock(&info->cb_lock);
            /* release reference added when command is saved */
            cmd->releaseRef();
             if (num_cmd == info->num_cmd) {
                 ALOGI("Cancelling command %p:%s did not work", cmd, (cmd ? cmd->getType(): ""));
                 bad_commands++;
             }
         }
     }

 for (int i = 0; i < info->num_event_cb; i++) {
        cb_info *cbi = &(info->event_cb[i]);
 WifiCommand *cmd = (WifiCommand *)cbi->cb_arg;
        ALOGE("Leaked command %p", cmd);
 }
    pthread_mutex_unlock(&info->cb_lock);
    internal_cleaned_up_handler(handle);
}

Use-after-free vulnerability in the wifi_cleanup function in bcmdhd/wifi_hal/wifi_hal.cpp in Wi-Fi in Android 6.x before 2016-02-01 allows attackers to gain privileges by leveraging access to the local physical environment during execution of a crafted application, aka internal bug 25753768.


void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler)
{
    hal_info *info = getHalInfo(handle);
 char buf[64];

    info->cleaned_up_handler = handler;
 if (write(info->cleanup_socks[0], "Exit", 4) < 1) {
        ALOGE("could not write to the cleanup socket");
 } else {
        memset(buf, 0, sizeof(buf));
 int result = read(info->cleanup_socks[0], buf, sizeof(buf));
        ALOGE("%s: Read after POLL returned %d, error no = %d", __FUNCTION__, result, errno);
 if (strncmp(buf, "Done", 4) == 0) {
            ALOGE("Event processing terminated");
 } else {
            ALOGD("Rx'ed %s", buf);
 }
 }
    info->clean_up = true;
    pthread_mutex_lock(&info->cb_lock);

 int bad_commands = 0;

 for (int i = 0; i < info->num_event_cb; i++) {
        cb_info *cbi = &(info->event_cb[i]);
 WifiCommand *cmd = (WifiCommand *)cbi->cb_arg;
        ALOGI("Command left in event_cb %p:%s", cmd, (cmd ? cmd->getType(): ""));
 }

 while (info->num_cmd > bad_commands) {
 int num_cmd = info->num_cmd;
        cmd_info *cmdi = &(info->cmd[bad_commands]);
 WifiCommand *cmd = cmdi->cmd;
 if (cmd != NULL) {
            ALOGI("Cancelling command %p:%s", cmd, cmd->getType());

             pthread_mutex_unlock(&info->cb_lock);
             cmd->cancel();
             pthread_mutex_lock(&info->cb_lock);
             if (num_cmd == info->num_cmd) {
                 ALOGI("Cancelling command %p:%s did not work", cmd, (cmd ? cmd->getType(): ""));
                 bad_commands++;
             }
            /* release reference added when command is saved */
            cmd->releaseRef();
         }
     }

 for (int i = 0; i < info->num_event_cb; i++) {
        cb_info *cbi = &(info->event_cb[i]);
 WifiCommand *cmd = (WifiCommand *)cbi->cb_arg;
        ALOGE("Leaked command %p", cmd);
 }
    pthread_mutex_unlock(&info->cb_lock);
    internal_cleaned_up_handler(handle);
}


static bool getCoverageFormat12(vector<uint32_t>& coverage, const uint8_t* data, size_t size) {
 const size_t kNGroupsOffset = 12;
 const size_t kFirstGroupOffset = 16;

     const size_t kGroupSize = 12;
     const size_t kStartCharCodeOffset = 0;
     const size_t kEndCharCodeOffset = 4;
     if (kFirstGroupOffset > size) {
         return false;
     }
     uint32_t nGroups = readU32(data, kNGroupsOffset);
    if (kFirstGroupOffset + nGroups * kGroupSize > size) {
         return false;
     }
     for (uint32_t i = 0; i < nGroups; i++) {
 uint32_t groupOffset = kFirstGroupOffset + i * kGroupSize;
 uint32_t start = readU32(data, groupOffset + kStartCharCodeOffset);
 uint32_t end = readU32(data, groupOffset + kEndCharCodeOffset);
        addRange(coverage, start, end + 1); // file is inclusive, vector is exclusive
 }
 return true;
}

Integer overflow in the getCoverageFormat12 function in CmapCoverage.cpp in the Minikin library in Android 5.x before 5.1.1 LMY49G and 6.x before 2016-02-01 allows attackers to cause a denial of service (continuous rebooting) via an application that triggers loading of a crafted TTF font, aka internal bug 25645298.


static bool getCoverageFormat12(vector<uint32_t>& coverage, const uint8_t* data, size_t size) {
 const size_t kNGroupsOffset = 12;
 const size_t kFirstGroupOffset = 16;

     const size_t kGroupSize = 12;
     const size_t kStartCharCodeOffset = 0;
     const size_t kEndCharCodeOffset = 4;
    const size_t kMaxNGroups = 0xfffffff0 / kGroupSize;  // protection against overflow
    // For all values < kMaxNGroups, kFirstGroupOffset + nGroups * kGroupSize fits in 32 bits.
     if (kFirstGroupOffset > size) {
         return false;
     }
     uint32_t nGroups = readU32(data, kNGroupsOffset);
    if (nGroups >= kMaxNGroups || kFirstGroupOffset + nGroups * kGroupSize > size) {
         return false;
     }
     for (uint32_t i = 0; i < nGroups; i++) {
 uint32_t groupOffset = kFirstGroupOffset + i * kGroupSize;
 uint32_t start = readU32(data, groupOffset + kStartCharCodeOffset);
 uint32_t end = readU32(data, groupOffset + kEndCharCodeOffset);
        addRange(coverage, start, end + 1); // file is inclusive, vector is exclusive
 }
 return true;
}


static bool get_build_id(
 Backtrace* backtrace, uintptr_t base_addr, uint8_t* e_ident, std::string* build_id) {
 HdrType hdr;

  memcpy(&hdr.e_ident[0], e_ident, EI_NIDENT);

 if (backtrace->Read(base_addr + EI_NIDENT, reinterpret_cast<uint8_t*>(&hdr) + EI_NIDENT,
 sizeof(HdrType) - EI_NIDENT) != sizeof(HdrType) - EI_NIDENT) {
 return false;
 }

 for (size_t i = 0; i < hdr.e_phnum; i++) {
 PhdrType phdr;
 if (backtrace->Read(base_addr + hdr.e_phoff + i * hdr.e_phentsize,
 reinterpret_cast<uint8_t*>(&phdr), sizeof(phdr)) != sizeof(phdr)) {
 return false;
 }
 if (phdr.p_type == PT_NOTE) {
 size_t hdr_size = phdr.p_filesz;
 uintptr_t addr = base_addr + phdr.p_offset;
 while (hdr_size >= sizeof(NhdrType)) {
 NhdrType nhdr;
 if (backtrace->Read(addr, reinterpret_cast<uint8_t*>(&nhdr), sizeof(nhdr)) != sizeof(nhdr)) {
 return false;
 }
        addr += sizeof(nhdr);

         if (nhdr.n_type == NT_GNU_BUILD_ID) {
           addr += NOTE_ALIGN(nhdr.n_namesz);
          uint8_t build_id_data[128];
          if (nhdr.n_namesz > sizeof(build_id_data)) {
            ALOGE("Possible corrupted note, name size value is too large: %u",
                  nhdr.n_namesz);
             return false;
           }
           if (backtrace->Read(addr, build_id_data, nhdr.n_descsz) != nhdr.n_descsz) {
 return false;
 }

          build_id->clear();
 for (size_t bytes = 0; bytes < nhdr.n_descsz; bytes++) {
 *build_id += android::base::StringPrintf("%02x", build_id_data[bytes]);
 }

 return true;
 } else {
          hdr_size -= sizeof(nhdr);
 size_t skip_bytes = NOTE_ALIGN(nhdr.n_namesz) + NOTE_ALIGN(nhdr.n_descsz);
          addr += skip_bytes;
 if (hdr_size < skip_bytes) {
 break;
 }
          hdr_size -= skip_bytes;
 }
 }
 }
 }
 return false;
}

The get_build_id function in elf_utils.cpp in Debuggerd in Android 6.x before 2016-02-01 allows attackers to gain privileges via a crafted application that mishandles a Desc Size element in an ELF Note, aka internal bug 25187394.


static bool get_build_id(
 Backtrace* backtrace, uintptr_t base_addr, uint8_t* e_ident, std::string* build_id) {
 HdrType hdr;

  memcpy(&hdr.e_ident[0], e_ident, EI_NIDENT);

 if (backtrace->Read(base_addr + EI_NIDENT, reinterpret_cast<uint8_t*>(&hdr) + EI_NIDENT,
 sizeof(HdrType) - EI_NIDENT) != sizeof(HdrType) - EI_NIDENT) {
 return false;
 }

 for (size_t i = 0; i < hdr.e_phnum; i++) {
 PhdrType phdr;
 if (backtrace->Read(base_addr + hdr.e_phoff + i * hdr.e_phentsize,
 reinterpret_cast<uint8_t*>(&phdr), sizeof(phdr)) != sizeof(phdr)) {
 return false;
 }
 if (phdr.p_type == PT_NOTE) {
 size_t hdr_size = phdr.p_filesz;
 uintptr_t addr = base_addr + phdr.p_offset;
 while (hdr_size >= sizeof(NhdrType)) {
 NhdrType nhdr;
 if (backtrace->Read(addr, reinterpret_cast<uint8_t*>(&nhdr), sizeof(nhdr)) != sizeof(nhdr)) {
 return false;
 }
        addr += sizeof(nhdr);

         if (nhdr.n_type == NT_GNU_BUILD_ID) {
           addr += NOTE_ALIGN(nhdr.n_namesz);
          uint8_t build_id_data[160];
          if (nhdr.n_descsz > sizeof(build_id_data)) {
            ALOGE("Possible corrupted note, desc size value is too large: %u",
                  nhdr.n_descsz);
             return false;
           }
           if (backtrace->Read(addr, build_id_data, nhdr.n_descsz) != nhdr.n_descsz) {
 return false;
 }

          build_id->clear();
 for (size_t bytes = 0; bytes < nhdr.n_descsz; bytes++) {
 *build_id += android::base::StringPrintf("%02x", build_id_data[bytes]);
 }

 return true;
 } else {
          hdr_size -= sizeof(nhdr);
 size_t skip_bytes = NOTE_ALIGN(nhdr.n_namesz) + NOTE_ALIGN(nhdr.n_descsz);
          addr += skip_bytes;
 if (hdr_size < skip_bytes) {
 break;
 }
          hdr_size -= skip_bytes;
 }
 }
 }
 }
 return false;
}


void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
 if (err != OK) {
        mMetaDataSize = -1ll;
        mContentType = "";
        mSniffedMIME = "";
 {
            sp<DataSource> dataSource = mDataSource;
            sp<NuCachedSource2> cachedSource = mCachedSource;
            sp<DataSource> httpSource = mHttpSource;

             {
                 Mutex::Autolock _l(mDisconnectLock);
                 mDataSource.clear();
                 mCachedSource.clear();
                 mHttpSource.clear();
             }
 }

        cancelPollBuffering();
 }
    notifyPrepared(err);
}

The NuPlayer::GenericSource::notifyPreparedAndCleanup function in media/libmediaplayerservice/nuplayer/GenericSource.cpp in mediaserver in Android 5.x before 5.1.1 LMY49G and 6.x before 2016-02-01 improperly manages mDrmManagerClient objects, which allows remote attackers to execute arbitrary code or cause a denial of service (memory corruption) via a crafted media file, aka internal bug 25070434.


void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) {
 if (err != OK) {
        mMetaDataSize = -1ll;
        mContentType = "";
        mSniffedMIME = "";
 {
            sp<DataSource> dataSource = mDataSource;
            sp<NuCachedSource2> cachedSource = mCachedSource;
            sp<DataSource> httpSource = mHttpSource;

             {
                 Mutex::Autolock _l(mDisconnectLock);
                 mDataSource.clear();
                mDrmManagerClient = NULL;
                 mCachedSource.clear();
                 mHttpSource.clear();
             }
 }

        cancelPollBuffering();
 }
    notifyPrepared(err);
}


static int prctl_set_vma_anon_name(unsigned long start, unsigned long end,
 unsigned long arg)
{
 unsigned long tmp;
 struct vm_area_struct * vma, *prev;
 int unmapped_error = 0;
 int error = -EINVAL;

 /*
	 * If the interval [start,end) covers some unmapped address
	 * ranges, just ignore them, but return -ENOMEM at the end.
	 * - this matches the handling in madvise.
	 */
	vma = find_vma_prev(current->mm, start, &prev);
 if (vma && start > vma->vm_start)
		prev = vma;

 for (;;) {
 /* Still start < end. */
		error = -ENOMEM;
 if (!vma)
 return error;

 /* Here start < (end|vma->vm_end). */
 if (start < vma->vm_start) {
			unmapped_error = -ENOMEM;
			start = vma->vm_start;
 if (start >= end)
 return error;
 }

 /* Here vma->vm_start <= start < (end|vma->vm_end) */
		tmp = vma->vm_end;
 if (end < tmp)

 			tmp = end;

 		/* Here vma->vm_start <= start < tmp <= (end|vma->vm_end). */
		error = prctl_update_vma_anon_name(vma, &prev, start, end,
 				(const char __user *)arg);
 		if (error)
 			return error;
		start = tmp;
 if (prev && start < prev->vm_end)
			start = prev->vm_end;
		error = unmapped_error;
 if (start >= end)
 return error;
 if (prev)
			vma = prev->vm_next;
 else /* madvise_remove dropped mmap_sem */
			vma = find_vma(current->mm, start);
 }
}

The prctl_set_vma_anon_name function in kernel/sys.c in Android before 5.1.1 LMY49F and 6.0 before 2016-01-01 does not ensure that only one vma is accessed in a certain update action, which allows attackers to gain privileges or cause a denial of service (vma list corruption) via a crafted application, aka internal bug 20017123.


static int prctl_set_vma_anon_name(unsigned long start, unsigned long end,
 unsigned long arg)
{
 unsigned long tmp;
 struct vm_area_struct * vma, *prev;
 int unmapped_error = 0;
 int error = -EINVAL;

 /*
	 * If the interval [start,end) covers some unmapped address
	 * ranges, just ignore them, but return -ENOMEM at the end.
	 * - this matches the handling in madvise.
	 */
	vma = find_vma_prev(current->mm, start, &prev);
 if (vma && start > vma->vm_start)
		prev = vma;

 for (;;) {
 /* Still start < end. */
		error = -ENOMEM;
 if (!vma)
 return error;

 /* Here start < (end|vma->vm_end). */
 if (start < vma->vm_start) {
			unmapped_error = -ENOMEM;
			start = vma->vm_start;
 if (start >= end)
 return error;
 }

 /* Here vma->vm_start <= start < (end|vma->vm_end) */
		tmp = vma->vm_end;
 if (end < tmp)

 			tmp = end;

 		/* Here vma->vm_start <= start < tmp <= (end|vma->vm_end). */
		error = prctl_update_vma_anon_name(vma, &prev, start, tmp,
 				(const char __user *)arg);
 		if (error)
 			return error;
		start = tmp;
 if (prev && start < prev->vm_end)
			start = prev->vm_end;
		error = unmapped_error;
 if (start >= end)
 return error;
 if (prev)
			vma = prev->vm_next;
 else /* madvise_remove dropped mmap_sem */
			vma = find_vma(current->mm, start);
 }
}


static void debugCallback (int fd, short flags, void *param) {
 int acceptFD, option;
 struct sockaddr_un peeraddr;
 socklen_t socklen = sizeof (peeraddr);

     int data;
     unsigned int qxdm_data[6];
     const char *deactData[1] = {"1"};
    char *actData[1];
     RIL_Dial dialData;
     int hangupData[1] = {1};
     int number;
     char **args;
     RIL_SOCKET_ID socket_id = RIL_SOCKET_1;
     int sim_id = 0;

     RLOGI("debugCallback for socket %s", rilSocketIdToString(socket_id));

    acceptFD = accept (fd, (sockaddr *) &peeraddr, &socklen);

 if (acceptFD < 0) {
        RLOGE ("error accepting on debug port: %d\n", errno);
 return;
 }

 if (recv(acceptFD, &number, sizeof(int), 0) != sizeof(int)) {
        RLOGE ("error reading on socket: number of Args: \n");
        close(acceptFD);
 return;
 }

 if (number < 0) {
        RLOGE ("Invalid number of arguments: \n");
        close(acceptFD);
 return;
 }

    args = (char **) calloc(number, sizeof(char*));
 if (args == NULL) {
        RLOGE("Memory allocation failed for debug args");
        close(acceptFD);
 return;
 }

 for (int i = 0; i < number; i++) {
 int len;
 if (recv(acceptFD, &len, sizeof(int), 0) != sizeof(int)) {
            RLOGE ("error reading on socket: Len of Args: \n");
            freeDebugCallbackArgs(i, args);
            close(acceptFD);
 return;
 }
 if (len == INT_MAX || len < 0) {
            RLOGE("Invalid value of len: \n");
            freeDebugCallbackArgs(i, args);
            close(acceptFD);
 return;
 }

        args[i] = (char *) calloc(len + 1, sizeof(char));
 if (args[i] == NULL) {
            RLOGE("Memory allocation failed for debug args");
            freeDebugCallbackArgs(i, args);
            close(acceptFD);
 return;
 }
 if (recv(acceptFD, args[i], sizeof(char) * len, 0)
 != (int)sizeof(char) * len) {
            RLOGE ("error reading on socket: Args[%d] \n", i);
            freeDebugCallbackArgs(i, args);
            close(acceptFD);
 return;
 }
 char * buf = args[i];
        buf[len] = 0;
 if ((i+1) == number) {
 /* The last argument should be sim id 0(SIM1)~3(SIM4) */
            sim_id = atoi(args[i]);
 switch (sim_id) {
 case 0:
                    socket_id = RIL_SOCKET_1;
 break;
 #if (SIM_COUNT >= 2)
 case 1:
                    socket_id = RIL_SOCKET_2;
 break;
 #endif
 #if (SIM_COUNT >= 3)
 case 2:
                    socket_id = RIL_SOCKET_3;
 break;
 #endif
 #if (SIM_COUNT >= 4)
 case 3:
                    socket_id = RIL_SOCKET_4;
 break;
 #endif
 default:
                    socket_id = RIL_SOCKET_1;
 break;
 }
 }
 }

 switch (atoi(args[0])) {
 case 0:
            RLOGI ("Connection on debug port: issuing reset.");
            issueLocalRequest(RIL_REQUEST_RESET_RADIO, NULL, 0, socket_id);
 break;
 case 1:
            RLOGI ("Connection on debug port: issuing radio power off.");
            data = 0;
            issueLocalRequest(RIL_REQUEST_RADIO_POWER, &data, sizeof(int), socket_id);
 if (socket_id == RIL_SOCKET_1 && s_ril_param_socket.fdCommand > 0) {
                close(s_ril_param_socket.fdCommand);
                s_ril_param_socket.fdCommand = -1;
 }
 #if (SIM_COUNT == 2)
 else if (socket_id == RIL_SOCKET_2 && s_ril_param_socket2.fdCommand > 0) {
                close(s_ril_param_socket2.fdCommand);
                s_ril_param_socket2.fdCommand = -1;
 }
 #endif
 break;
 case 2:
            RLOGI ("Debug port: issuing unsolicited voice network change.");
            RIL_UNSOL_RESPONSE(RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, NULL, 0, socket_id);
 break;
 case 3:
            RLOGI ("Debug port: QXDM log enable.");
            qxdm_data[0] = 65536; // head.func_tag
            qxdm_data[1] = 16; // head.len
            qxdm_data[2] = 1; // mode: 1 for 'start logging'
            qxdm_data[3] = 32; // log_file_size: 32megabytes
            qxdm_data[4] = 0; // log_mask
            qxdm_data[5] = 8; // log_max_fileindex
            issueLocalRequest(RIL_REQUEST_OEM_HOOK_RAW, qxdm_data,
 6 * sizeof(int), socket_id);
 break;
 case 4:
            RLOGI ("Debug port: QXDM log disable.");
            qxdm_data[0] = 65536;
            qxdm_data[1] = 16;
            qxdm_data[2] = 0; // mode: 0 for 'stop logging'
            qxdm_data[3] = 32;
            qxdm_data[4] = 0;
            qxdm_data[5] = 8;
            issueLocalRequest(RIL_REQUEST_OEM_HOOK_RAW, qxdm_data,
 6 * sizeof(int), socket_id);
 break;
 case 5:
            RLOGI("Debug port: Radio On");
            data = 1;
            issueLocalRequest(RIL_REQUEST_RADIO_POWER, &data, sizeof(int), socket_id);
            sleep(2);

             issueLocalRequest(RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, NULL, 0, socket_id);
             break;
        case 6:
            RLOGI("Debug port: Setup Data Call, Apn :%s\n", args[1]);
            actData[0] = args[1];
            issueLocalRequest(RIL_REQUEST_SETUP_DATA_CALL, &actData,
                              sizeof(actData), socket_id);
            break;
         case 7:
             RLOGI("Debug port: Deactivate Data Call");
             issueLocalRequest(RIL_REQUEST_DEACTIVATE_DATA_CALL, &deactData,
 sizeof(deactData), socket_id);
 break;

         case 8:
             RLOGI("Debug port: Dial Call");
             dialData.clir = 0;
             dialData.address = args[1];
             issueLocalRequest(RIL_REQUEST_DIAL, &dialData, sizeof(dialData), socket_id);
             break;
 case 9:
            RLOGI("Debug port: Answer Call");
            issueLocalRequest(RIL_REQUEST_ANSWER, NULL, 0, socket_id);
 break;
 case 10:
            RLOGI("Debug port: End Call");
            issueLocalRequest(RIL_REQUEST_HANGUP, &hangupData,
 sizeof(hangupData), socket_id);
 break;
 default:
            RLOGE ("Invalid request");
 break;
 }
    freeDebugCallbackArgs(number, args);
    close(acceptFD);
}

An information disclosure vulnerability in the Android system (rild). Product: Android. Versions: 4.4.4, 5.0.2, 5.1.1, 6.0, 6.0.1, 7.0, 7.1.1, 7.1.2. Android ID: A-37896655.