mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-26 15:27:38 +00:00
Prevent client error
This commit is contained in:
parent
09392be069
commit
40b6de599c
13
su.h
13
su.h
@ -59,15 +59,20 @@ typedef enum {
|
|||||||
} policy_t;
|
} policy_t;
|
||||||
|
|
||||||
struct su_info {
|
struct su_info {
|
||||||
unsigned uid;
|
unsigned uid; /* Key to find su_info */
|
||||||
|
pthread_mutex_t lock; /* Internal lock */
|
||||||
|
int count; /* Just a count for debugging purpose */
|
||||||
|
|
||||||
|
/* These values should be guarded with internal lock */
|
||||||
policy_t policy;
|
policy_t policy;
|
||||||
pthread_mutex_t lock;
|
|
||||||
int count;
|
|
||||||
int clock;
|
|
||||||
int multiuser_mode;
|
int multiuser_mode;
|
||||||
int root_access;
|
int root_access;
|
||||||
int mnt_ns;
|
int mnt_ns;
|
||||||
|
|
||||||
|
/* These should be guarded with global list lock */
|
||||||
struct list_head pos;
|
struct list_head pos;
|
||||||
|
int ref;
|
||||||
|
int clock;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct su_request {
|
struct su_request {
|
||||||
|
70
su_daemon.c
70
su_daemon.c
@ -30,6 +30,11 @@
|
|||||||
|
|
||||||
#define TIMEOUT 3
|
#define TIMEOUT 3
|
||||||
|
|
||||||
|
#define LOCK_LIST() pthread_mutex_lock(&list_lock)
|
||||||
|
#define LOCK_UID() pthread_mutex_lock(&info->lock)
|
||||||
|
#define UNLOCK_LIST() pthread_mutex_unlock(&list_lock)
|
||||||
|
#define UNLOCK_UID() pthread_mutex_unlock(&info->lock)
|
||||||
|
|
||||||
static struct list_head active_list, waiting_list;
|
static struct list_head active_list, waiting_list;
|
||||||
static pthread_t su_collector = 0;
|
static pthread_t su_collector = 0;
|
||||||
static pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
@ -59,17 +64,13 @@ static void sighandler(int sig) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sigpipe_handler(int sig) {
|
|
||||||
LOGD("su: Client killed unexpectedly\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maintain the lists periodically
|
// Maintain the lists periodically
|
||||||
static void *collector(void *args) {
|
static void *collector(void *args) {
|
||||||
LOGD("su: collector started\n");
|
LOGD("su: collector started\n");
|
||||||
struct su_info *node;
|
struct su_info *node;
|
||||||
while(1) {
|
while(1) {
|
||||||
sleep(1);
|
sleep(1);
|
||||||
pthread_mutex_lock(&list_lock);
|
LOCK_LIST();
|
||||||
list_for_each(node, &active_list, struct su_info, pos) {
|
list_for_each(node, &active_list, struct su_info, pos) {
|
||||||
if (--node->clock == 0) {
|
if (--node->clock == 0) {
|
||||||
// Timeout, move to waiting list
|
// Timeout, move to waiting list
|
||||||
@ -78,14 +79,14 @@ static void *collector(void *args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
list_for_each(node, &waiting_list, struct su_info, pos) {
|
list_for_each(node, &waiting_list, struct su_info, pos) {
|
||||||
if (node->count == 0) {
|
if (node->ref == 0) {
|
||||||
// Nothing is using the info, remove it
|
// Nothing is using the info, remove it
|
||||||
__ = list_pop(&node->pos);
|
__ = list_pop(&node->pos);
|
||||||
pthread_mutex_destroy(&node->lock);
|
pthread_mutex_destroy(&node->lock);
|
||||||
free(node);
|
free(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&list_lock);
|
UNLOCK_LIST();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +96,7 @@ void su_daemon_receiver(int client) {
|
|||||||
struct su_info *info = NULL, *node;
|
struct su_info *info = NULL, *node;
|
||||||
int new_request = 0;
|
int new_request = 0;
|
||||||
|
|
||||||
pthread_mutex_lock(&list_lock);
|
LOCK_LIST();
|
||||||
|
|
||||||
if (!su_collector) {
|
if (!su_collector) {
|
||||||
init_list_head(&active_list);
|
init_list_head(&active_list);
|
||||||
@ -109,8 +110,10 @@ void su_daemon_receiver(int client) {
|
|||||||
|
|
||||||
// Search for existing in the active list
|
// Search for existing in the active list
|
||||||
list_for_each(node, &active_list, struct su_info, pos) {
|
list_for_each(node, &active_list, struct su_info, pos) {
|
||||||
if (node->uid == credential.uid)
|
if (node->uid == credential.uid) {
|
||||||
info = node;
|
info = node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no exist, create a new request
|
// If no exist, create a new request
|
||||||
@ -119,19 +122,17 @@ void su_daemon_receiver(int client) {
|
|||||||
info = malloc(sizeof(*info));
|
info = malloc(sizeof(*info));
|
||||||
info->uid = credential.uid;
|
info->uid = credential.uid;
|
||||||
info->policy = QUERY;
|
info->policy = QUERY;
|
||||||
|
info->ref = 0;
|
||||||
info->count = 0;
|
info->count = 0;
|
||||||
pthread_mutex_init(&info->lock, NULL);
|
pthread_mutex_init(&info->lock, NULL);
|
||||||
list_insert_end(&active_list, &info->pos);
|
list_insert_end(&active_list, &info->pos);
|
||||||
}
|
}
|
||||||
info->clock = TIMEOUT; /* Reset timer */
|
info->clock = TIMEOUT; /* Reset timer */
|
||||||
++info->count; /* Increment reference count */
|
++info->ref; /* Increment reference count */
|
||||||
|
|
||||||
pthread_mutex_unlock(&list_lock);
|
UNLOCK_LIST();
|
||||||
|
|
||||||
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
|
|
||||||
pthread_mutex_lock(&info->lock);
|
|
||||||
|
|
||||||
// Default values
|
// Default values
|
||||||
struct su_context ctx = {
|
struct su_context ctx = {
|
||||||
@ -165,6 +166,9 @@ void su_daemon_receiver(int client) {
|
|||||||
info->policy = DENY;
|
info->policy = DENY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lock before the policy is determined
|
||||||
|
LOCK_UID();
|
||||||
|
|
||||||
// Not cached, do the checks
|
// Not cached, do the checks
|
||||||
if (info->policy == QUERY) {
|
if (info->policy == QUERY) {
|
||||||
// Get data from database
|
// Get data from database
|
||||||
@ -193,7 +197,7 @@ void su_daemon_receiver(int client) {
|
|||||||
|
|
||||||
// If still not determined, open a pipe and wait for results
|
// If still not determined, open a pipe and wait for results
|
||||||
if (info->policy == QUERY)
|
if (info->policy == QUERY)
|
||||||
pipe2(pipefd, O_CLOEXEC);
|
xpipe2(pipefd, O_CLOEXEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fork a new process, the child process will need to setsid,
|
// Fork a new process, the child process will need to setsid,
|
||||||
@ -213,35 +217,45 @@ void su_daemon_receiver(int client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The policy is determined, unlock
|
// The policy is determined, unlock
|
||||||
pthread_mutex_unlock(&info->lock);
|
UNLOCK_UID();
|
||||||
|
|
||||||
// Wait result
|
// Wait result
|
||||||
LOGD("su: wait_result waiting for %d\n", child);
|
LOGD("su: waiting child: [%d]\n", child);
|
||||||
int status, code;
|
int status, code;
|
||||||
|
|
||||||
// Handle SIGPIPE, since we don't want to crash our daemon
|
|
||||||
struct sigaction act;
|
|
||||||
memset(&act, 0, sizeof(act));
|
|
||||||
act.sa_handler = sigpipe_handler;
|
|
||||||
sigaction(SIGPIPE, &act, NULL);
|
|
||||||
|
|
||||||
if (waitpid(child, &status, 0) > 0)
|
if (waitpid(child, &status, 0) > 0)
|
||||||
code = WEXITSTATUS(status);
|
code = WEXITSTATUS(status);
|
||||||
else
|
else
|
||||||
code = -1;
|
code = -1;
|
||||||
|
|
||||||
// Pass the return code back to the client
|
/* Passing the return code back to the client:
|
||||||
write(client, &code, sizeof(code)); /* Might SIGPIPE, ignored */
|
* The client might be closed unexpectedly (e.g. swipe a root app out of recents)
|
||||||
LOGD("su: return code to client: %d\n", code);
|
* In that case, writing to the client (which doesn't exist) will result in SIGPIPE
|
||||||
|
* Here we simply just ignore the situation.
|
||||||
|
*/
|
||||||
|
struct sigaction act;
|
||||||
|
memset(&act, 0, sizeof(act));
|
||||||
|
act.sa_handler = SIG_IGN;
|
||||||
|
sigaction(SIGPIPE, &act, NULL);
|
||||||
|
|
||||||
|
LOGD("su: return code: [%d]\n", code);
|
||||||
|
write(client, &code, sizeof(code));
|
||||||
close(client);
|
close(client);
|
||||||
|
|
||||||
|
// Restore default handler for SIGPIPE
|
||||||
|
act.sa_handler = SIG_DFL;
|
||||||
|
sigaction(SIGPIPE, &act, NULL);
|
||||||
|
|
||||||
// Decrement reference count
|
// Decrement reference count
|
||||||
--info->count;
|
LOCK_LIST();
|
||||||
|
--info->ref;
|
||||||
|
UNLOCK_LIST();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGD("su: child process started\n");
|
LOGD("su: child process started\n");
|
||||||
|
UNLOCK_UID();
|
||||||
|
|
||||||
// ack
|
// ack
|
||||||
write_int(client, 1);
|
write_int(client, 1);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user