diff options
-rw-r--r-- | camera/ICameraService.cpp | 28 | ||||
-rw-r--r-- | include/camera/ICameraService.h | 2 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraService.cpp | 83 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraService.h | 34 |
4 files changed, 102 insertions, 45 deletions
diff --git a/camera/ICameraService.cpp b/camera/ICameraService.cpp index 51a775b..a02dbe2 100644 --- a/camera/ICameraService.cpp +++ b/camera/ICameraService.cpp @@ -20,6 +20,7 @@ #include <utils/Errors.h> #include <utils/String16.h> +#include <inttypes.h> #include <stdint.h> #include <sys/types.h> @@ -303,10 +304,10 @@ public: return res; } - virtual void notifySystemEvent(int eventId, int arg0) { + virtual void notifySystemEvent(int32_t eventId, const int32_t* args, size_t len) { Parcel data, reply; data.writeInt32(eventId); - data.writeInt32(arg0); + data.writeInt32Array(len, args); remote()->transact(BnCameraService::NOTIFY_SYSTEM_EVENT, data, &reply, IBinder::FLAG_ONEWAY); } @@ -481,9 +482,26 @@ status_t BnCameraService::onTransact( } break; case NOTIFY_SYSTEM_EVENT: { CHECK_INTERFACE(ICameraService, data, reply); - int eventId = data.readInt32(); - int arg0 = data.readInt32(); - notifySystemEvent(eventId, arg0); + int32_t eventId = data.readInt32(); + int32_t len = data.readInt32(); + if (len < 0) { + ALOGE("%s: Received poorly formatted length in binder request: notifySystemEvent.", + __FUNCTION__); + return FAILED_TRANSACTION; + } + if (len > 512) { + ALOGE("%s: Length %" PRIi32 " too long in binder request: notifySystemEvent.", + __FUNCTION__, len); + return FAILED_TRANSACTION; + } + int32_t events[len] = {}; + status_t status = data.read(events, sizeof(int32_t) * len); + if (status != NO_ERROR) { + ALOGE("%s: Received poorly formatted binder request: notifySystemEvent.", + __FUNCTION__); + return FAILED_TRANSACTION; + } + notifySystemEvent(eventId, events, len); return NO_ERROR; } break; default: diff --git a/include/camera/ICameraService.h b/include/camera/ICameraService.h index cad275e..5f85635 100644 --- a/include/camera/ICameraService.h +++ b/include/camera/ICameraService.h @@ -164,7 +164,7 @@ public: /** * Notify the camera service of a system event. Should only be called from system_server. */ - virtual void notifySystemEvent(int eventId, int arg0) = 0; + virtual void notifySystemEvent(int32_t eventId, const int32_t* args, size_t length) = 0; }; // ---------------------------------------------------------------------------- diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 59e1c37..fc9a332 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -122,8 +122,8 @@ static void torch_mode_status_change( // should be ok for now. static CameraService *gCameraService; -CameraService::CameraService() : mEventLog(DEFAULT_EVENT_LOG_LENGTH), - mLastUserId(DEFAULT_LAST_USER_ID), mSoundRef(0), mModule(0), mFlashlight(0) { +CameraService::CameraService() : mEventLog(DEFAULT_EVENT_LOG_LENGTH), mAllowedUsers(), + mSoundRef(0), mModule(0), mFlashlight(0) { ALOGI("CameraService started (pid=%d)", getpid()); gCameraService = this; @@ -676,6 +676,20 @@ status_t CameraService::makeClient(const sp<CameraService>& cameraService, return NO_ERROR; } +String8 CameraService::toString(std::set<userid_t> intSet) { + String8 s(""); + bool first = true; + for (userid_t i : intSet) { + if (first) { + s.appendFormat("%d", i); + first = false; + } else { + s.appendFormat(", %d", i); + } + } + return s; +} + status_t CameraService::initializeShimMetadata(int cameraId) { int uid = getCallingUid(); @@ -783,7 +797,7 @@ status_t CameraService::validateConnectLocked(const String8& cameraId, /*inout*/ // Check device policy for this camera char value[PROPERTY_VALUE_MAX]; char key[PROPERTY_KEY_MAX]; - int clientUserId = multiuser_get_user_id(clientUid); + userid_t clientUserId = multiuser_get_user_id(clientUid); snprintf(key, PROPERTY_KEY_MAX, "sys.secpolicy.camera.off_%d", clientUserId); property_get(key, value, "0"); if (strcmp(value, "1") == 0) { @@ -795,10 +809,10 @@ status_t CameraService::validateConnectLocked(const String8& cameraId, /*inout*/ // Only allow clients who are being used by the current foreground device user, unless calling // from our own process. - if (callingPid != getpid() && - (mLastUserId != clientUserId && mLastUserId != DEFAULT_LAST_USER_ID)) { - ALOGE("CameraService::connect X (PID %d) rejected (cannot connect from previous " - "device user %d, current device user %d)", callingPid, clientUserId, mLastUserId); + if (callingPid != getpid() && (mAllowedUsers.find(clientUserId) == mAllowedUsers.end())) { + ALOGE("CameraService::connect X (PID %d) rejected (cannot connect from " + "device user %d, currently allowed device users: %s)", callingPid, clientUserId, + toString(mAllowedUsers).string()); return PERMISSION_DENIED; } @@ -1197,10 +1211,10 @@ status_t CameraService::setTorchMode(const String16& cameraId, bool enabled, return OK; } -void CameraService::notifySystemEvent(int eventId, int arg0) { +void CameraService::notifySystemEvent(int32_t eventId, const int32_t* args, size_t length) { switch(eventId) { case ICameraService::USER_SWITCHED: { - doUserSwitch(/*newUserId*/arg0); + doUserSwitch(/*newUserIds*/args, /*length*/length); break; } case ICameraService::NO_EVENT: @@ -1443,20 +1457,30 @@ sp<CameraService::BasicClient> CameraService::removeClientLocked(const String8& return clientDescriptorPtr->getValue(); } -void CameraService::doUserSwitch(int newUserId) { +void CameraService::doUserSwitch(const int32_t* newUserId, size_t length) { // Acquire mServiceLock and prevent other clients from connecting std::unique_ptr<AutoConditionLock> lock = AutoConditionLock::waitAndAcquire(mServiceLockWrapper); - if (newUserId <= 0) { - ALOGW("%s: Bad user ID %d given during user switch, resetting to default.", __FUNCTION__, - newUserId); - newUserId = DEFAULT_LAST_USER_ID; + std::set<userid_t> newAllowedUsers; + for (size_t i = 0; i < length; i++) { + if (newUserId[i] < 0) { + ALOGE("%s: Bad user ID %d given during user switch, ignoring.", + __FUNCTION__, newUserId[i]); + return; + } + newAllowedUsers.insert(static_cast<userid_t>(newUserId[i])); + } + + + if (newAllowedUsers == mAllowedUsers) { + ALOGW("%s: Received notification of user switch with no updated user IDs.", __FUNCTION__); + return; } - logUserSwitch(mLastUserId, newUserId); + logUserSwitch(mAllowedUsers, newAllowedUsers); - mLastUserId = newUserId; + mAllowedUsers = std::move(newAllowedUsers); // Current user has switched, evict all current clients. std::vector<sp<BasicClient>> evicted; @@ -1468,6 +1492,13 @@ void CameraService::doUserSwitch(int newUserId) { continue; } + // Don't evict clients that are still allowed. + uid_t clientUid = clientSp->getClientUid(); + userid_t clientUserId = multiuser_get_user_id(clientUid); + if (mAllowedUsers.find(clientUserId) != mAllowedUsers.end()) { + continue; + } + evicted.push_back(clientSp); String8 curTime = getFormattedCurrentTime(); @@ -1527,10 +1558,13 @@ void CameraService::logRejected(const char* cameraId, int clientPid, cameraId, clientPackage, clientPid, reason)); } -void CameraService::logUserSwitch(int oldUserId, int newUserId) { +void CameraService::logUserSwitch(const std::set<userid_t>& oldUserIds, + const std::set<userid_t>& newUserIds) { + String8 newUsers = toString(newUserIds); + String8 oldUsers = toString(oldUserIds); // Log the new and old users - logEvent(String8::format("USER_SWITCH from old user: %d , to new user: %d", oldUserId, - newUserId)); + logEvent(String8::format("USER_SWITCH previous allowed users: %s , current allowed users: %s", + oldUsers.string(), newUsers.string())); } void CameraService::logDeviceRemoved(const char* cameraId, const char* reason) { @@ -1735,6 +1769,10 @@ int CameraService::BasicClient::getClientPid() const { return mClientPid; } +uid_t CameraService::BasicClient::getClientUid() const { + return mClientUid; +} + bool CameraService::BasicClient::canCastToApiClient(apiLevel level) const { // Defaults to API2. return level == API_2; @@ -1937,12 +1975,18 @@ String8 CameraService::CameraClientManager::toString() const { auto conflicting = i->getConflicting(); auto clientSp = i->getValue(); String8 packageName; + userid_t clientUserId; if (clientSp.get() != nullptr) { packageName = String8{clientSp->getPackageName()}; + uid_t clientUid = clientSp->getClientUid(); + clientUserId = multiuser_get_user_id(clientUid); } ret.appendFormat("\n(Camera ID: %s, Cost: %" PRId32 ", PID: %" PRId32 ", Priority: %" PRId32 ", ", key.string(), cost, pid, priority); + if (clientSp.get() != nullptr) { + ret.appendFormat("User Id: %d, ", clientUserId); + } if (packageName.size() != 0) { ret.appendFormat("Client Package Name: %s", packageName.string()); } @@ -2025,6 +2069,7 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) { result.appendFormat("Number of camera devices: %d\n", mNumberOfCameras); String8 activeClientString = mActiveClientManager.toString(); result.appendFormat("Active Camera Clients:\n%s", activeClientString.string()); + result.appendFormat("Allowed users:\n%s\n", toString(mAllowedUsers).string()); sp<VendorTagDescriptor> desc = VendorTagDescriptor::getGlobalVendorTagDescriptor(); if (desc == NULL) { diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 1041550..9b7163a 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -83,11 +83,6 @@ public: // Default number of messages to store in eviction log static const size_t DEFAULT_EVENT_LOG_LENGTH = 100; - enum { - // Default last user id - DEFAULT_LAST_USER_ID = 0, - }; - // Implementation of BinderService<T> static char const* getServiceName() { return "media.camera"; } @@ -141,7 +136,7 @@ public: virtual status_t setTorchMode(const String16& cameraId, bool enabled, const sp<IBinder>& clientBinder); - virtual void notifySystemEvent(int eventId, int arg0); + virtual void notifySystemEvent(int32_t eventId, const int32_t* args, size_t length); // OK = supports api of that version, -EOPNOTSUPP = does not support virtual status_t supportsCameraApi( @@ -200,6 +195,9 @@ public: virtual void notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode, const CaptureResultExtras& resultExtras) = 0; + // Get the UID of the application client using this + virtual uid_t getClientUid() const; + // Get the PID of the application client using this virtual int getClientPid() const; @@ -469,7 +467,6 @@ private: const String16& clientPackageName, int clientUid, apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly, /*out*/sp<CLIENT>& device); - // Lock guarding camera service state Mutex mServiceLock; @@ -492,8 +489,8 @@ private: RingBuffer<String8> mEventLog; Mutex mLogLock; - // UID of last user. - int mLastUserId; + // Currently allowed user IDs + std::set<userid_t> mAllowedUsers; /** * Get the camera state for a given camera id. @@ -542,7 +539,7 @@ private: /** * Handle a notification that the current device user has changed. */ - void doUserSwitch(int newUserId); + void doUserSwitch(const int32_t* newUserId, size_t length); /** * Add an event log message. @@ -568,7 +565,8 @@ private: /** * Add an event log message that the current device user has been switched. */ - void logUserSwitch(int oldUserId, int newUserId); + void logUserSwitch(const std::set<userid_t>& oldUserIds, + const std::set<userid_t>& newUserIds); /** * Add an event log message that a device has been removed by the HAL @@ -699,6 +697,11 @@ private: int facing, int clientPid, uid_t clientUid, int servicePid, bool legacyMode, int halVersion, int deviceVersion, apiLevel effectiveApiLevel, /*out*/sp<BasicClient>* client); + + status_t checkCameraAccess(const String16& opPackageName); + + static String8 toString(std::set<userid_t> intSet); + }; template<class Func> @@ -775,15 +778,6 @@ status_t CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String if((ret = validateConnectLocked(cameraId, /*inout*/clientUid)) != NO_ERROR) { return ret; } - int userId = multiuser_get_user_id(clientUid); - - if (userId != mLastUserId && clientPid != getpid() ) { - // If no previous user ID had been set, set to the user of the caller. - logUserSwitch(mLastUserId, userId); - LOG_ALWAYS_FATAL_IF(mLastUserId != DEFAULT_LAST_USER_ID, - "Invalid state: Should never update user ID here unless was default"); - mLastUserId = userId; - } // Check the shim parameters after acquiring lock, if they have already been updated and // we were doing a shim update, return immediately |