Loading include/binder/Permission.h→include/binder/PermissionCache.h +79 −0 Original line number Diff line number Diff line Loading @@ -20,46 +20,57 @@ #include <stdint.h> #include <unistd.h> #include <utils/SortedVector.h> #include <utils/String16.h> #include <utils/threads.h> #include <utils/Singleton.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. * 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 Permission { public: Permission(char const* name); Permission(const String16& name); Permission(const Permission& rhs); virtual ~Permission(); 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; bool operator < (const Permission& rhs) const; // free the whole cache, but keep the permission name pool void purge(); // checks the current binder call's caller has access to this permission bool checkCalling() const; status_t check(bool* granted, const String16& permission, uid_t uid) const; // checks the specified pid/uid has access to this permission bool check(pid_t pid, uid_t uid) const; void cache(const String16& permission, uid_t uid, bool granted); protected: virtual bool doCheckPermission(pid_t pid, uid_t uid) const; public: PermissionCache(); private: Permission& operator = (const Permission& rhs) const; const String16 mPermissionName; mutable SortedVector<uid_t> mGranted; const pid_t mPid; mutable Mutex mLock; 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); }; // --------------------------------------------------------------------------- Loading libs/binder/Android.mk +1 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ sources := \ MemoryHeapBase.cpp \ MemoryHeapPmem.cpp \ Parcel.cpp \ Permission.cpp \ PermissionCache.cpp \ ProcessState.cpp \ Static.cpp Loading libs/binder/Permission.cpp→libs/binder/PermissionCache.cpp +113 −0 Original line number Diff line number Diff line Loading @@ -14,72 +14,97 @@ * 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/Permission.h> #include <binder/PermissionCache.h> #include <utils/String8.h> namespace android { // --------------------------------------------------------------------------- Permission::Permission(char const* name) : mPermissionName(name), mPid(getpid()) { // ---------------------------------------------------------------------------- ANDROID_SINGLETON_STATIC_INSTANCE(PermissionCache) ; // ---------------------------------------------------------------------------- PermissionCache::PermissionCache() { } Permission::Permission(const String16& name) : mPermissionName(name), mPid(getpid()) { 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; } Permission::Permission(const Permission& rhs) : mPermissionName(rhs.mPermissionName), mGranted(rhs.mGranted), mPid(rhs.mPid) { 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); } } Permission::~Permission() { void PermissionCache::purge() { Mutex::Autolock _l(mLock); mCache.clear(); } bool Permission::operator < (const Permission& rhs) const { return mPermissionName < rhs.mPermissionName; bool PermissionCache::checkCallingPermission(const String16& permission) { return PermissionCache::checkCallingPermission(permission, NULL, NULL); } bool Permission::checkCalling() const { 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(); return doCheckPermission(pid, uid); } bool Permission::check(pid_t pid, uid_t uid) const { return doCheckPermission(pid, uid); if (outPid) *outPid = pid; if (outUid) *outUid = uid; return PermissionCache::checkPermission(permission, pid, uid); } bool Permission::doCheckPermission(pid_t pid, uid_t uid) const { if ((uid == 0) || (pid == mPid)) { 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; } 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); 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; } Loading services/surfaceflinger/SurfaceFlinger.cpp +16 −10 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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), Loading @@ -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), Loading Loading @@ -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(), Loading Loading @@ -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; Loading @@ -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; Loading @@ -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(); Loading Loading @@ -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); Loading services/surfaceflinger/SurfaceFlinger.h +6 −11 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -353,10 +352,6 @@ 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 Loading Loading
include/binder/Permission.h→include/binder/PermissionCache.h +79 −0 Original line number Diff line number Diff line Loading @@ -20,46 +20,57 @@ #include <stdint.h> #include <unistd.h> #include <utils/SortedVector.h> #include <utils/String16.h> #include <utils/threads.h> #include <utils/Singleton.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. * 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 Permission { public: Permission(char const* name); Permission(const String16& name); Permission(const Permission& rhs); virtual ~Permission(); 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; bool operator < (const Permission& rhs) const; // free the whole cache, but keep the permission name pool void purge(); // checks the current binder call's caller has access to this permission bool checkCalling() const; status_t check(bool* granted, const String16& permission, uid_t uid) const; // checks the specified pid/uid has access to this permission bool check(pid_t pid, uid_t uid) const; void cache(const String16& permission, uid_t uid, bool granted); protected: virtual bool doCheckPermission(pid_t pid, uid_t uid) const; public: PermissionCache(); private: Permission& operator = (const Permission& rhs) const; const String16 mPermissionName; mutable SortedVector<uid_t> mGranted; const pid_t mPid; mutable Mutex mLock; 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); }; // --------------------------------------------------------------------------- Loading
libs/binder/Android.mk +1 −1 Original line number Diff line number Diff line Loading @@ -27,7 +27,7 @@ sources := \ MemoryHeapBase.cpp \ MemoryHeapPmem.cpp \ Parcel.cpp \ Permission.cpp \ PermissionCache.cpp \ ProcessState.cpp \ Static.cpp Loading
libs/binder/Permission.cpp→libs/binder/PermissionCache.cpp +113 −0 Original line number Diff line number Diff line Loading @@ -14,72 +14,97 @@ * 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/Permission.h> #include <binder/PermissionCache.h> #include <utils/String8.h> namespace android { // --------------------------------------------------------------------------- Permission::Permission(char const* name) : mPermissionName(name), mPid(getpid()) { // ---------------------------------------------------------------------------- ANDROID_SINGLETON_STATIC_INSTANCE(PermissionCache) ; // ---------------------------------------------------------------------------- PermissionCache::PermissionCache() { } Permission::Permission(const String16& name) : mPermissionName(name), mPid(getpid()) { 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; } Permission::Permission(const Permission& rhs) : mPermissionName(rhs.mPermissionName), mGranted(rhs.mGranted), mPid(rhs.mPid) { 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); } } Permission::~Permission() { void PermissionCache::purge() { Mutex::Autolock _l(mLock); mCache.clear(); } bool Permission::operator < (const Permission& rhs) const { return mPermissionName < rhs.mPermissionName; bool PermissionCache::checkCallingPermission(const String16& permission) { return PermissionCache::checkCallingPermission(permission, NULL, NULL); } bool Permission::checkCalling() const { 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(); return doCheckPermission(pid, uid); } bool Permission::check(pid_t pid, uid_t uid) const { return doCheckPermission(pid, uid); if (outPid) *outPid = pid; if (outUid) *outUid = uid; return PermissionCache::checkPermission(permission, pid, uid); } bool Permission::doCheckPermission(pid_t pid, uid_t uid) const { if ((uid == 0) || (pid == mPid)) { 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; } 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); 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; } Loading
services/surfaceflinger/SurfaceFlinger.cpp +16 −10 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -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), Loading @@ -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), Loading Loading @@ -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(), Loading Loading @@ -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; Loading @@ -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; Loading @@ -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(); Loading Loading @@ -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); Loading
services/surfaceflinger/SurfaceFlinger.h +6 −11 Original line number Diff line number Diff line Loading @@ -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" Loading Loading @@ -353,10 +352,6 @@ 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 Loading