blob: 4b63704d4edd3ff643f8c4368bf6b1e011bda3d7 [file] [log] [blame]
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "AttributionAndPermissionUtils"
#define ATRACE_TAG ATRACE_TAG_CAMERA
#include "AttributionAndPermissionUtils.h"
#include <binder/AppOpsManager.h>
#include <binder/PermissionController.h>
#include <com_android_internal_camera_flags.h>
#include <cutils/properties.h>
#include <private/android_filesystem_config.h>
#include "CameraService.h"
#include <binder/IPCThreadState.h>
#include <binderthreadstate/CallerUtils.h>
#include <hwbinder/IPCThreadState.h>
namespace {
using android::content::AttributionSourceState;
static const std::string kPermissionServiceName = "permission";
static std::string getAttributionString(const AttributionSourceState& attributionSource) {
std::ostringstream ret;
const AttributionSourceState* current = &attributionSource;
while (current != nullptr) {
if (current != &attributionSource) {
ret << ", ";
}
ret << "[uid " << current->uid << ", pid " << current->pid;
ret << ", packageName \"" << current->packageName.value_or("<unknown>");
ret << "\"]";
if (!current->next.empty()) {
current = &current->next[0];
} else {
current = nullptr;
}
}
return ret.str();
}
} // namespace
namespace android {
namespace flags = com::android::internal::camera::flags;
const std::string AttributionAndPermissionUtils::sDumpPermission("android.permission.DUMP");
const std::string AttributionAndPermissionUtils::sManageCameraPermission(
"android.permission.MANAGE_CAMERA");
const std::string AttributionAndPermissionUtils::sCameraPermission("android.permission.CAMERA");
const std::string AttributionAndPermissionUtils::sSystemCameraPermission(
"android.permission.SYSTEM_CAMERA");
const std::string AttributionAndPermissionUtils::sCameraHeadlessSystemUserPermission(
"android.permission.CAMERA_HEADLESS_SYSTEM_USER");
const std::string AttributionAndPermissionUtils::sCameraPrivacyAllowlistPermission(
"android.permission.CAMERA_PRIVACY_ALLOWLIST");
const std::string AttributionAndPermissionUtils::sCameraSendSystemEventsPermission(
"android.permission.CAMERA_SEND_SYSTEM_EVENTS");
const std::string AttributionAndPermissionUtils::sCameraOpenCloseListenerPermission(
"android.permission.CAMERA_OPEN_CLOSE_LISTENER");
const std::string AttributionAndPermissionUtils::sCameraInjectExternalCameraPermission(
"android.permission.CAMERA_INJECT_EXTERNAL_CAMERA");
int AttributionAndPermissionUtils::getCallingUid() const {
if (getCurrentServingCall() == BinderCallType::HWBINDER) {
return hardware::IPCThreadState::self()->getCallingUid();
}
return IPCThreadState::self()->getCallingUid();
}
int AttributionAndPermissionUtils::getCallingPid() const {
if (getCurrentServingCall() == BinderCallType::HWBINDER) {
return hardware::IPCThreadState::self()->getCallingPid();
}
return IPCThreadState::self()->getCallingPid();
}
int64_t AttributionAndPermissionUtils::clearCallingIdentity() {
if (getCurrentServingCall() == BinderCallType::HWBINDER) {
return hardware::IPCThreadState::self()->clearCallingIdentity();
}
return IPCThreadState::self()->clearCallingIdentity();
}
void AttributionAndPermissionUtils::restoreCallingIdentity(int64_t token) {
if (getCurrentServingCall() == BinderCallType::HWBINDER) {
hardware::IPCThreadState::self()->restoreCallingIdentity(token);
} else {
IPCThreadState::self()->restoreCallingIdentity(token);
}
return;
}
binder::Status AttributionAndPermissionUtils::resolveAttributionSource(
/*inout*/ AttributionSourceState& resolvedAttributionSource, const std::string& methodName,
const std::optional<std::string>& cameraIdMaybe) {
// Check if we can trust clientUid
if (!resolveClientUid(resolvedAttributionSource.uid)) {
return errorNotTrusted(resolvedAttributionSource.pid, resolvedAttributionSource.uid,
methodName, cameraIdMaybe, *resolvedAttributionSource.packageName,
/* isPid= */ false);
}
resolveAttributionPackage(resolvedAttributionSource);
if (!resolveClientPid(resolvedAttributionSource.pid)) {
return errorNotTrusted(resolvedAttributionSource.pid, resolvedAttributionSource.uid,
methodName, cameraIdMaybe, *resolvedAttributionSource.packageName,
/* isPid= */ true);
}
return binder::Status::ok();
}
PermissionChecker::PermissionResult AttributionAndPermissionUtils::checkPermission(
const std::string& cameraId, const std::string& permission,
const AttributionSourceState& attributionSource, const std::string& message,
int32_t attributedOpCode, bool forDataDelivery, bool startDataDelivery,
bool checkAutomotive) {
AttributionSourceState clientAttribution = attributionSource;
if (!flags::check_full_attribution_source_chain() && !clientAttribution.next.empty()) {
clientAttribution.next.clear();
}
if (checkAutomotive && checkAutomotivePrivilegedClient(cameraId, clientAttribution)) {
return PermissionChecker::PERMISSION_GRANTED;
}
PermissionChecker::PermissionResult result;
if (forDataDelivery) {
if (startDataDelivery) {
result = mPermissionChecker->checkPermissionForStartDataDeliveryFromDatasource(
toString16(permission), clientAttribution, toString16(message),
attributedOpCode);
} else {
result = mPermissionChecker->checkPermissionForDataDeliveryFromDatasource(
toString16(permission), clientAttribution, toString16(message),
attributedOpCode);
}
} else {
result = mPermissionChecker->checkPermissionForPreflight(
toString16(permission), clientAttribution, toString16(message), attributedOpCode);
}
if (result == PermissionChecker::PERMISSION_HARD_DENIED) {
ALOGI("%s (forDataDelivery %d startDataDelivery %d): Permission hard denied "
"for client attribution %s",
__FUNCTION__, forDataDelivery, startDataDelivery,
getAttributionString(clientAttribution).c_str());
} else if (result == PermissionChecker::PERMISSION_SOFT_DENIED) {
ALOGI("%s checkPermission (forDataDelivery %d startDataDelivery %d): Permission soft "
"denied "
"for client attribution %s",
__FUNCTION__, forDataDelivery, startDataDelivery,
getAttributionString(clientAttribution).c_str());
}
return result;
}
bool AttributionAndPermissionUtils::checkPermissionForPreflight(
const std::string& cameraId, const std::string& permission,
const AttributionSourceState& attributionSource, const std::string& message,
int32_t attributedOpCode) {
return checkPermission(cameraId, permission, attributionSource, message, attributedOpCode,
/* forDataDelivery */ false, /* startDataDelivery */ false,
/* checkAutomotive */ true) != PermissionChecker::PERMISSION_HARD_DENIED;
}
bool AttributionAndPermissionUtils::checkPermissionForDataDelivery(
const std::string& cameraId, const std::string& permission,
const AttributionSourceState& attributionSource, const std::string& message,
int32_t attributedOpCode) {
return checkPermission(cameraId, permission, attributionSource, message, attributedOpCode,
/* forDataDelivery */ true, /* startDataDelivery */ false,
/* checkAutomotive */ false) !=
PermissionChecker::PERMISSION_HARD_DENIED;
}
PermissionChecker::PermissionResult
AttributionAndPermissionUtils::checkPermissionForStartDataDelivery(
const std::string& cameraId, const std::string& permission,
const AttributionSourceState& attributionSource, const std::string& message,
int32_t attributedOpCode) {
return checkPermission(cameraId, permission, attributionSource, message, attributedOpCode,
/* forDataDelivery */ true, /* startDataDelivery */ true,
/* checkAutomotive */ false);
}
// Can camera service trust the caller based on the calling UID?
bool AttributionAndPermissionUtils::isTrustedCallingUid(uid_t uid) {
switch (uid) {
case AID_MEDIA: // mediaserver
case AID_CAMERASERVER: // cameraserver
case AID_RADIO: // telephony
return true;
default:
return false;
}
}
bool AttributionAndPermissionUtils::isAutomotiveDevice() {
// Checks the property ro.hardware.type and returns true if it is
// automotive.
char value[PROPERTY_VALUE_MAX] = {0};
property_get("ro.hardware.type", value, "");
return strncmp(value, "automotive", PROPERTY_VALUE_MAX) == 0;
}
bool AttributionAndPermissionUtils::isHeadlessSystemUserMode() {
// Checks if the device is running in headless system user mode
// by checking the property ro.fw.mu.headless_system_user.
char value[PROPERTY_VALUE_MAX] = {0};
property_get("ro.fw.mu.headless_system_user", value, "");
return strncmp(value, "true", PROPERTY_VALUE_MAX) == 0;
}
bool AttributionAndPermissionUtils::isAutomotivePrivilegedClient(int32_t uid) {
// Returns false if this is not an automotive device type.
if (!isAutomotiveDevice()) return false;
// Returns true if the uid is AID_AUTOMOTIVE_EVS which is a
// privileged client uid used for safety critical use cases such as
// rear view and surround view.
return uid == AID_AUTOMOTIVE_EVS;
}
std::string AttributionAndPermissionUtils::getPackageNameFromUid(int clientUid) const {
std::string packageName("");
sp<IPermissionController> permCtrl = getPermissionController();
if (permCtrl == nullptr) {
// Return empty package name and the further interaction
// with camera will likely fail
return packageName;
}
Vector<String16> packages;
permCtrl->getPackagesForUid(clientUid, packages);
if (packages.isEmpty()) {
ALOGE("No packages for calling UID %d", clientUid);
// Return empty package name and the further interaction
// with camera will likely fail
return packageName;
}
// Arbitrarily pick the first name in the list
packageName = toStdString(packages[0]);
return packageName;
}
status_t AttributionAndPermissionUtils::getUidForPackage(const std::string& packageName, int userId,
/*inout*/ uid_t& uid, int err) {
PermissionController pc;
uid = pc.getPackageUid(toString16(packageName), 0);
if (uid <= 0) {
ALOGE("Unknown package: '%s'", packageName.c_str());
dprintf(err, "Unknown package: '%s'\n", packageName.c_str());
return BAD_VALUE;
}
if (userId < 0) {
ALOGE("Invalid user: %d", userId);
dprintf(err, "Invalid user: %d\n", userId);
return BAD_VALUE;
}
uid = multiuser_get_uid(userId, uid);
return NO_ERROR;
}
bool AttributionAndPermissionUtils::isCallerCameraServerNotDelegating() {
return (getCallingPid() == getpid());
}
bool AttributionAndPermissionUtils::hasPermissionsForCamera(
const std::string& cameraId, const AttributionSourceState& attributionSource,
bool forDataDelivery, bool checkAutomotive) {
return checkPermission(cameraId, sCameraPermission, attributionSource, std::string(),
AppOpsManager::OP_NONE, forDataDelivery, /* startDataDelivery */ false,
checkAutomotive) != PermissionChecker::PERMISSION_HARD_DENIED;
}
PermissionChecker::PermissionResult
AttributionAndPermissionUtils::checkPermissionsForCameraForPreflight(
const std::string& cameraId, const AttributionSourceState& attributionSource) {
return checkPermission(cameraId, sCameraPermission, attributionSource, std::string(),
AppOpsManager::OP_NONE, /* forDataDelivery */ false,
/* startDataDelivery */ false, /* checkAutomotive */ false);
}
PermissionChecker::PermissionResult
AttributionAndPermissionUtils::checkPermissionsForCameraForDataDelivery(
const std::string& cameraId, const AttributionSourceState& attributionSource) {
return checkPermission(cameraId, sCameraPermission, attributionSource, std::string(),
AppOpsManager::OP_NONE, /* forDataDelivery */ true,
/* startDataDelivery */ false, /* checkAutomotive */ false);
}
PermissionChecker::PermissionResult
AttributionAndPermissionUtils::checkPermissionsForCameraForStartDataDelivery(
const std::string& cameraId, const AttributionSourceState& attributionSource) {
return checkPermission(cameraId, sCameraPermission, attributionSource, std::string(),
AppOpsManager::OP_NONE, /* forDataDelivery */ true,
/* startDataDelivery */ true, /* checkAutomotive */ false);
}
bool AttributionAndPermissionUtils::hasPermissionsForSystemCamera(
const std::string& cameraId, const AttributionSourceState& attributionSource,
bool checkCameraPermissions) {
bool systemCameraPermission =
checkPermissionForPreflight(cameraId, sSystemCameraPermission, attributionSource,
std::string(), AppOpsManager::OP_NONE);
return systemCameraPermission &&
(!checkCameraPermissions || hasPermissionsForCamera(cameraId, attributionSource));
}
bool AttributionAndPermissionUtils::hasPermissionsForCameraHeadlessSystemUser(
const std::string& cameraId, const AttributionSourceState& attributionSource) {
return checkPermissionForPreflight(cameraId, sCameraHeadlessSystemUserPermission,
attributionSource, std::string(), AppOpsManager::OP_NONE);
}
bool AttributionAndPermissionUtils::hasPermissionsForCameraPrivacyAllowlist(
const AttributionSourceState& attributionSource) {
return checkPermissionForPreflight(std::string(), sCameraPrivacyAllowlistPermission,
attributionSource, std::string(), AppOpsManager::OP_NONE);
}
bool AttributionAndPermissionUtils::hasPermissionsForOpenCloseListener(
const AttributionSourceState& attributionSource) {
return checkPermissionForPreflight(std::string(), sCameraOpenCloseListenerPermission,
attributionSource, std::string(), AppOpsManager::OP_NONE);
}
void AttributionAndPermissionUtils::finishDataDelivery(
const AttributionSourceState& attributionSource) {
mPermissionChecker->finishDataDeliveryFromDatasource(AppOpsManager::OP_CAMERA,
attributionSource);
}
bool AttributionAndPermissionUtils::checkAutomotivePrivilegedClient(
const std::string& cameraId, const AttributionSourceState& attributionSource) {
if (isAutomotivePrivilegedClient(attributionSource.uid)) {
// If cameraId is empty, then it means that this check is not used for the
// purpose of accessing a specific camera, hence grant permission just
// based on uid to the automotive privileged client.
if (cameraId.empty()) return true;
auto cameraService = mCameraService.promote();
if (cameraService == nullptr) {
ALOGE("%s: CameraService unavailable.", __FUNCTION__);
return false;
}
// If this call is used for accessing a specific camera then cam_id must be provided.
// In that case, only pre-grants the permission for accessing the exterior system only
// camera.
return cameraService->isAutomotiveExteriorSystemCamera(cameraId);
}
return false;
}
void AttributionAndPermissionUtils::resolveAttributionPackage(
AttributionSourceState& resolvedAttributionSource) {
if (resolvedAttributionSource.packageName.has_value() &&
resolvedAttributionSource.packageName->size() > 0) {
return;
}
// NDK calls don't come with package names, but we need one for various cases.
// Generally, there's a 1:1 mapping between UID and package name, but shared UIDs
// do exist. For all authentication cases, all packages under the same UID get the
// same permissions, so picking any associated package name is sufficient. For some
// other cases, this may give inaccurate names for clients in logs.
resolvedAttributionSource.packageName = getPackageNameFromUid(resolvedAttributionSource.uid);
}
// TODO(362551824): Make USE_CALLING_UID more explicit with a scoped enum.
bool AttributionAndPermissionUtils::resolveClientUid(/*inout*/ int& clientUid) {
int callingUid = getCallingUid();
bool validUid = true;
if (clientUid == hardware::ICameraService::USE_CALLING_UID) {
clientUid = callingUid;
} else {
validUid = isTrustedCallingUid(callingUid);
if (flags::use_context_attribution_source()) {
validUid = validUid || (clientUid == callingUid);
}
}
return validUid;
}
// TODO(362551824): Make USE_CALLING_UID more explicit with a scoped enum.
bool AttributionAndPermissionUtils::resolveClientPid(/*inout*/ int& clientPid) {
int callingUid = getCallingUid();
int callingPid = getCallingPid();
bool validPid = true;
if (clientPid == hardware::ICameraService::USE_CALLING_PID) {
clientPid = callingPid;
} else {
validPid = isTrustedCallingUid(callingUid);
if (flags::use_context_attribution_source()) {
validPid = validPid || (clientPid == callingPid);
}
}
return validPid;
}
binder::Status AttributionAndPermissionUtils::errorNotTrusted(
int clientPid, int clientUid, const std::string& methodName,
const std::optional<std::string>& cameraIdMaybe, const std::string& clientName,
bool isPid) const {
int callingPid = getCallingPid();
int callingUid = getCallingUid();
ALOGE("CameraService::%s X (calling PID %d, calling UID %d) rejected "
"(don't trust %s %d)",
methodName.c_str(), callingPid, callingUid, isPid ? "clientPid" : "clientUid",
isPid ? clientPid : clientUid);
return STATUS_ERROR_FMT(hardware::ICameraService::ERROR_PERMISSION_DENIED,
"Untrusted caller (calling PID %d, UID %d) trying to "
"forward camera access to camera %s for client %s (PID %d, UID %d)",
getCallingPid(), getCallingUid(), cameraIdMaybe.value_or("N/A").c_str(),
clientName.c_str(), clientPid, clientUid);
}
const sp<IPermissionController>& AttributionAndPermissionUtils::getPermissionController() const {
static const char* kPermissionControllerService = "permission";
static thread_local sp<IPermissionController> sPermissionController = nullptr;
if (sPermissionController == nullptr ||
!IInterface::asBinder(sPermissionController)->isBinderAlive()) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->checkService(toString16(kPermissionControllerService));
if (binder == nullptr) {
ALOGE("%s: Could not get permission service", __FUNCTION__);
sPermissionController = nullptr;
} else {
sPermissionController = interface_cast<IPermissionController>(binder);
}
}
return sPermissionController;
}
} // namespace android