Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9df32619 authored by Mathias Agopian's avatar Mathias Agopian Committed by Android (Google) Code Review
Browse files

Merge "PermissionCache caches permission checks"

parents 531b95f1 0dd593f2
Loading
Loading
Loading
Loading
+79 −0
Original line number Original line Diff line number Diff line
@@ -20,46 +20,57 @@
#include <stdint.h>
#include <stdint.h>
#include <unistd.h>
#include <unistd.h>


#include <utils/SortedVector.h>
#include <utils/String16.h>
#include <utils/String16.h>
#include <utils/threads.h>
#include <utils/Singleton.h>


namespace android {
namespace android {
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------


/*
/*
 * Permission caches the result of the permission check for the given
 * PermissionCache caches permission checks for a given uid.
 * permission name and the provided uid/pid. It also handles a few
 *
 * known cases efficiently (caller is in the same process or is root).
 * Currently the cache is not updated when there is a permission change,
 * The package manager does something similar but lives in dalvik world
 * for instance when an application is uninstalled.
 * and is therefore extremely slow to access.
 *
 * IMPORTANT: for the reason stated above, only system permissions are safe
 * to cache. This restriction may be lifted at a later time.
 *
 */
 */


class Permission
class PermissionCache : Singleton<PermissionCache> {
{
    struct Entry {
public:
        String16    name;
            Permission(char const* name);
        uid_t       uid;
            Permission(const String16& name);
        bool        granted;
            Permission(const Permission& rhs);
        inline bool operator < (const Entry& e) const {
    virtual ~Permission();
            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
    status_t check(bool* granted,
    bool checkCalling() const;
            const String16& permission, uid_t uid) const;


    // checks the specified pid/uid has access to this permission
    void cache(const String16& permission, uid_t uid, bool granted);
    bool check(pid_t pid, uid_t uid) const;


protected:
public:
    virtual bool doCheckPermission(pid_t pid, uid_t uid) const;
    PermissionCache();


private:
    static bool checkCallingPermission(const String16& permission);
    Permission& operator = (const Permission& rhs) const;

    const String16 mPermissionName;
    static bool checkCallingPermission(const String16& permission,
    mutable SortedVector<uid_t> mGranted;
                                int32_t* outPid, int32_t* outUid);
    const pid_t mPid;

    mutable Mutex mLock;
    static bool checkPermission(const String16& permission,
            pid_t pid, uid_t uid);
};
};


// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
+1 −1
Original line number Original line Diff line number Diff line
@@ -27,7 +27,7 @@ sources := \
    MemoryHeapBase.cpp \
    MemoryHeapBase.cpp \
    MemoryHeapPmem.cpp \
    MemoryHeapPmem.cpp \
    Parcel.cpp \
    Parcel.cpp \
    Permission.cpp \
    PermissionCache.cpp \
    ProcessState.cpp \
    ProcessState.cpp \
    Static.cpp
    Static.cpp


+113 −0
Original line number Original line Diff line number Diff line
@@ -14,72 +14,97 @@
 * limitations under the License.
 * limitations under the License.
 */
 */


#define LOG_TAG "PermissionCache"

#include <stdint.h>
#include <stdint.h>
#include <utils/Log.h>
#include <utils/Log.h>
#include <binder/IPCThreadState.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/IServiceManager.h>
#include <binder/Permission.h>
#include <binder/PermissionCache.h>
#include <utils/String8.h>


namespace android {
namespace android {
// ---------------------------------------------------------------------------


Permission::Permission(char const* name)
// ----------------------------------------------------------------------------
    : mPermissionName(name), mPid(getpid())

{
ANDROID_SINGLETON_STATIC_INSTANCE(PermissionCache) ;

// ----------------------------------------------------------------------------

PermissionCache::PermissionCache() {
}
}


Permission::Permission(const String16& name)
status_t PermissionCache::check(bool* granted,
    : mPermissionName(name), mPid(getpid())
        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)
void PermissionCache::cache(const String16& permission,
    : mPermissionName(rhs.mPermissionName),
        uid_t uid, bool granted) {
    mGranted(rhs.mGranted),
    Mutex::Autolock _l(mLock);
    mPid(rhs.mPid)
    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
bool PermissionCache::checkCallingPermission(const String16& permission) {
{
    return PermissionCache::checkCallingPermission(permission, NULL, NULL);
    return mPermissionName < rhs.mPermissionName;
}
}


bool Permission::checkCalling() const
bool PermissionCache::checkCallingPermission(
{
        const String16& permission, int32_t* outPid, int32_t* outUid) {
    IPCThreadState* ipcState = IPCThreadState::self();
    IPCThreadState* ipcState = IPCThreadState::self();
    pid_t pid = ipcState->getCallingPid();
    pid_t pid = ipcState->getCallingPid();
    uid_t uid = ipcState->getCallingUid();
    uid_t uid = ipcState->getCallingUid();
    return doCheckPermission(pid, uid);
    if (outPid) *outPid = pid;
}
    if (outUid) *outUid = uid;

    return PermissionCache::checkPermission(permission, 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
bool PermissionCache::checkPermission(
{
        const String16& permission, pid_t pid, uid_t uid) {
    if ((uid == 0) || (pid == mPid)) {
    if ((uid == 0) || (pid == getpid())) {
        // root and ourselves is always okay
        // root and ourselves is always okay
        return true;
        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);
    PermissionCache& pc(PermissionCache::getInstance());
    if (granted) {
    bool granted = false;
        Mutex::Autolock _l(mLock);
    if (pc.check(&granted, permission, uid) != NO_ERROR) {
        // no need to check again, the old item will be replaced if it is
        nsecs_t t = -systemTime();
        // already there.
        granted = android::checkPermission(permission, pid, uid);
        mGranted.add(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;
    return granted;
}
}
+5 −3
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@


#include <binder/BinderService.h>
#include <binder/BinderService.h>
#include <binder/IServiceManager.h>
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>


#include <gui/ISensorServer.h>
#include <gui/ISensorServer.h>
#include <gui/ISensorEventConnection.h>
#include <gui/ISensorEventConnection.h>
@@ -58,8 +59,7 @@ namespace android {
 */
 */


SensorService::SensorService()
SensorService::SensorService()
    : mDump("android.permission.DUMP"),
    : mInitCheck(NO_INIT)
      mInitCheck(NO_INIT)
{
{
}
}


@@ -166,12 +166,14 @@ SensorService::~SensorService()
        delete mSensorMap.valueAt(i);
        delete mSensorMap.valueAt(i);
}
}


static const String16 sDump("android.permission.DUMP");

status_t SensorService::dump(int fd, const Vector<String16>& args)
status_t SensorService::dump(int fd, const Vector<String16>& args)
{
{
    const size_t SIZE = 1024;
    const size_t SIZE = 1024;
    char buffer[SIZE];
    char buffer[SIZE];
    String8 result;
    String8 result;
    if (!mDump.checkCalling()) {
    if (!PermissionCache::checkCallingPermission(sDump)) {
        snprintf(buffer, SIZE, "Permission Denial: "
        snprintf(buffer, SIZE, "Permission Denial: "
                "can't dump SurfaceFlinger from pid=%d, uid=%d\n",
                "can't dump SurfaceFlinger from pid=%d, uid=%d\n",
                IPCThreadState::self()->getCallingPid(),
                IPCThreadState::self()->getCallingPid(),
+0 −2
Original line number Original line Diff line number Diff line
@@ -27,7 +27,6 @@
#include <utils/RefBase.h>
#include <utils/RefBase.h>


#include <binder/BinderService.h>
#include <binder/BinderService.h>
#include <binder/Permission.h>


#include <gui/Sensor.h>
#include <gui/Sensor.h>
#include <gui/SensorChannel.h>
#include <gui/SensorChannel.h>
@@ -117,7 +116,6 @@ class SensorService :
    Vector<Sensor> mUserSensorList;
    Vector<Sensor> mUserSensorList;
    DefaultKeyedVector<int, SensorInterface*> mSensorMap;
    DefaultKeyedVector<int, SensorInterface*> mSensorMap;
    Vector<SensorInterface *> mVirtualSensorList;
    Vector<SensorInterface *> mVirtualSensorList;
    Permission mDump;
    status_t mInitCheck;
    status_t mInitCheck;


    // protected by mLock
    // protected by mLock
Loading