From c85602db731ce1d0de9289b5d8a2af51d74f0916 Mon Sep 17 00:00:00 2001 From: Pierre Langlois Date: Wed, 11 Feb 2015 16:41:31 +0000 Subject: 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 --- include/kdbinder/binder/IPermissionController.h | 45 ++++++++++ include/kdbinder/binder/IServiceManager.h | 5 ++ include/kdbinder/binder/PermissionCache.h | 77 +++++++++++++++++ libs/kdbinder/Android.mk | 2 + libs/kdbinder/binder/IPermissionController.cpp | 71 ++++++++++++++++ libs/kdbinder/binder/IServiceManager.cpp | 12 +++ libs/kdbinder/binder/PermissionCache.cpp | 107 ++++++++++++++++++++++++ 7 files changed, 319 insertions(+) create mode 100644 include/kdbinder/binder/IPermissionController.h create mode 100644 include/kdbinder/binder/PermissionCache.h create mode 100644 libs/kdbinder/binder/IPermissionController.cpp create mode 100644 libs/kdbinder/binder/PermissionCache.cpp 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 + +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 { + 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* 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 +#include + +#include +#include +#include + +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 { + 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 + +#include +#include +#include + +#include + +namespace android { + +class BpPermissionController : public BpInterface { + public: + explicit BpPermissionController(const sp& impl) + : BpInterface(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 { public: explicit BpServiceManager(const sp& 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 +#include +#include +#include +#include +#include + +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 -- cgit v1.2.3