Commit message: None
CVE: CVE-2016-0826
CWE: CWE-264
Vulnerability description: 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.

Project: Android

void CameraService::BasicClient::disconnect() {
    ALOGV("BasicClient::disconnect");
    mCameraService->removeClientByRemote(mRemoteBinder);

     mClientPid = 0;
 }

Project: Android

static int getCallingPid() {
 return IPCThreadState::self()->getCallingPid();
}

Project: Android

status_t CameraService::getCameraCharacteristics(int cameraId,
 CameraMetadata* cameraInfo) {
 if (!cameraInfo) {
        ALOGE("%s: cameraInfo is NULL", __FUNCTION__);
 return BAD_VALUE;
 }

 if (!mModule) {
        ALOGE("%s: camera hardware module doesn't exist", __FUNCTION__);
 return -ENODEV;
 }

 if (mModule->common.module_api_version < CAMERA_MODULE_API_VERSION_2_0) {
        ALOGE("%s: Only HAL module version V2 or higher supports static metadata", __FUNCTION__);
 return BAD_VALUE;
 }

 if (cameraId < 0 || cameraId >= mNumberOfCameras) {
        ALOGE("%s: Invalid camera id: %d", __FUNCTION__, cameraId);
 return BAD_VALUE;
 }

 int facing;
 if (getDeviceVersion(cameraId, &facing) == CAMERA_DEVICE_API_VERSION_1_0) {
        ALOGE("%s: HAL1 doesn't support static metadata yet", __FUNCTION__);
 return BAD_VALUE;
 }

 if (getDeviceVersion(cameraId, &facing) <= CAMERA_DEVICE_API_VERSION_2_1) {
        ALOGW("%s: HAL2.x doesn't support getCameraCharacteristics for now", __FUNCTION__);
 return BAD_VALUE;
 }

 struct camera_info info;
 status_t ret = mModule->get_camera_info(cameraId, &info);
 *cameraInfo = info.static_camera_characteristics;

 return ret;
}

Project: Android

void CameraService::onDeviceStatusChanged(int cameraId,
 int newStatus)
{
    ALOGI("%s: Status changed for cameraId=%d, newStatus=%d", __FUNCTION__,
          cameraId, newStatus);

 if (cameraId < 0 || cameraId >= MAX_CAMERAS) {
        ALOGE("%s: Bad camera ID %d", __FUNCTION__, cameraId);
 return;
 }

 if ((int)getStatus(cameraId) == newStatus) {
        ALOGE("%s: State transition to the same status 0x%x not allowed",
              __FUNCTION__, (uint32_t)newStatus);
 return;
 }

 /* don't do this in updateStatus
       since it is also called from connect and we could get into a deadlock */
 if (newStatus == CAMERA_DEVICE_STATUS_NOT_PRESENT) {
 Vector<sp<BasicClient> > clientsToDisconnect;
 {
 Mutex::Autolock al(mServiceLock);

 /* Find all clients that we need to disconnect */
           sp<BasicClient> client = mClient[cameraId].promote();
 if (client.get() != NULL) {
               clientsToDisconnect.push_back(client);
 }

 int i = cameraId;
 for (size_t j = 0; j < mProClientList[i].size(); ++j) {
               sp<ProClient> cl = mProClientList[i][j].promote();
 if (cl != NULL) {
                   clientsToDisconnect.push_back(cl);
 }
 }
 }

 /* now disconnect them. don't hold the lock
           or we can get into a deadlock */

 for (size_t i = 0; i < clientsToDisconnect.size(); ++i) {
            sp<BasicClient> client = clientsToDisconnect[i];

            client->disconnect();
 /**
             * The remote app will no longer be able to call methods on the
             * client since the client PID will be reset to 0
             */
 }

        ALOGV("%s: After unplug, disconnected %d clients",
              __FUNCTION__, clientsToDisconnect.size());
 }

    updateStatus(
 static_cast<ICameraServiceListener::Status>(newStatus), cameraId);

}

Project: Android

void CameraService::releaseSound() {
 Mutex::Autolock lock(mSoundLock);
    LOG1("CameraService::releaseSound ref=%d", mSoundRef);
 if (--mSoundRef) return;

 for (int i = 0; i < NUM_SOUNDS; i++) {
 if (mSoundPlayer[i] != 0) {
            mSoundPlayer[i]->disconnect();
            mSoundPlayer[i].clear();
 }
 }
}

Project: Android

CameraService::~CameraService() {
 for (int i = 0; i < mNumberOfCameras; i++) {
 if (mBusy[i]) {
            ALOGE("camera %d is still in use in destructor!", i);
 }
 }

    gCameraService = NULL;
}

Project: Android

status_t Camera2Client::commandStopFaceDetectionL(Parameters &params) {
 status_t res = OK;
    ALOGV("%s: Camera %d: Stopping face detection",
          __FUNCTION__, mCameraId);

 if (!params.enableFaceDetect) return OK;

    params.enableFaceDetect = false;

 if (params.state == Parameters::PREVIEW
 || params.state == Parameters::RECORD
 || params.state == Parameters::VIDEO_SNAPSHOT) {
        res = updateRequests(params);
 }

 return res;
}

Project: Android

status_t Camera2Client::connect(const sp<ICameraClient>& client) {
    ATRACE_CALL();
    ALOGV("%s: E", __FUNCTION__);
 Mutex::Autolock icl(mBinderSerializationLock);

 if (mClientPid != 0 && getCallingPid() != mClientPid) {
        ALOGE("%s: Camera %d: Connection attempt from pid %d; "
 "current locked to pid %d", __FUNCTION__,
                mCameraId, getCallingPid(), mClientPid);
 return BAD_VALUE;
 }

    mClientPid = getCallingPid();

    mRemoteCallback = client;
    mSharedCameraCallbacks = client;

 return OK;
}

Project: Android

int Camera2Client::getCallbackStreamId() const {
 return mCallbackProcessor->getStreamId();
}

Project: Android

String8 Camera2Client::getParameters() const {
    ATRACE_CALL();
    ALOGV("%s: Camera %d", __FUNCTION__, mCameraId);
 Mutex::Autolock icl(mBinderSerializationLock);
 if ( checkPid(__FUNCTION__) != OK) return String8();

 SharedParameters::ReadLock l(mParameters);

 return l.mParameters.get();
}

Project: Android

bool Camera2Client::recordingEnabled() {
    ATRACE_CALL();
 Mutex::Autolock icl(mBinderSerializationLock);

 if ( checkPid(__FUNCTION__) != OK) return false;

 return recordingEnabledL();
}

Project: Android

status_t Camera2Client::storeMetaDataInBuffers(bool enabled) {
    ATRACE_CALL();
 Mutex::Autolock icl(mBinderSerializationLock);
 status_t res;
 if ( (res = checkPid(__FUNCTION__) ) != OK) return res;

 SharedParameters::Lock l(mParameters);
 switch (l.mParameters.state) {
 case Parameters::RECORD:
 case Parameters::VIDEO_SNAPSHOT:
            ALOGE("%s: Camera %d: Can't be called in state %s",
                    __FUNCTION__, mCameraId,
 Parameters::getStateName(l.mParameters.state));
 return INVALID_OPERATION;
 default:
 break;
 }

    l.mParameters.storeMetadataInBuffers = enabled;

 return OK;
}

Project: Android

status_t Camera2Client::takePicture(int msgType) {
    ATRACE_CALL();
 Mutex::Autolock icl(mBinderSerializationLock);
 status_t res;
 if ( (res = checkPid(__FUNCTION__) ) != OK) return res;

 int takePictureCounter;
 {
 SharedParameters::Lock l(mParameters);
 switch (l.mParameters.state) {
 case Parameters::DISCONNECTED:
 case Parameters::STOPPED:
 case Parameters::WAITING_FOR_PREVIEW_WINDOW:
                ALOGE("%s: Camera %d: Cannot take picture without preview enabled",
                        __FUNCTION__, mCameraId);
 return INVALID_OPERATION;
 case Parameters::PREVIEW:
                res = commandStopFaceDetectionL(l.mParameters);
 if (res != OK) {
                    ALOGE("%s: Camera %d: Unable to stop face detection for still capture",
                            __FUNCTION__, mCameraId);
 return res;
 }
                l.mParameters.state = Parameters::STILL_CAPTURE;
 break;
 case Parameters::RECORD:
                l.mParameters.state = Parameters::VIDEO_SNAPSHOT;
 break;
 case Parameters::STILL_CAPTURE:
 case Parameters::VIDEO_SNAPSHOT:
                ALOGE("%s: Camera %d: Already taking a picture",
                        __FUNCTION__, mCameraId);
 return INVALID_OPERATION;
 }

        ALOGV("%s: Camera %d: Starting picture capture", __FUNCTION__, mCameraId);

        res = updateProcessorStream(mJpegProcessor, l.mParameters);
 if (res != OK) {
            ALOGE("%s: Camera %d: Can't set up still image stream: %s (%d)",
                    __FUNCTION__, mCameraId, strerror(-res), res);
 return res;
 }
        takePictureCounter = ++l.mParameters.takePictureCounter;
 }

    ATRACE_ASYNC_BEGIN(kTakepictureLabel, takePictureCounter);

    syncWithDevice();

    res = mCaptureSequencer->startCapture(msgType);
 if (res != OK) {
        ALOGE("%s: Camera %d: Unable to start capture: %s (%d)",
                __FUNCTION__, mCameraId, strerror(-res), res);
 }

 return res;
}

Project: Android

status_t CameraClient::checkPid() const {
 int callingPid = getCallingPid();
 if (callingPid == mClientPid) return NO_ERROR;

    ALOGW("attempt to use a locked camera from a different process"
 " (old pid %d, new pid %d)", mClientPid, callingPid);
 return EBUSY;
}

Project: Android

void CameraClient::enableMsgType(int32_t msgType) {
    android_atomic_or(msgType, &mMsgEnabled);
    mHardware->enableMsgType(msgType);
}

Project: Android

void CameraClient::handleCompressedPicture(const sp<IMemory>& mem) {
    disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);

    sp<ICameraClient> c = mRemoteCallback;
    mLock.unlock();
 if (c != 0) {
        c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem, NULL);
 }
}

Project: Android

status_t CameraClient::setParameters(const String8& params) {
    LOG1("setParameters (pid %d) (%s)", getCallingPid(), params.string());

 Mutex::Autolock lock(mLock);
 status_t result = checkPidAndHardware();
 if (result != NO_ERROR) return result;

 CameraParameters p(params);
 return mHardware->setParameters(p);
}

Project: Android

status_t CameraClient::startRecording() {
    LOG1("startRecording (pid %d)", getCallingPid());
 return startCameraMode(CAMERA_RECORDING_MODE);
}

Project: Android

status_t CameraClient::unlock() {
 int callingPid = getCallingPid();
    LOG1("unlock (pid %d)", callingPid);
 Mutex::Autolock lock(mLock);

 status_t result = checkPid();
 if (result == NO_ERROR) {
 if (mHardware->recordingEnabled()) {
            ALOGE("Not allowed to unlock camera during recording.");
 return INVALID_OPERATION;
 }
        mClientPid = 0;
        LOG1("clear mRemoteCallback (pid %d)", callingPid);
        mRemoteCallback.clear();
 }
 return result;
}

Project: Android

status_t CameraDeviceClient::cancelRequest(int requestId) {
    ATRACE_CALL();
    ALOGV("%s, requestId = %d", __FUNCTION__, requestId);

 status_t res;

 if ( (res = checkPid(__FUNCTION__) ) != OK) return res;

 Mutex::Autolock icl(mBinderSerializationLock);

 if (!mDevice.get()) return DEAD_OBJECT;

 Vector<int>::iterator it, end;
 for (it = mStreamingRequestList.begin(), end = mStreamingRequestList.end();
         it != end; ++it) {
 if (*it == requestId) {
 break;
 }
 }

 if (it == end) {
        ALOGE("%s: Camera%d: Did not find request id %d in list of streaming "
 "requests", __FUNCTION__, mCameraId, requestId);
 return BAD_VALUE;
 }

    res = mDevice->clearStreamingRequest();

 if (res == OK) {
        ALOGV("%s: Camera %d: Successfully cleared streaming request",
              __FUNCTION__, mCameraId);
        mStreamingRequestList.erase(it);
 }

 return res;
}

Project: Android

bool CameraDeviceClient::enforceRequestPermissions(CameraMetadata& metadata) {

 const int pid = IPCThreadState::self()->getCallingPid();
 const int selfPid = getpid();
 camera_metadata_entry_t entry;

 /**
     * Mixin default important security values
     * - android.led.transmit = defaulted ON
     */
 CameraMetadata staticInfo = mDevice->info();
    entry = staticInfo.find(ANDROID_LED_AVAILABLE_LEDS);
 for(size_t i = 0; i < entry.count; ++i) {
 uint8_t led = entry.data.u8[i];

 switch(led) {
 case ANDROID_LED_AVAILABLE_LEDS_TRANSMIT: {
 uint8_t transmitDefault = ANDROID_LED_TRANSMIT_ON;
 if (!metadata.exists(ANDROID_LED_TRANSMIT)) {
                    metadata.update(ANDROID_LED_TRANSMIT,
 &transmitDefault, 1);
 }
 break;
 }
 }
 }

 if (pid == selfPid) {
 return true;
 }

 /**
     * Permission check special fields in the request
     * - android.led.transmit = android.permission.CAMERA_DISABLE_TRANSMIT
     */
    entry = metadata.find(ANDROID_LED_TRANSMIT);
 if (entry.count > 0 && entry.data.u8[0] != ANDROID_LED_TRANSMIT_ON) {
 String16 permissionString =
 String16("android.permission.CAMERA_DISABLE_TRANSMIT_LED");
 if (!checkCallingPermission(permissionString)) {
 const int uid = IPCThreadState::self()->getCallingUid();
            ALOGE("Permission Denial: "
 "can't disable transmit LED pid=%d, uid=%d", pid, uid);
 return false;
 }
 }

 return true;
}

Project: Android

status_t CameraDeviceClient::flush() {
    ATRACE_CALL();
    ALOGV("%s", __FUNCTION__);

 status_t res = OK;
 if ( (res = checkPid(__FUNCTION__) ) != OK) return res;

 Mutex::Autolock icl(mBinderSerializationLock);

 if (!mDevice.get()) return DEAD_OBJECT;

 return mDevice->flush();

 }

Project: Android

CameraDeviceClient::~CameraDeviceClient() {
}

Project: Android

status_t ProCamera2Client::exclusiveUnlock() {
    ATRACE_CALL();
    ALOGV("%s", __FUNCTION__);

 Mutex::Autolock icl(mBinderSerializationLock);
 SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);

 if (!mExclusiveLock) {
        ALOGW("%s: cannot unlock, no lock was held in the first place",
              __FUNCTION__);
 return BAD_VALUE;
 }

    mExclusiveLock = false;
 if (mRemoteCallback != NULL ) {
        mRemoteCallback->onLockStatusChanged(
 IProCameraCallbacks::LOCK_RELEASED);
 }
    ALOGV("%s: exclusive lock released", __FUNCTION__);

 return OK;
}