aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre Langlois <pierre.langlois@arm.com>2015-02-11 16:41:31 +0000
committerPierre Langlois <pierre.langlois@arm.com>2016-03-04 18:01:17 +0000
commitc85602db731ce1d0de9289b5d8a2af51d74f0916 (patch)
treeabc113ed3184e91d8f0a7bf9a5b9ec4a07320bd6
parentfaa15a27bff96bebe6e522c8c6662fef10f6a55d (diff)
downloadkdbinder-c85602db731ce1d0de9289b5d8a2af51d74f0916.tar.gz
libkdbinder: import IPermissionController and PermissionCache
These are imported as they are in libbinder as they are just a IInterface to check for permissions. The actual implementation is in IServiceManager and is left unimplemented for now. Change-Id: Ifedd45d142839bac0f13920e1d898412046003e2
-rw-r--r--include/kdbinder/binder/IPermissionController.h45
-rw-r--r--include/kdbinder/binder/IServiceManager.h5
-rw-r--r--include/kdbinder/binder/PermissionCache.h77
-rw-r--r--libs/kdbinder/Android.mk2
-rw-r--r--libs/kdbinder/binder/IPermissionController.cpp71
-rw-r--r--libs/kdbinder/binder/IServiceManager.cpp12
-rw-r--r--libs/kdbinder/binder/PermissionCache.cpp107
7 files changed, 319 insertions, 0 deletions
diff --git a/include/kdbinder/binder/IPermissionController.h b/include/kdbinder/binder/IPermissionController.h
new file mode 100644
index 0000000..c062955
--- /dev/null
+++ b/include/kdbinder/binder/IPermissionController.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+//
+#ifndef INCLUDE_KDBINDER_BINDER_IPERMISSIONCONTROLLER_H_
+#define INCLUDE_KDBINDER_BINDER_IPERMISSIONCONTROLLER_H_
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+class IPermissionController : public IInterface {
+ public:
+ DECLARE_META_INTERFACE(PermissionController);
+
+ virtual bool checkPermission(const String16& permission, int32_t pid,
+ int32_t uid) = 0;
+
+ enum {
+ CHECK_PERMISSION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
+ };
+};
+
+class BnPermissionController : public BnInterface<IPermissionController> {
+ public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0);
+};
+
+} // namespace android
+
+#endif // INCLUDE_KDBINDER_BINDER_IPERMISSIONCONTROLLER_H_
diff --git a/include/kdbinder/binder/IServiceManager.h b/include/kdbinder/binder/IServiceManager.h
index 3114884..3f91d60 100644
--- a/include/kdbinder/binder/IServiceManager.h
+++ b/include/kdbinder/binder/IServiceManager.h
@@ -64,6 +64,11 @@ status_t getService(const String16& name, sp<INTERFACE>* outService) {
return NAME_NOT_FOUND;
}
+bool checkCallingPermission(const String16& permission);
+bool checkCallingPermission(const String16& permission,
+ int32_t* outPid, int32_t* outUid);
+bool checkPermission(const String16& permission, pid_t pid, uid_t uid);
+
} // namespace android
#endif // INCLUDE_KDBINDER_BINDER_ISERVICEMANAGER_H_
diff --git a/include/kdbinder/binder/PermissionCache.h b/include/kdbinder/binder/PermissionCache.h
new file mode 100644
index 0000000..ad6c1f0
--- /dev/null
+++ b/include/kdbinder/binder/PermissionCache.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef INCLUDE_KDBINDER_BINDER_PERMISSIONCACHE_H_
+#define INCLUDE_KDBINDER_BINDER_PERMISSIONCACHE_H_
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include <utils/String16.h>
+#include <utils/Singleton.h>
+#include <utils/SortedVector.h>
+
+namespace android {
+
+/*
+ * PermissionCache caches permission checks for a given uid.
+ *
+ * Currently the cache is not updated when there is a permission change,
+ * for instance when an application is uninstalled.
+ *
+ * IMPORTANT: for the reason stated above, only system permissions are safe
+ * to cache. This restriction may be lifted at a later time.
+ *
+ */
+
+class PermissionCache : Singleton<PermissionCache> {
+ struct Entry {
+ String16 name;
+ uid_t uid;
+ bool granted;
+ inline bool operator < (const Entry& e) const {
+ return (uid == e.uid) ? (name < e.name) : (uid < e.uid);
+ }
+ };
+
+ mutable Mutex mLock;
+ // we pool all the permission names we see, as many permissions checks
+ // will have identical names
+ SortedVector< String16 > mPermissionNamesPool;
+ // this is our cache per say. it stores pooled names.
+ SortedVector< Entry > mCache;
+
+ // free the whole cache, but keep the permission name pool
+ void purge();
+
+ status_t check(bool* granted, const String16& permission, uid_t uid) const;
+
+ void cache(const String16& permission, uid_t uid, bool granted);
+
+ public:
+ PermissionCache();
+
+ static bool checkCallingPermission(const String16& permission);
+
+ static bool checkCallingPermission(const String16& permission,
+ int32_t* outPid, int32_t* outUid);
+
+ static bool checkPermission(const String16& permission, pid_t pid, uid_t uid);
+};
+
+} // namespace android
+
+#endif // INCLUDE_KDBINDER_BINDER_PERMISSIONCACHE_H_
diff --git a/libs/kdbinder/Android.mk b/libs/kdbinder/Android.mk
index e96b640..9217c91 100644
--- a/libs/kdbinder/Android.mk
+++ b/libs/kdbinder/Android.mk
@@ -21,6 +21,8 @@ kdbinder_sources := \
binder/Static.cpp \
binder/Parcel.cpp \
binder/IServiceManager.cpp \
+ binder/IPermissionController.cpp \
+ binder/PermissionCache.cpp \
kdbus/bus.cpp \
kdbus/connection.cpp \
kdbus/iterable.cpp \
diff --git a/libs/kdbinder/binder/IPermissionController.cpp b/libs/kdbinder/binder/IPermissionController.cpp
new file mode 100644
index 0000000..739873a
--- /dev/null
+++ b/libs/kdbinder/binder/IPermissionController.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 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 "PermissionController"
+
+#include <binder/IPermissionController.h>
+
+#include <utils/Log.h>
+#include <binder/Parcel.h>
+#include <utils/String8.h>
+
+#include <private/binder/Static.h>
+
+namespace android {
+
+class BpPermissionController : public BpInterface<IPermissionController> {
+ public:
+ explicit BpPermissionController(const sp<IBinder>& impl)
+ : BpInterface<IPermissionController>(impl) {}
+
+ virtual bool checkPermission(const String16& permission, int32_t pid,
+ int32_t uid) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IPermissionController::getInterfaceDescriptor());
+ data.writeString16(permission);
+ data.writeInt32(pid);
+ data.writeInt32(uid);
+ remote()->transact(CHECK_PERMISSION_TRANSACTION, data, &reply);
+ // fail on exception
+ if (reply.readExceptionCode() != 0) return 0;
+ return reply.readInt32() != 0;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(PermissionController,
+ "android.os.IPermissionController");
+
+status_t BnPermissionController::onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags) {
+ // printf("PermissionController received: "); data.print();
+ switch (code) {
+ case CHECK_PERMISSION_TRANSACTION: {
+ CHECK_INTERFACE(IPermissionController, data, reply);
+ String16 permission = data.readString16();
+ int32_t pid = data.readInt32();
+ int32_t uid = data.readInt32();
+ bool res = checkPermission(permission, pid, uid);
+ reply->writeNoException();
+ reply->writeInt32(res ? 1 : 0);
+ return NO_ERROR;
+ }
+ break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+} // namespace android
diff --git a/libs/kdbinder/binder/IServiceManager.cpp b/libs/kdbinder/binder/IServiceManager.cpp
index bbf1b54..67e0274 100644
--- a/libs/kdbinder/binder/IServiceManager.cpp
+++ b/libs/kdbinder/binder/IServiceManager.cpp
@@ -33,6 +33,18 @@
namespace android {
+bool checkCallingPermission(const String16& /*permission*/, int32_t* /*outPid*/,
+ int32_t* /*outUid*/) {
+ // TODO: unimplemented
+ return true;
+}
+
+bool checkPermission(const String16& /*permission*/, pid_t /*pid*/,
+ uid_t /*uid*/) {
+ // TODO: unimplemented
+ return true;
+}
+
class BpServiceManager : public BpInterface<IServiceManager> {
public:
explicit BpServiceManager(const sp<IBinder>& impl)
diff --git a/libs/kdbinder/binder/PermissionCache.cpp b/libs/kdbinder/binder/PermissionCache.cpp
new file mode 100644
index 0000000..ce4721d
--- /dev/null
+++ b/libs/kdbinder/binder/PermissionCache.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2015 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 "PermissionCache"
+
+#include <stdint.h>
+#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/PermissionCache.h>
+#include <utils/String8.h>
+
+namespace android {
+
+ANDROID_SINGLETON_STATIC_INSTANCE(PermissionCache);
+
+PermissionCache::PermissionCache() {}
+
+status_t PermissionCache::check(bool* granted, const String16& permission,
+ uid_t uid) const {
+ Mutex::Autolock _l(mLock);
+ Entry e;
+ e.name = permission;
+ e.uid = uid;
+ ssize_t index = mCache.indexOf(e);
+ if (index >= 0) {
+ *granted = mCache.itemAt(index).granted;
+ return NO_ERROR;
+ }
+ return NAME_NOT_FOUND;
+}
+
+void PermissionCache::cache(const String16& permission, uid_t uid,
+ bool granted) {
+ Mutex::Autolock _l(mLock);
+ Entry e;
+ ssize_t index = mPermissionNamesPool.indexOf(permission);
+ if (index > 0) {
+ e.name = mPermissionNamesPool.itemAt(index);
+ } else {
+ mPermissionNamesPool.add(permission);
+ e.name = permission;
+ }
+ // note, we don't need to store the pid, which is not actually used in
+ // permission checks
+ e.uid = uid;
+ e.granted = granted;
+ index = mCache.indexOf(e);
+ if (index < 0) {
+ mCache.add(e);
+ }
+}
+
+void PermissionCache::purge() {
+ Mutex::Autolock _l(mLock);
+ mCache.clear();
+}
+
+bool PermissionCache::checkCallingPermission(const String16& permission) {
+ return PermissionCache::checkCallingPermission(permission, NULL, NULL);
+}
+
+bool PermissionCache::checkCallingPermission(
+ const String16& permission, int32_t* outPid, int32_t* outUid) {
+ IPCThreadState* ipcState = IPCThreadState::self();
+ pid_t pid = ipcState->getCallingPid();
+ uid_t uid = ipcState->getCallingUid();
+ if (outPid) *outPid = pid;
+ if (outUid) *outUid = uid;
+ return PermissionCache::checkPermission(permission, pid, uid);
+}
+
+bool PermissionCache::checkPermission(const String16& permission, pid_t pid,
+ uid_t uid) {
+ if ((uid == 0) || (pid == getpid())) {
+ // root and ourselves is always okay
+ return true;
+ }
+
+ PermissionCache& pc(PermissionCache::getInstance());
+ bool granted = false;
+ if (pc.check(&granted, permission, uid) != NO_ERROR) {
+ nsecs_t t = -systemTime();
+ granted = android::checkPermission(permission, pid, uid);
+ t += systemTime();
+ ALOGD("checking %s for uid=%d => %s (%d us)",
+ String8(permission).string(), uid,
+ granted?"granted":"denied", (int)ns2us(t));
+ pc.cache(permission, uid, granted);
+ }
+ return granted;
+}
+
+} // namespace android