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/sensorservice/SensorService.cpp +5 −3 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ #include <binder/BinderService.h> #include <binder/IServiceManager.h> #include <binder/PermissionCache.h> #include <gui/ISensorServer.h> #include <gui/ISensorEventConnection.h> Loading Loading @@ -58,8 +59,7 @@ namespace android { */ SensorService::SensorService() : mDump("android.permission.DUMP"), mInitCheck(NO_INIT) : mInitCheck(NO_INIT) { } Loading Loading @@ -166,12 +166,14 @@ SensorService::~SensorService() delete mSensorMap.valueAt(i); } static const String16 sDump("android.permission.DUMP"); status_t SensorService::dump(int fd, const Vector<String16>& args) { const size_t SIZE = 1024; 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 services/sensorservice/SensorService.h +0 −2 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ #include <utils/RefBase.h> #include <binder/BinderService.h> #include <binder/Permission.h> #include <gui/Sensor.h> #include <gui/SensorChannel.h> Loading Loading @@ -117,7 +116,6 @@ class SensorService : Vector<Sensor> mUserSensorList; DefaultKeyedVector<int, SensorInterface*> mSensorMap; Vector<SensorInterface *> mVirtualSensorList; Permission mDump; status_t mInitCheck; // protected by mLock 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/sensorservice/SensorService.cpp +5 −3 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ #include <binder/BinderService.h> #include <binder/IServiceManager.h> #include <binder/PermissionCache.h> #include <gui/ISensorServer.h> #include <gui/ISensorEventConnection.h> Loading Loading @@ -58,8 +59,7 @@ namespace android { */ SensorService::SensorService() : mDump("android.permission.DUMP"), mInitCheck(NO_INIT) : mInitCheck(NO_INIT) { } Loading Loading @@ -166,12 +166,14 @@ SensorService::~SensorService() delete mSensorMap.valueAt(i); } static const String16 sDump("android.permission.DUMP"); status_t SensorService::dump(int fd, const Vector<String16>& args) { const size_t SIZE = 1024; 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
services/sensorservice/SensorService.h +0 −2 Original line number Diff line number Diff line Loading @@ -27,7 +27,6 @@ #include <utils/RefBase.h> #include <binder/BinderService.h> #include <binder/Permission.h> #include <gui/Sensor.h> #include <gui/SensorChannel.h> Loading Loading @@ -117,7 +116,6 @@ class SensorService : Vector<Sensor> mUserSensorList; DefaultKeyedVector<int, SensorInterface*> mSensorMap; Vector<SensorInterface *> mVirtualSensorList; Permission mDump; status_t mInitCheck; // protected by mLock Loading