Simplify su_info caches

No more lists. 99.999% it will only handle a single excessive requestor anyways.
This commit is contained in:
topjohnwu 2018-10-03 23:31:15 -04:00
parent 58ae596b0f
commit 6a06c92fa6
2 changed files with 28 additions and 38 deletions

View File

@ -9,7 +9,6 @@
#include <sys/stat.h> #include <sys/stat.h>
#include "db.h" #include "db.h"
#include "list.h"
#define DEFAULT_SHELL "/system/bin/sh" #define DEFAULT_SHELL "/system/bin/sh"
@ -24,10 +23,9 @@ struct su_info {
struct su_access access; struct su_access access;
struct stat manager_stat; struct stat manager_stat;
/* These should be guarded with global list lock */ /* These should be guarded with global cache lock */
struct list_head pos;
int ref; int ref;
int clock; int life;
}; };
struct su_request { struct su_request {
@ -57,7 +55,6 @@ void set_identity(unsigned uid);
// connect.c // connect.c
void app_log(); void app_log();
void app_connect(const char *socket); void app_connect(const char *socket);
void socket_send_request(int fd); void socket_send_request(int fd);

View File

@ -19,7 +19,6 @@
#include "utils.h" #include "utils.h"
#include "su.h" #include "su.h"
#include "pts.h" #include "pts.h"
#include "list.h"
#include "selinux.h" #include "selinux.h"
// Constants for the atty bitfield // Constants for the atty bitfield
@ -29,13 +28,13 @@
#define TIMEOUT 3 #define TIMEOUT 3
#define LOCK_LIST() pthread_mutex_lock(&list_lock) #define LOCK_CACHE() pthread_mutex_lock(&cache_lock)
#define LOCK_UID() pthread_mutex_lock(&info->lock) #define LOCK_INFO() pthread_mutex_lock(&info->lock)
#define UNLOCK_LIST() pthread_mutex_unlock(&list_lock) #define UNLOCK_CACHE() pthread_mutex_unlock(&cache_lock)
#define UNLOCK_UID() pthread_mutex_unlock(&ctx.info->lock) #define UNLOCK_INFO() pthread_mutex_unlock(&ctx.info->lock)
static struct list_head info_cache = { .prev = &info_cache, .next = &info_cache }; static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER; static struct su_info *cache;
static void sighandler(int sig) { static void sighandler(int sig) {
restore_stdin(); restore_stdin();
@ -64,12 +63,13 @@ static void *info_collector(void *node) {
struct su_info *info = node; struct su_info *info = node;
while (1) { while (1) {
sleep(1); sleep(1);
if (info->clock && --info->clock == 0) { if (info->life) {
LOCK_LIST(); LOCK_CACHE();
list_pop(&info->pos); if (--info->life == 0 && cache && info->uid == cache->uid)
UNLOCK_LIST(); cache = NULL;
UNLOCK_CACHE();
} }
if (!info->clock && !info->ref) { if (!info->life && !info->ref) {
pthread_mutex_destroy(&info->lock); pthread_mutex_destroy(&info->lock);
free(info); free(info);
return NULL; return NULL;
@ -111,22 +111,15 @@ static void database_check(struct su_info *info) {
} }
static struct su_info *get_su_info(unsigned uid) { static struct su_info *get_su_info(unsigned uid) {
struct su_info *info = NULL, *node; struct su_info *info;
int cache_miss = 0;
LOCK_LIST(); LOCK_CACHE();
// Search for existing info in cache if (cache && cache->uid == uid) {
list_for_each(node, &info_cache, struct su_info, pos) { info = cache;
if (node->uid == uid) { } else {
info = node; cache_miss = 1;
break;
}
}
int cache_miss = info == NULL;
if (cache_miss) {
// If cache miss, create a new one and push to cache
info = malloc(sizeof(*info)); info = malloc(sizeof(*info));
info->uid = uid; info->uid = uid;
info->dbs = DEFAULT_DB_SETTINGS; info->dbs = DEFAULT_DB_SETTINGS;
@ -135,26 +128,26 @@ static struct su_info *get_su_info(unsigned uid) {
info->ref = 0; info->ref = 0;
info->count = 0; info->count = 0;
pthread_mutex_init(&info->lock, NULL); pthread_mutex_init(&info->lock, NULL);
list_insert_end(&info_cache, &info->pos); cache = info;
} }
// Update the cache status // Update the cache status
info->clock = TIMEOUT; info->life = TIMEOUT;
++info->ref; ++info->ref;
// Start a thread to maintain the info cache // Start a thread to maintain the cache
if (cache_miss) { if (cache_miss) {
pthread_t thread; pthread_t thread;
xpthread_create(&thread, NULL, info_collector, info); xpthread_create(&thread, NULL, info_collector, info);
pthread_detach(thread); pthread_detach(thread);
} }
UNLOCK_LIST(); UNLOCK_CACHE();
LOGD("su: request from uid=[%d] (#%d)\n", info->uid, ++info->count); LOGD("su: request from uid=[%d] (#%d)\n", info->uid, ++info->count);
// Lock before the policy is determined // Lock before the policy is determined
LOCK_UID(); LOCK_INFO();
if (info->access.policy == QUERY) { if (info->access.policy == QUERY) {
// Not cached, get data from database // Not cached, get data from database
@ -318,7 +311,7 @@ void su_daemon_receiver(int client, struct ucred *credential) {
// Fail fast // Fail fast
if (ctx.info->access.policy == DENY && !ctx.info->access.log && !ctx.info->access.notify) { if (ctx.info->access.policy == DENY && !ctx.info->access.log && !ctx.info->access.notify) {
UNLOCK_UID(); UNLOCK_INFO();
write_int(client, DENY); write_int(client, DENY);
return; return;
} }
@ -346,7 +339,7 @@ void su_daemon_receiver(int client, struct ucred *credential) {
} }
// The policy is determined, unlock // The policy is determined, unlock
UNLOCK_UID(); UNLOCK_INFO();
// Info is now useless to us, decrement reference count // Info is now useless to us, decrement reference count
--ctx.info->ref; --ctx.info->ref;