Introduce an API to verify trusted caller apps by UID.
This CL introduces a new function to make sure only trusted packages
like VrCore can make use of APIs that are not intended for app use.
As a first example, this CL introduces a caller check for taking screenshots,
although any sensitive APIs should implement similar checks.
Package trust is defined by having the RESTRICTED_VR_ACCESS permission.
Bug: 34474022
Change-Id: Ib5a242d1a4e17f59b178fb1465064043613ac369
diff --git a/libs/vr/libvr_manager/Android.mk b/libs/vr/libvr_manager/Android.mk
new file mode 100644
index 0000000..e9987f7
--- /dev/null
+++ b/libs/vr/libvr_manager/Android.mk
@@ -0,0 +1,42 @@
+# Copyright (C) 2017 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.
+
+LOCAL_PATH := $(call my-dir)
+
+exported_include_dirs := \
+ $(LOCAL_PATH)/include
+
+include_dirs := \
+ frameworks/native/include/vr/vr_manager \
+ $(exported_include_dirs)
+
+src_files := \
+ vr_manager.cpp \
+ trusted_uids.cpp
+
+static_libs := \
+ libutils \
+ libbinder \
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(src_files)
+LOCAL_C_INCLUDES := $(include_dirs)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(exported_include_dirs)
+LOCAL_CFLAGS += -Wall
+LOCAL_CFLAGS += -Werror
+LOCAL_CFLAGS += -Wunused
+LOCAL_CFLAGS += -Wunreachable-code
+LOCAL_STATIC_LIBRARIES := $(static_libs)
+LOCAL_MODULE := libvr_manager
+include $(BUILD_STATIC_LIBRARY)
diff --git a/libs/vr/libvr_manager/include/private/dvr/trusted_uids.h b/libs/vr/libvr_manager/include/private/dvr/trusted_uids.h
new file mode 100644
index 0000000..4496fbf
--- /dev/null
+++ b/libs/vr/libvr_manager/include/private/dvr/trusted_uids.h
@@ -0,0 +1,33 @@
+#ifndef ANDROID_DVR_TRUSTED_UIDS_H_
+#define ANDROID_DVR_TRUSTED_UIDS_H_
+
+#include <sys/types.h>
+
+namespace android {
+namespace dvr {
+
+/**
+ * Tells if a provided UID can be trusted to access restricted VR APIs.
+ *
+ * UID trust is based on the android.permission.RESTRICTED_VR_ACCESS permission.
+ * AID_SYSTEM and AID_ROOT are automatically trusted by Android.
+ *
+ * UIDs are guaranteed not to be reused until the next reboot even in case
+ * of package reinstall. For performance reasons this method caches results by
+ * default, as otherwise every check would trigger a Java call.
+ *
+ * This function is thread-safe.
+ *
+ * @param uid The uid to check.
+ * @param use_cache If true any cached result for the provided uid will be
+ * reused. If false this call will reach the Application Manager Service
+ * in Java to get updated values. Any updates will be stored in the cache.
+ * @return true if the uid is trusted, false if not or if the VR Manager Service
+ * could not be reached to verify the uid.
+ */
+bool IsTrustedUid(uid_t uid, bool use_cache = true);
+
+} // namespace dvr
+} // namespace android
+
+#endif // ANDROID_DVR_TRUSTED_UIDS_H_
diff --git a/libs/vr/libvr_manager/trusted_uids.cpp b/libs/vr/libvr_manager/trusted_uids.cpp
new file mode 100644
index 0000000..4228a05
--- /dev/null
+++ b/libs/vr/libvr_manager/trusted_uids.cpp
@@ -0,0 +1,51 @@
+#include "private/dvr/trusted_uids.h"
+
+#include <mutex>
+#include <unordered_map>
+
+#include <binder/IPermissionController.h>
+#include <binder/IServiceManager.h>
+#include <private/android_filesystem_config.h>
+#include <utils/String16.h>
+#include <vr/vr_manager/vr_manager.h>
+
+namespace android {
+namespace dvr {
+
+bool IsTrustedUid(uid_t uid, bool use_cache) {
+ static std::unordered_map<uid_t, bool> uid_cache;
+ static std::mutex uid_cache_mutex;
+
+ // Whitelist requests from the system UID.
+ // These are already whitelisted by the permission service, but it might not
+ // be available if the ActivityManagerService is up during boot.
+ // This ensures the correct result for system services while booting up.
+ if (uid == AID_SYSTEM)
+ return true;
+
+ std::lock_guard<std::mutex> lock(uid_cache_mutex);
+
+ if (use_cache) {
+ auto it = uid_cache.find(uid);
+ if (it != uid_cache.end())
+ return it->second;
+ }
+
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
+ if (binder == 0) {
+ ALOGW("Could not access permission service");
+ return false;
+ }
+
+ // Note: we ignore the pid because it's only used to automatically reply
+ // true if the caller is the Activity Manager Service.
+ bool trusted = interface_cast<IPermissionController>(binder)->checkPermission(
+ String16("android.permission.RESTRICTED_VR_ACCESS"), -1, uid);
+
+ // Cache the information for this uid to avoid future Java calls.
+ uid_cache[uid] = trusted;
+ return trusted;
+}
+
+} // namespace dvr
+} // namespace android
diff --git a/libs/vr/libvr_manager/vr_manager.cpp b/libs/vr/libvr_manager/vr_manager.cpp
new file mode 100644
index 0000000..d24cbb5
--- /dev/null
+++ b/libs/vr/libvr_manager/vr_manager.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 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 "VrManager"
+#include <utils/Log.h>
+
+#include <vr/vr_manager/vr_manager.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+// Must be kept in sync with interface defined in IVrStateCallbacks.aidl.
+
+class BpVrStateCallbacks : public BpInterface<IVrStateCallbacks> {
+ public:
+ explicit BpVrStateCallbacks(const sp<IBinder>& impl)
+ : BpInterface<IVrStateCallbacks>(impl) {}
+
+ void onVrStateChanged(bool enabled) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IVrStateCallbacks::getInterfaceDescriptor());
+ data.writeBool(enabled);
+ remote()->transact(ON_VR_STATE_CHANGED, data, &reply, IBinder::FLAG_ONEWAY);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(VrStateCallbacks, "android.service.vr.IVrStateCallbacks");
+
+status_t BnVrStateCallbacks::onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags) {
+ switch(code) {
+ case ON_VR_STATE_CHANGED: {
+ CHECK_INTERFACE(IVrStateCallbacks, data, reply);
+ onVrStateChanged(data.readBool());
+ return OK;
+ }
+ }
+ return BBinder::onTransact(code, data, reply, flags);
+}
+
+// Must be kept in sync with interface defined in IVrManager.aidl.
+
+class BpVrManager : public BpInterface<IVrManager> {
+ public:
+ explicit BpVrManager(const sp<IBinder>& impl)
+ : BpInterface<IVrManager>(impl) {}
+
+ void registerListener(const sp<IVrStateCallbacks>& cb) override {
+ Parcel data;
+ data.writeInterfaceToken(IVrManager::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(cb));
+ remote()->transact(REGISTER_LISTENER, data, NULL);
+ }
+
+ void unregisterListener(const sp<IVrStateCallbacks>& cb) override {
+ Parcel data;
+ data.writeInterfaceToken(IVrManager::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(cb));
+ remote()->transact(UNREGISTER_LISTENER, data, NULL);
+ }
+
+ bool getVrModeState() override {
+ Parcel data, reply;
+ data.writeInterfaceToken(IVrManager::getInterfaceDescriptor());
+ remote()->transact(GET_VR_MODE_STATE, data, &reply);
+ int32_t ret = reply.readExceptionCode();
+ if (ret != 0) {
+ return false;
+ }
+ return reply.readBool();
+ }
+};
+
+IMPLEMENT_META_INTERFACE(VrManager, "android.service.vr.IVrManager");
+
+} // namespace android
diff --git a/libs/vr/libvrflinger/Android.mk b/libs/vr/libvrflinger/Android.mk
index 6b5e7cc..d90e85a 100644
--- a/libs/vr/libvrflinger/Android.mk
+++ b/libs/vr/libvrflinger/Android.mk
@@ -45,6 +45,7 @@
libperformance \
libsensor \
libpdx_default_transport \
+ libvr_manager \
sharedLibraries := \
android.dvr.composer@1.0 \
diff --git a/libs/vr/libvrflinger/screenshot_service.cpp b/libs/vr/libvrflinger/screenshot_service.cpp
index e174943..fd1c582 100644
--- a/libs/vr/libvrflinger/screenshot_service.cpp
+++ b/libs/vr/libvrflinger/screenshot_service.cpp
@@ -3,7 +3,9 @@
#include <utils/Trace.h>
#include <pdx/default_transport/service_endpoint.h>
+#include <private/android_filesystem_config.h>
#include <private/dvr/display_types.h>
+#include <private/dvr/trusted_uids.h>
using android::pdx::Message;
using android::pdx::MessageInfo;
@@ -40,6 +42,12 @@
ScreenshotData ScreenshotService::OnTakeScreenshot(pdx::Message& message,
int layer_index) {
+ // Also allow AID_SHELL to support vrscreencap commands.
+ if (message.GetEffectiveUserId() != AID_SHELL &&
+ !IsTrustedUid(message.GetEffectiveUserId())) {
+ REPLY_ERROR_RETURN(message, EACCES, {});
+ }
+
AddWaiter(std::move(message), layer_index);
return {};
}