Move database logic outside of MagiskSU
This commit is contained in:
parent
7e2ba41c64
commit
b2f719989d
10
activity.c
10
activity.c
@ -45,7 +45,7 @@ static void silent_run(char* const args[]) {
|
||||
}
|
||||
|
||||
static int setup_user(struct su_context *ctx, char* user) {
|
||||
switch (ctx->info->multiuser_mode) {
|
||||
switch (ctx->info->dbs.v[SU_MULTIUSER_MODE]) {
|
||||
case MULTIUSER_MODE_OWNER_ONLY: /* Should already be denied if not owner */
|
||||
case MULTIUSER_MODE_OWNER_MANAGED:
|
||||
sprintf(user, "%d", 0);
|
||||
@ -59,7 +59,7 @@ static int setup_user(struct su_context *ctx, char* user) {
|
||||
|
||||
void app_send_result(struct su_context *ctx, policy_t policy) {
|
||||
char fromUid[16];
|
||||
if (ctx->info->multiuser_mode == MULTIUSER_MODE_OWNER_MANAGED)
|
||||
if (ctx->info->dbs.v[SU_MULTIUSER_MODE] == MULTIUSER_MODE_OWNER_MANAGED)
|
||||
sprintf(fromUid, "%d", ctx->info->uid % 100000);
|
||||
else
|
||||
sprintf(fromUid, "%d", ctx->info->uid);
|
||||
@ -74,7 +74,7 @@ void app_send_result(struct su_context *ctx, policy_t policy) {
|
||||
int notify = setup_user(ctx, user);
|
||||
|
||||
char activity[128];
|
||||
sprintf(activity, ACTION_RESULT, ctx->info->pkg_name);
|
||||
sprintf(activity, ACTION_RESULT, ctx->info->str.s[SU_REQUESTER]);
|
||||
|
||||
// Send notice to manager, enable logging
|
||||
char *result_command[] = {
|
||||
@ -113,7 +113,7 @@ void app_send_request(struct su_context *ctx) {
|
||||
int notify = setup_user(ctx, user);
|
||||
|
||||
char activity[128];
|
||||
sprintf(activity, ACTION_REQUEST, ctx->info->pkg_name);
|
||||
sprintf(activity, ACTION_REQUEST, ctx->info->str.s[SU_REQUESTER]);
|
||||
|
||||
char *request_command[] = {
|
||||
AM_PATH, "start", "-n",
|
||||
@ -128,7 +128,7 @@ void app_send_request(struct su_context *ctx) {
|
||||
// Send notice to user to tell them root is managed by owner
|
||||
if (notify) {
|
||||
sprintf(user, "%d", notify);
|
||||
sprintf(activity, ACTION_RESULT, ctx->info->pkg_name);
|
||||
sprintf(activity, ACTION_RESULT, ctx->info->str.s[SU_REQUESTER]);
|
||||
char *notify_command[] = {
|
||||
AM_PATH, "broadcast", "-n",
|
||||
activity,
|
||||
|
148
db.c
148
db.c
@ -1,148 +0,0 @@
|
||||
/*
|
||||
** Copyright 2017, John Wu (@topjohnwu)
|
||||
** Copyright 2013, Koushik Dutta (@koush)
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sqlite3.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "magisk.h"
|
||||
#include "su.h"
|
||||
|
||||
static int policy_callback(void *v, int argc, char **argv, char **azColName) {
|
||||
struct su_context *ctx = (struct su_context *) v;
|
||||
policy_t policy = QUERY;
|
||||
time_t until = 0;
|
||||
for (int i = 0; i < argc; i++) {
|
||||
if (strcmp(azColName[i], "policy") == 0)
|
||||
policy = atoi(argv[i]);
|
||||
else if (strcmp(azColName[i], "until") == 0)
|
||||
until = atol(argv[i]);
|
||||
}
|
||||
|
||||
if (policy == DENY)
|
||||
ctx->info->policy = DENY;
|
||||
else if (policy == ALLOW && (until == 0 || until > time(NULL)))
|
||||
ctx->info->policy = ALLOW;
|
||||
|
||||
LOGD("su_db: query policy=[%d]\n", ctx->info->policy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int settings_callback(void *v, int argc, char **argv, char **azColName) {
|
||||
struct su_context *ctx = (struct su_context *) v;
|
||||
int *target, value;
|
||||
char *entry;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if (strcmp(azColName[i], "key") == 0) {
|
||||
if (strcmp(argv[i], ROOT_ACCESS_ENTRY) == 0)
|
||||
target = &ctx->info->root_access;
|
||||
else if (strcmp(argv[i], MULTIUSER_MODE_ENTRY) == 0)
|
||||
target = &ctx->info->multiuser_mode;
|
||||
else if (strcmp(argv[i], NAMESPACE_MODE_ENTRY) == 0)
|
||||
target = &ctx->info->mnt_ns;
|
||||
entry = argv[i];
|
||||
} else if (strcmp(azColName[i], "value") == 0) {
|
||||
value = atoi(argv[i]);
|
||||
}
|
||||
}
|
||||
LOGD("su_db: query %s=[%d]\n", entry, value);
|
||||
*target = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int strings_callback(void *v, int argc, char **argv, char **azColName) {
|
||||
struct su_context *ctx = (struct su_context *) v;
|
||||
char *entry, *target, *value;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if (strcmp(azColName[i], "key") == 0) {
|
||||
if (strcmp(argv[i], REQUESTER_ENTRY) == 0)
|
||||
target = ctx->info->pkg_name;
|
||||
entry = argv[i];
|
||||
} else if (strcmp(azColName[i], "value") == 0) {
|
||||
value = argv[i];
|
||||
}
|
||||
}
|
||||
LOGD("su_db: query %s=[%s]\n", entry, value);
|
||||
strcpy(target, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void database_check(struct su_context *ctx) {
|
||||
sqlite3 *db = NULL;
|
||||
int ret;
|
||||
char buffer[PATH_MAX], *err = NULL;
|
||||
const char *base = access("/data/user_de", F_OK) == 0 ? "/data/user_de" : "/data/user";
|
||||
|
||||
// Set default values
|
||||
ctx->info->root_access = ROOT_ACCESS_APPS_AND_ADB;
|
||||
ctx->info->multiuser_mode = MULTIUSER_MODE_OWNER_ONLY;
|
||||
ctx->info->mnt_ns = NAMESPACE_MODE_REQUESTER;
|
||||
strcpy(ctx->info->pkg_name, "???"); /* bad string so it doesn't exist */
|
||||
|
||||
// Open database
|
||||
ret = sqlite3_open_v2(MAGISKDB, &db, SQLITE_OPEN_READONLY, NULL);
|
||||
if (ret) {
|
||||
LOGE("sqlite3 open failure: %s\n", sqlite3_errstr(ret));
|
||||
sqlite3_close(db);
|
||||
goto stat_requester;
|
||||
}
|
||||
|
||||
// Query for strings
|
||||
sqlite3_exec(db, "SELECT key, value FROM strings", strings_callback, ctx, &err);
|
||||
if (err)
|
||||
LOGE("sqlite3_exec: %s\n", err);
|
||||
err = NULL;
|
||||
|
||||
// Query for settings
|
||||
sqlite3_exec(db, "SELECT key, value FROM settings", settings_callback, ctx, &err);
|
||||
if (err)
|
||||
LOGE("sqlite3_exec: %s\n", err);
|
||||
err = NULL;
|
||||
|
||||
// Query for policy
|
||||
int uid = -1;
|
||||
switch (ctx->info->multiuser_mode) {
|
||||
case MULTIUSER_MODE_OWNER_ONLY:
|
||||
if (ctx->info->uid / 100000) {
|
||||
uid = -1;
|
||||
ctx->info->policy = DENY;
|
||||
ctx->notify = 0;
|
||||
} else {
|
||||
uid = ctx->info->uid;
|
||||
}
|
||||
break;
|
||||
case MULTIUSER_MODE_OWNER_MANAGED:
|
||||
uid = ctx->info->uid % 100000;
|
||||
break;
|
||||
case MULTIUSER_MODE_USER:
|
||||
uid = ctx->info->uid;
|
||||
break;
|
||||
}
|
||||
|
||||
sprintf(buffer, "SELECT policy, until FROM policies WHERE uid=%d", uid);
|
||||
sqlite3_exec(db, buffer, policy_callback, ctx, &err);
|
||||
if (err)
|
||||
LOGE("sqlite3_exec: %s\n", err);
|
||||
|
||||
sqlite3_close(db);
|
||||
|
||||
stat_requester:
|
||||
// We prefer the original name
|
||||
sprintf(buffer, "%s/0/" JAVA_PACKAGE_NAME, base);
|
||||
if (stat(buffer, &ctx->info->st) == 0) {
|
||||
strcpy(ctx->info->pkg_name, JAVA_PACKAGE_NAME);
|
||||
} else {
|
||||
sprintf(buffer, "%s/0/%s", base, ctx->info->pkg_name);
|
||||
if (stat(buffer, &ctx->info->st) == -1) {
|
||||
LOGE("su: cannot find requester");
|
||||
memset(&ctx->info->st, 0, sizeof(ctx->info->st));
|
||||
}
|
||||
}
|
||||
}
|
48
su.c
48
su.c
@ -104,7 +104,7 @@ void set_identity(unsigned uid) {
|
||||
static __attribute__ ((noreturn)) void allow() {
|
||||
char* argv[] = { NULL, NULL, NULL, NULL };
|
||||
|
||||
if (su_ctx->notify)
|
||||
if (su_ctx->info->access.notify || su_ctx->info->access.log)
|
||||
app_send_result(su_ctx, ALLOW);
|
||||
|
||||
if (su_ctx->to.login)
|
||||
@ -129,7 +129,7 @@ static __attribute__ ((noreturn)) void allow() {
|
||||
}
|
||||
|
||||
static __attribute__ ((noreturn)) void deny() {
|
||||
if (su_ctx->notify)
|
||||
if (su_ctx->info->access.notify || su_ctx->info->access.log)
|
||||
app_send_result(su_ctx, DENY);
|
||||
|
||||
LOGW("su: request rejected (%u->%u)", su_ctx->info->uid, su_ctx->to.uid);
|
||||
@ -140,7 +140,7 @@ static __attribute__ ((noreturn)) void deny() {
|
||||
static void socket_cleanup() {
|
||||
if (su_ctx && su_ctx->sock_path[0]) {
|
||||
unlink(su_ctx->sock_path);
|
||||
su_ctx->sock_path[0] = 0;
|
||||
su_ctx->sock_path[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,8 +151,9 @@ static void cleanup_signal(int sig) {
|
||||
|
||||
__attribute__ ((noreturn)) void exit2(int status) {
|
||||
// Handle the pipe, or the daemon will get stuck
|
||||
if (su_ctx->info->policy == QUERY) {
|
||||
xwrite(su_ctx->pipefd[1], &su_ctx->info->policy, sizeof(su_ctx->info->policy));
|
||||
if (su_ctx->pipefd[0] >= 0) {
|
||||
int i = DENY;
|
||||
xwrite(su_ctx->pipefd[1], &i, sizeof(i));
|
||||
close(su_ctx->pipefd[0]);
|
||||
close(su_ctx->pipefd[1]);
|
||||
}
|
||||
@ -215,7 +216,6 @@ int su_daemon_main(int argc, char **argv) {
|
||||
case 'c':
|
||||
su_ctx->to.command = concat_commands(argc, argv);
|
||||
optind = argc;
|
||||
su_ctx->notify = 1;
|
||||
break;
|
||||
case 'h':
|
||||
usage(EXIT_SUCCESS);
|
||||
@ -240,7 +240,7 @@ int su_daemon_main(int argc, char **argv) {
|
||||
// Do nothing, placed here for legacy support :)
|
||||
break;
|
||||
case 'M':
|
||||
su_ctx->info->mnt_ns = NAMESPACE_MODE_GLOBAL;
|
||||
su_ctx->info->dbs.v[SU_MNT_NS] = NAMESPACE_MODE_GLOBAL;
|
||||
break;
|
||||
default:
|
||||
/* Bionic getopt_long doesn't terminate its error output by newline */
|
||||
@ -265,7 +265,7 @@ int su_daemon_main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
// Handle namespaces
|
||||
switch (su_ctx->info->mnt_ns) {
|
||||
switch (su_ctx->info->dbs.v[SU_MNT_NS]) {
|
||||
case NAMESPACE_MODE_GLOBAL:
|
||||
LOGD("su: use global namespace\n");
|
||||
break;
|
||||
@ -285,30 +285,8 @@ int su_daemon_main(int argc, char **argv) {
|
||||
// Change directory to cwd
|
||||
chdir(su_ctx->cwd);
|
||||
|
||||
// Check root_access configuration
|
||||
switch (su_ctx->info->root_access) {
|
||||
case ROOT_ACCESS_DISABLED:
|
||||
LOGE("Root access is disabled!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
case ROOT_ACCESS_APPS_ONLY:
|
||||
if (su_ctx->info->uid == UID_SHELL) {
|
||||
LOGE("Root access is disabled for ADB!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case ROOT_ACCESS_ADB_ONLY:
|
||||
if (su_ctx->info->uid != UID_SHELL) {
|
||||
LOGE("Root access limited to ADB only!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case ROOT_ACCESS_APPS_AND_ADB:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// New request or no db exist, notify user for response
|
||||
if (su_ctx->info->policy == QUERY && su_ctx->info->st.st_uid != 0) {
|
||||
if (su_ctx->pipefd[0] >= 0) {
|
||||
socket_serv_fd = socket_create_temp(su_ctx->sock_path, sizeof(su_ctx->sock_path));
|
||||
setup_sighandlers(cleanup_signal);
|
||||
|
||||
@ -326,17 +304,17 @@ int su_daemon_main(int argc, char **argv) {
|
||||
socket_cleanup();
|
||||
|
||||
if (strcmp(result, "socket:ALLOW") == 0)
|
||||
su_ctx->info->policy = ALLOW;
|
||||
su_ctx->info->access.policy = ALLOW;
|
||||
else
|
||||
su_ctx->info->policy = DENY;
|
||||
su_ctx->info->access.policy = DENY;
|
||||
|
||||
// Report the policy to main daemon
|
||||
xwrite(su_ctx->pipefd[1], &su_ctx->info->policy, sizeof(su_ctx->info->policy));
|
||||
xwrite(su_ctx->pipefd[1], &su_ctx->info->access.policy, sizeof(policy_t));
|
||||
close(su_ctx->pipefd[0]);
|
||||
close(su_ctx->pipefd[1]);
|
||||
}
|
||||
|
||||
if (su_ctx->info->policy == ALLOW)
|
||||
if (su_ctx->info->access.policy == ALLOW)
|
||||
allow();
|
||||
else
|
||||
deny();
|
||||
|
48
su.h
48
su.h
@ -8,57 +8,26 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "db.h"
|
||||
#include "list.h"
|
||||
|
||||
#define MAGISKSU_VER_STR xstr(MAGISK_VERSION) ":MAGISKSU (topjohnwu)"
|
||||
|
||||
// DB settings for root access
|
||||
#define ROOT_ACCESS_ENTRY "root_access"
|
||||
#define ROOT_ACCESS_DISABLED 0
|
||||
#define ROOT_ACCESS_APPS_ONLY 1
|
||||
#define ROOT_ACCESS_ADB_ONLY 2
|
||||
#define ROOT_ACCESS_APPS_AND_ADB 3
|
||||
|
||||
// DB settings for multiuser
|
||||
#define MULTIUSER_MODE_ENTRY "multiuser_mode"
|
||||
#define MULTIUSER_MODE_OWNER_ONLY 0
|
||||
#define MULTIUSER_MODE_OWNER_MANAGED 1
|
||||
#define MULTIUSER_MODE_USER 2
|
||||
|
||||
// DB settings for namespace seperation
|
||||
#define NAMESPACE_MODE_ENTRY "mnt_ns"
|
||||
#define NAMESPACE_MODE_GLOBAL 0
|
||||
#define NAMESPACE_MODE_REQUESTER 1
|
||||
#define NAMESPACE_MODE_ISOLATE 2
|
||||
|
||||
// DB entry for requester
|
||||
#define REQUESTER_ENTRY "requester"
|
||||
|
||||
// DO NOT CHANGE LINE BELOW, java package name will always be the same
|
||||
#define JAVA_PACKAGE_NAME "com.topjohnwu.magisk"
|
||||
// This is used if wrapping the fragment classes and activities
|
||||
// with classes in another package.
|
||||
#define REQUESTOR_PREFIX JAVA_PACKAGE_NAME ".superuser"
|
||||
|
||||
#define DEFAULT_SHELL "/system/bin/sh"
|
||||
|
||||
typedef enum {
|
||||
QUERY = 0,
|
||||
DENY = 1,
|
||||
ALLOW = 2,
|
||||
} policy_t;
|
||||
|
||||
struct su_info {
|
||||
unsigned uid; /* Key to find su_info */
|
||||
unsigned uid; /* Unique key to find su_info */
|
||||
pthread_mutex_t lock; /* Internal lock */
|
||||
int count; /* Just a count for debugging purpose */
|
||||
int count; /* Just a count for debugging purpose */
|
||||
|
||||
/* These values should be guarded with internal lock */
|
||||
policy_t policy;
|
||||
int multiuser_mode;
|
||||
int root_access;
|
||||
int mnt_ns;
|
||||
char pkg_name[PATH_MAX];
|
||||
struct db_settings dbs;
|
||||
struct db_strings str;
|
||||
struct su_access access;
|
||||
struct stat st;
|
||||
|
||||
/* These should be guarded with global list lock */
|
||||
@ -79,7 +48,6 @@ struct su_context {
|
||||
struct su_info *info;
|
||||
struct su_request to;
|
||||
pid_t pid;
|
||||
int notify;
|
||||
char cwd[PATH_MAX];
|
||||
char sock_path[PATH_MAX];
|
||||
int pipefd[2];
|
||||
@ -105,8 +73,4 @@ void socket_receive_result(int fd, char *result, ssize_t result_len);
|
||||
void app_send_result(struct su_context *ctx, policy_t policy);
|
||||
void app_send_request(struct su_context *ctx);
|
||||
|
||||
// db.c
|
||||
|
||||
void database_check(struct su_context *ctx);
|
||||
|
||||
#endif
|
||||
|
169
su_daemon.c
169
su_daemon.c
@ -31,7 +31,7 @@
|
||||
#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)
|
||||
#define UNLOCK_UID() pthread_mutex_unlock(&ctx.info->lock)
|
||||
|
||||
static struct list_head active_list, waiting_list;
|
||||
static pthread_t su_collector = 0;
|
||||
@ -88,11 +88,41 @@ static void *collector(void *args) {
|
||||
}
|
||||
}
|
||||
|
||||
void su_daemon_receiver(int client, struct ucred *credential) {
|
||||
LOGD("su: request from client: %d\n", client);
|
||||
static void database_check(struct su_info *info) {
|
||||
int uid = info->uid;
|
||||
sqlite3 *db = get_magiskdb();
|
||||
if (db) {
|
||||
get_db_settings(db, -1, &info->dbs);
|
||||
get_db_strings(db, -1, &info->str);
|
||||
|
||||
// Check multiuser settings
|
||||
switch (info->dbs.v[SU_MULTIUSER_MODE]) {
|
||||
case MULTIUSER_MODE_OWNER_ONLY:
|
||||
if (info->uid / 100000) {
|
||||
uid = -1;
|
||||
info->access = NO_SU_ACCESS;
|
||||
}
|
||||
break;
|
||||
case MULTIUSER_MODE_OWNER_MANAGED:
|
||||
uid = info->uid % 100000;
|
||||
break;
|
||||
case MULTIUSER_MODE_USER:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (uid > 0)
|
||||
get_uid_policy(db, uid, &info->access);
|
||||
sqlite3_close(db);
|
||||
}
|
||||
|
||||
// We need to check our manager
|
||||
if (info->access.log || info->access.notify)
|
||||
validate_manager(info->str.s[SU_REQUESTER], uid / 100000, &info->st);
|
||||
}
|
||||
|
||||
static struct su_info *get_su_info(unsigned uid) {
|
||||
struct su_info *info = NULL, *node;
|
||||
int new_request = 0;
|
||||
|
||||
LOCK_LIST();
|
||||
|
||||
@ -104,7 +134,7 @@ void su_daemon_receiver(int client, struct ucred *credential) {
|
||||
|
||||
// Search for existing in the active list
|
||||
list_for_each(node, &active_list, struct su_info, pos) {
|
||||
if (node->uid == credential->uid) {
|
||||
if (node->uid == uid) {
|
||||
info = node;
|
||||
break;
|
||||
}
|
||||
@ -112,10 +142,11 @@ void su_daemon_receiver(int client, struct ucred *credential) {
|
||||
|
||||
// If no exist, create a new request
|
||||
if (info == NULL) {
|
||||
new_request = 1;
|
||||
info = malloc(sizeof(*info));
|
||||
info->uid = credential->uid;
|
||||
info->policy = QUERY;
|
||||
info->uid = uid;
|
||||
info->dbs = DEFAULT_DB_SETTINGS;
|
||||
info->access = DEFAULT_SU_ACCESS;
|
||||
INIT_DB_STRINGS(&info->str);
|
||||
info->ref = 0;
|
||||
info->count = 0;
|
||||
pthread_mutex_init(&info->lock, NULL);
|
||||
@ -128,65 +159,85 @@ void su_daemon_receiver(int client, struct ucred *credential) {
|
||||
|
||||
LOGD("su: request from uid=[%d] (#%d)\n", info->uid, ++info->count);
|
||||
|
||||
// Default values
|
||||
struct su_context ctx = {
|
||||
.info = info,
|
||||
.to = {
|
||||
.uid = UID_ROOT,
|
||||
.login = 0,
|
||||
.keepenv = 0,
|
||||
.shell = DEFAULT_SHELL,
|
||||
.command = NULL,
|
||||
},
|
||||
.pid = credential->pid,
|
||||
.notify = new_request,
|
||||
};
|
||||
|
||||
// Lock before the policy is determined
|
||||
LOCK_UID();
|
||||
|
||||
// Not cached, do the checks
|
||||
if (info->policy == QUERY) {
|
||||
// Get data from database
|
||||
database_check(&ctx);
|
||||
if (info->access.policy == QUERY) {
|
||||
// Not cached, get data from database
|
||||
database_check(info);
|
||||
|
||||
// Check requester
|
||||
if (info->policy == QUERY) {
|
||||
if (info->st.st_gid != info->st.st_uid) {
|
||||
LOGE("Bad uid/gid %d/%d for Superuser Requestor", info->st.st_gid, info->st.st_uid);
|
||||
info->policy = DENY;
|
||||
ctx.notify = 0;
|
||||
} else if ((info->uid % 100000) == (info->st.st_uid % 100000)) {
|
||||
info->policy = ALLOW;
|
||||
info->root_access = ROOT_ACCESS_APPS_AND_ADB;
|
||||
ctx.notify = 0;
|
||||
}
|
||||
// Check su access settings
|
||||
switch (info->dbs.v[ROOT_ACCESS]) {
|
||||
case ROOT_ACCESS_DISABLED:
|
||||
LOGE("Root access is disabled!\n");
|
||||
info->access = NO_SU_ACCESS;
|
||||
break;
|
||||
case ROOT_ACCESS_ADB_ONLY:
|
||||
if (info->uid != UID_SHELL) {
|
||||
LOGE("Root access is disabled for ADB!\n");
|
||||
info->access = NO_SU_ACCESS;
|
||||
}
|
||||
break;
|
||||
case ROOT_ACCESS_APPS_ONLY:
|
||||
if (info->uid == UID_SHELL) {
|
||||
LOGE("Root access limited to ADB only!\n");
|
||||
info->access = NO_SU_ACCESS;
|
||||
}
|
||||
break;
|
||||
case ROOT_ACCESS_APPS_AND_ADB:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// always allow if it's root
|
||||
if (info->uid == UID_ROOT) {
|
||||
info->policy = ALLOW;
|
||||
info->root_access = ROOT_ACCESS_APPS_AND_ADB;
|
||||
ctx.notify = 0;
|
||||
}
|
||||
// If it's the manager, allow it silently
|
||||
if ((info->uid % 100000) == (info->st.st_uid % 100000))
|
||||
info->access = SILENT_SU_ACCESS;
|
||||
|
||||
// If still not determined, open a pipe and wait for results
|
||||
if (info->policy == QUERY)
|
||||
xpipe2(ctx.pipefd, O_CLOEXEC);
|
||||
// Allow if it's root
|
||||
if (info->uid == UID_ROOT)
|
||||
info->access = SILENT_SU_ACCESS;
|
||||
|
||||
// If still not determined, check if manager exists
|
||||
if (info->access.policy == QUERY && info->str.s[SU_REQUESTER][0] == '\0')
|
||||
info->access = NO_SU_ACCESS;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
// Fork a new process, the child process will need to setsid,
|
||||
// open a pseudo-terminal if needed, and will eventually run exec
|
||||
// The parent process will wait for the result and
|
||||
// send the return code back to our client
|
||||
void su_daemon_receiver(int client, struct ucred *credential) {
|
||||
LOGD("su: request from client: %d\n", client);
|
||||
|
||||
// Default values
|
||||
struct su_context ctx = {
|
||||
.info = get_su_info(credential->uid),
|
||||
.to = {
|
||||
.uid = UID_ROOT,
|
||||
.login = 0,
|
||||
.keepenv = 0,
|
||||
.shell = DEFAULT_SHELL,
|
||||
.command = NULL,
|
||||
},
|
||||
.pid = credential->pid,
|
||||
.pipefd = { -1, -1 }
|
||||
};
|
||||
|
||||
// If still not determined, open a pipe and wait for results
|
||||
if (ctx.info->access.policy == QUERY)
|
||||
xpipe2(ctx.pipefd, O_CLOEXEC);
|
||||
|
||||
/* Fork a new process, the child process will need to setsid,
|
||||
* open a pseudo-terminal if needed, and will eventually run exec
|
||||
* The parent process will wait for the result and
|
||||
* send the return code back to our client
|
||||
*/
|
||||
int child = fork();
|
||||
if (child < 0)
|
||||
PLOGE("fork");
|
||||
|
||||
if (child) {
|
||||
// Wait for results
|
||||
if (info->policy == QUERY) {
|
||||
xxread(ctx.pipefd[0], &info->policy, sizeof(info->policy));
|
||||
if (ctx.pipefd[0] >= 0) {
|
||||
xxread(ctx.pipefd[0], &ctx.info->access.policy, sizeof(policy_t));
|
||||
close(ctx.pipefd[0]);
|
||||
close(ctx.pipefd[1]);
|
||||
}
|
||||
@ -223,7 +274,7 @@ void su_daemon_receiver(int client, struct ucred *credential) {
|
||||
|
||||
// Decrement reference count
|
||||
LOCK_LIST();
|
||||
--info->ref;
|
||||
--ctx.info->ref;
|
||||
UNLOCK_LIST();
|
||||
|
||||
return;
|
||||
@ -276,7 +327,7 @@ void su_daemon_receiver(int client, struct ucred *credential) {
|
||||
char *pts_slave = read_string(client);
|
||||
LOGD("su: pts_slave=[%s]\n", pts_slave);
|
||||
|
||||
// The the FDs for each of the streams
|
||||
// The FDs for each of the streams
|
||||
int infd = recv_fd(client);
|
||||
int outfd = recv_fd(client);
|
||||
int errfd = recv_fd(client);
|
||||
@ -286,12 +337,12 @@ void su_daemon_receiver(int client, struct ucred *credential) {
|
||||
close(client);
|
||||
|
||||
if (pts_slave[0]) {
|
||||
//Check pts_slave file is owned by daemon_from_uid
|
||||
struct stat stbuf;
|
||||
xstat(pts_slave, &stbuf);
|
||||
// Check pts_slave file is owned by daemon_from_uid
|
||||
struct stat st;
|
||||
xstat(pts_slave, &st);
|
||||
|
||||
//If caller is not root, ensure the owner of pts_slave is the caller
|
||||
if(stbuf.st_uid != info->uid && info->uid != 0) {
|
||||
// If caller is not root, ensure the owner of pts_slave is the caller
|
||||
if(st.st_uid != credential->uid && credential->uid != 0) {
|
||||
LOGE("su: Wrong permission of pts_slave");
|
||||
exit2(1);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user