diff options
-rw-r--r-- | include/binder/Permission.h | 68 | ||||
-rw-r--r-- | include/binder/PermissionCache.h | 79 | ||||
-rw-r--r-- | libs/binder/Android.mk | 2 | ||||
-rw-r--r-- | libs/binder/Permission.cpp | 88 | ||||
-rw-r--r-- | libs/binder/PermissionCache.cpp | 113 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 26 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 17 |
7 files changed, 215 insertions, 178 deletions
diff --git a/include/binder/Permission.h b/include/binder/Permission.h deleted file mode 100644 index 9542d50..0000000 --- a/include/binder/Permission.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2009 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 BINDER_PERMISSION_H -#define BINDER_PERMISSION_H - -#include <stdint.h> -#include <unistd.h> - -#include <utils/SortedVector.h> -#include <utils/String16.h> -#include <utils/threads.h> - -namespace android { -// --------------------------------------------------------------------------- - -/* - * Permission caches the result of the permission check for the given - * permission name and the provided uid/pid. It also handles a few - * known cases efficiently (caller is in the same process or is root). - * The package manager does something similar but lives in dalvik world - * and is therefore extremely slow to access. - */ - -class Permission -{ -public: - Permission(char const* name); - Permission(const String16& name); - Permission(const Permission& rhs); - virtual ~Permission(); - - bool operator < (const Permission& rhs) const; - - // checks the current binder call's caller has access to this permission - bool checkCalling() const; - - // checks the specified pid/uid has access to this permission - bool check(pid_t pid, uid_t uid) const; - -protected: - virtual bool doCheckPermission(pid_t pid, uid_t uid) const; - -private: - Permission& operator = (const Permission& rhs) const; - const String16 mPermissionName; - mutable SortedVector<uid_t> mGranted; - const pid_t mPid; - mutable Mutex mLock; -}; - -// --------------------------------------------------------------------------- -}; // namespace android - -#endif /* BINDER_PERMISSION_H */ diff --git a/include/binder/PermissionCache.h b/include/binder/PermissionCache.h new file mode 100644 index 0000000..1171d48 --- /dev/null +++ b/include/binder/PermissionCache.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2009 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 BINDER_PERMISSION_H +#define BINDER_PERMISSION_H + +#include <stdint.h> +#include <unistd.h> + +#include <utils/String16.h> +#include <utils/Singleton.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 /* BINDER_PERMISSION_H */ diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk index f9d9f25..3a12e96 100644 --- a/libs/binder/Android.mk +++ b/libs/binder/Android.mk @@ -27,7 +27,7 @@ sources := \ MemoryHeapBase.cpp \ MemoryHeapPmem.cpp \ Parcel.cpp \ - Permission.cpp \ + PermissionCache.cpp \ ProcessState.cpp \ Static.cpp diff --git a/libs/binder/Permission.cpp b/libs/binder/Permission.cpp deleted file mode 100644 index fd8fe69..0000000 --- a/libs/binder/Permission.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -#include <stdint.h> -#include <utils/Log.h> -#include <binder/IPCThreadState.h> -#include <binder/IServiceManager.h> -#include <binder/Permission.h> - -namespace android { -// --------------------------------------------------------------------------- - -Permission::Permission(char const* name) - : mPermissionName(name), mPid(getpid()) -{ -} - -Permission::Permission(const String16& name) - : mPermissionName(name), mPid(getpid()) -{ -} - -Permission::Permission(const Permission& rhs) - : mPermissionName(rhs.mPermissionName), - mGranted(rhs.mGranted), - mPid(rhs.mPid) -{ -} - -Permission::~Permission() -{ -} - -bool Permission::operator < (const Permission& rhs) const -{ - return mPermissionName < rhs.mPermissionName; -} - -bool Permission::checkCalling() const -{ - IPCThreadState* ipcState = IPCThreadState::self(); - pid_t pid = ipcState->getCallingPid(); - uid_t uid = ipcState->getCallingUid(); - return doCheckPermission(pid, uid); -} - -bool Permission::check(pid_t pid, uid_t uid) const -{ - return doCheckPermission(pid, uid); -} - -bool Permission::doCheckPermission(pid_t pid, uid_t uid) const -{ - if ((uid == 0) || (pid == mPid)) { - // root and ourselves is always okay - return true; - } else { - // see if we already granted this permission for this uid - Mutex::Autolock _l(mLock); - if (mGranted.indexOf(uid) >= 0) - return true; - } - - bool granted = checkPermission(mPermissionName, pid, uid); - if (granted) { - Mutex::Autolock _l(mLock); - // no need to check again, the old item will be replaced if it is - // already there. - mGranted.add(uid); - } - return granted; -} - -// --------------------------------------------------------------------------- -}; // namespace android diff --git a/libs/binder/PermissionCache.cpp b/libs/binder/PermissionCache.cpp new file mode 100644 index 0000000..7278187 --- /dev/null +++ b/libs/binder/PermissionCache.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2009 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(); + LOGD("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 diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 97edfee..f0b19f2 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -32,6 +32,7 @@ #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/MemoryHeapBase.h> +#include <binder/PermissionCache.h> #include <utils/String8.h> #include <utils/String16.h> @@ -67,6 +68,13 @@ namespace android { // --------------------------------------------------------------------------- +const String16 sHardwareTest("android.permission.HARDWARE_TEST"); +const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"); +const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER"); +const String16 sDump("android.permission.DUMP"); + +// --------------------------------------------------------------------------- + SurfaceFlinger::SurfaceFlinger() : BnSurfaceComposer(), Thread(false), mTransactionFlags(0), @@ -74,10 +82,6 @@ SurfaceFlinger::SurfaceFlinger() mResizeTransationPending(false), mLayersRemoved(false), mBootTime(systemTime()), - mHardwareTest("android.permission.HARDWARE_TEST"), - mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"), - mReadFramebuffer("android.permission.READ_FRAME_BUFFER"), - mDump("android.permission.DUMP"), mVisibleRegionsDirty(false), mHwWorkListDirty(false), mDeferReleaseConsole(false), @@ -1464,7 +1468,8 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) const size_t SIZE = 4096; char buffer[SIZE]; String8 result; - if (!mDump.checkCalling()) { + + if (!PermissionCache::checkCallingPermission(sDump)) { snprintf(buffer, SIZE, "Permission Denial: " "can't dump SurfaceFlinger from pid=%d, uid=%d\n", IPCThreadState::self()->getCallingPid(), @@ -1596,7 +1601,8 @@ status_t SurfaceFlinger::onTransact( IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); - if ((uid != AID_GRAPHICS) && !mAccessSurfaceFlinger.check(pid, uid)) { + if ((uid != AID_GRAPHICS) && + !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) { LOGE("Permission Denial: " "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); return PERMISSION_DENIED; @@ -1609,7 +1615,8 @@ status_t SurfaceFlinger::onTransact( IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); - if ((uid != AID_GRAPHICS) && !mReadFramebuffer.check(pid, uid)) { + if ((uid != AID_GRAPHICS) && + !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { LOGE("Permission Denial: " "can't read framebuffer pid=%d, uid=%d", pid, uid); return PERMISSION_DENIED; @@ -1621,7 +1628,7 @@ status_t SurfaceFlinger::onTransact( status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags); if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) { CHECK_INTERFACE(ISurfaceComposer, data, reply); - if (UNLIKELY(!mHardwareTest.checkCalling())) { + if (UNLIKELY(!PermissionCache::checkCallingPermission(sHardwareTest))) { IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); @@ -2404,8 +2411,7 @@ status_t Client::onTransact( const int self_pid = getpid(); if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) { // we're called from a different process, do the real check - if (!checkCallingPermission( - String16("android.permission.ACCESS_SURFACE_FLINGER"))) + if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger)) { LOGE("Permission Denial: " "can't openGlobalTransaction pid=%d, uid=%d", pid, uid); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index af1ef04..45f80ae 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -20,21 +20,20 @@ #include <stdint.h> #include <sys/types.h> -#include <utils/SortedVector.h> -#include <utils/KeyedVector.h> -#include <utils/threads.h> #include <utils/Atomic.h> #include <utils/Errors.h> +#include <utils/KeyedVector.h> #include <utils/RefBase.h> +#include <utils/SortedVector.h> +#include <utils/threads.h> -#include <binder/IMemory.h> -#include <binder/Permission.h> #include <binder/BinderService.h> +#include <binder/IMemory.h> #include <ui/PixelFormat.h> +#include <surfaceflinger/IGraphicBufferAlloc.h> #include <surfaceflinger/ISurfaceComposer.h> #include <surfaceflinger/ISurfaceComposerClient.h> -#include <surfaceflinger/IGraphicBufferAlloc.h> #include "Barrier.h" #include "Layer.h" @@ -353,11 +352,7 @@ private: surface_flinger_cblk_t* mServerCblk; GLuint mWormholeTexName; nsecs_t mBootTime; - Permission mHardwareTest; - Permission mAccessSurfaceFlinger; - Permission mReadFramebuffer; - Permission mDump; - + // Can only accessed from the main thread, these members // don't need synchronization State mDrawingState; |