Adapt su to Magisk

This commit is contained in:
topjohnwu 2017-01-23 22:51:00 +08:00
parent ef1d1303f4
commit e3a4a16507
4 changed files with 33 additions and 96 deletions

View File

@ -445,7 +445,7 @@ static int daemon_accept(int fd) {
} }
int run_daemon() { int run_daemon() {
if (getuid() != 0 || getgid() != 0) { if (getuid() != AID_ROOT || getgid() != AID_ROOT) {
PLOGE("daemon requires root. uid/gid not root"); PLOGE("daemon requires root. uid/gid not root");
return -1; return -1;
} }
@ -455,13 +455,19 @@ int run_daemon() {
break; break;
case -1: case -1:
PLOGE("fork"); PLOGE("fork");
return 1; return -1;
default: default:
return 0; return 0;
} }
if (setsid() < 0 || setcon("u:r:su_daemon:s0") < 0) if (setsid() < 0) {
return 1; PLOGE("setsid");
return -1;
}
if (setcon("u:r:su_daemon:s0") < 0) {
PLOGE("setcon");
return -1;
}
int fd; int fd;
struct sockaddr_un sun; struct sockaddr_un sun;
@ -478,32 +484,17 @@ int run_daemon() {
memset(&sun, 0, sizeof(sun)); memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_LOCAL; sun.sun_family = AF_LOCAL;
sprintf(sun.sun_path, "%s/server", REQUESTOR_DAEMON_PATH); strcpy(sun.sun_path, REQUESTOR_DAEMON_PATH);
/*
* Delete the socket to protect from situations when
* something bad occured previously and the kernel reused pid from that process.
* Small probability, isn't it.
*/
unlink(sun.sun_path); unlink(sun.sun_path);
unlink(REQUESTOR_DAEMON_PATH);
int previous_umask = umask(027);
mkdir(REQUESTOR_DAEMON_PATH, 0777);
memset(sun.sun_path, 0, sizeof(sun.sun_path));
memcpy(sun.sun_path, "\0" "SUPERUSER", strlen("SUPERUSER") + 1);
if (bind(fd, (struct sockaddr*)&sun, sizeof(sun)) < 0) { if (bind(fd, (struct sockaddr*)&sun, sizeof(sun)) < 0) {
PLOGE("daemon bind"); PLOGE("daemon bind");
goto err; goto err;
} }
chmod(REQUESTOR_DAEMON_PATH, 0755);
chmod(sun.sun_path, 0777); chmod(sun.sun_path, 0777);
umask(previous_umask);
if (listen(fd, 10) < 0) { if (listen(fd, 10) < 0) {
PLOGE("daemon listen"); PLOGE("daemon listen");
goto err; goto err;
@ -600,10 +591,7 @@ int connect_daemon(int argc, char *argv[], int ppid) {
memset(&sun, 0, sizeof(sun)); memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_LOCAL; sun.sun_family = AF_LOCAL;
sprintf(sun.sun_path, "%s/server", REQUESTOR_DAEMON_PATH); strcpy(sun.sun_path, REQUESTOR_DAEMON_PATH);
memset(sun.sun_path, 0, sizeof(sun.sun_path));
memcpy(sun.sun_path, "\0" "SUPERUSER", strlen("SUPERUSER") + 1);
if (0 != connect(socketfd, (struct sockaddr*)&sun, sizeof(sun))) { if (0 != connect(socketfd, (struct sockaddr*)&sun, sizeof(sun))) {
PLOGE("connect"); PLOGE("connect");

47
db.c
View File

@ -29,51 +29,31 @@ struct callback_data_t {
static int database_callback(void *v, int argc, char **argv, char **azColName){ static int database_callback(void *v, int argc, char **argv, char **azColName){
struct callback_data_t *data = (struct callback_data_t *)v; struct callback_data_t *data = (struct callback_data_t *)v;
int command_match = 0; policy_t policy = INTERACTIVE;
policy_t policy = DENY;
int i; int i;
time_t until = 0; time_t until = 0;
for(i = 0; i < argc; i++) { for(i = 0; i < argc; i++) {
if (strcmp(azColName[i], "policy") == 0) { if (strcmp(azColName[i], "policy") == 0) {
if (argv[i] == NULL) { if (argv[i] != NULL) {
policy = DENY; policy = atoi(argv[i]);
} }
if (strcmp(argv[i], "allow") == 0) {
policy = ALLOW;
}
else if (strcmp(argv[i], "interactive") == 0) {
policy = INTERACTIVE;
}
else {
policy = DENY;
}
}
else if (strcmp(azColName[i], "command") == 0) {
// null or empty command means to match all commands (whitelist all from uid)
command_match = argv[i] == NULL || strlen(argv[i]) == 0 || strcmp(argv[i], get_command(&(data->ctx->to))) == 0;
} }
else if (strcmp(azColName[i], "until") == 0) { else if (strcmp(azColName[i], "until") == 0) {
if (argv[i] != NULL) { if (argv[i] != NULL) {
until = atoi(argv[i]); until = atol(argv[i]);
} }
} }
} }
// check for command match if (policy == DENY) {
if (command_match) { data->policy = DENY;
// also make sure this policy has not expired return -1;
if (until == 0 || until > time(NULL)) { } else if (policy == ALLOW && (until == 0 || until > time(NULL))) {
if (policy == DENY) { data->policy = ALLOW;
data->policy = DENY; // even though we allow, continue, so we can see if there's another policy
return -1; // that denies...
}
data->policy = ALLOW;
// even though we allow, continue, so we can see if there's another policy
// that denies...
}
} }
return 0; return 0;
} }
@ -81,7 +61,7 @@ policy_t database_check(struct su_context *ctx) {
sqlite3 *db = NULL; sqlite3 *db = NULL;
char query[512]; char query[512];
snprintf(query, sizeof(query), "select policy, until, command from uid_policy where uid=%d", ctx->from.uid); snprintf(query, sizeof(query), "select policy, until from policies where uid=%d", ctx->from.uid);
int ret = sqlite3_open_v2(ctx->user.database_path, &db, SQLITE_OPEN_READONLY, NULL); int ret = sqlite3_open_v2(ctx->user.database_path, &db, SQLITE_OPEN_READONLY, NULL);
if (ret) { if (ret) {
LOGE("sqlite3 open failure: %d", ret); LOGE("sqlite3 open failure: %d", ret);
@ -89,7 +69,6 @@ policy_t database_check(struct su_context *ctx) {
return INTERACTIVE; return INTERACTIVE;
} }
int result;
char *err = NULL; char *err = NULL;
struct callback_data_t data; struct callback_data_t data;
data.ctx = ctx; data.ctx = ctx;

23
su.c
View File

@ -425,9 +425,6 @@ static int socket_send_request(int fd, const struct su_context *ctx) {
write_token(fd, "from.uid", ctx->from.uid); write_token(fd, "from.uid", ctx->from.uid);
write_token(fd, "to.uid", ctx->to.uid); write_token(fd, "to.uid", ctx->to.uid);
write_string_data(fd, "from.bin", ctx->from.bin); write_string_data(fd, "from.bin", ctx->from.bin);
write_string_data(fd, "bind.from", ctx->bind.from);
write_string_data(fd, "bind.to", ctx->bind.to);
write_string_data(fd, "init", ctx->init);
// TODO: Fix issue where not using -c does not result a in a command // TODO: Fix issue where not using -c does not result a in a command
write_string_data(fd, "command", get_command(&ctx->to)); write_string_data(fd, "command", get_command(&ctx->to));
write_token(fd, "eof", PROTO_VERSION); write_token(fd, "eof", PROTO_VERSION);
@ -510,12 +507,6 @@ static __attribute__ ((noreturn)) void allow(struct su_context *ctx) {
if (send_to_app) if (send_to_app)
send_result(ctx, ALLOW); send_result(ctx, ALLOW);
// if(ctx->bind.from[0] && ctx->bind.to[0])
// allow_bind(ctx);
// if(ctx->init[0])
// allow_init(ctx);
char *binary; char *binary;
argc = ctx->to.optind; argc = ctx->to.optind;
if (ctx->to.command) { if (ctx->to.command) {
@ -712,11 +703,6 @@ int su_main_nodaemon(int argc, char **argv) {
.database_path = REQUESTOR_DATA_PATH REQUESTOR_DATABASE_PATH, .database_path = REQUESTOR_DATA_PATH REQUESTOR_DATABASE_PATH,
.base_path = REQUESTOR_DATA_PATH REQUESTOR .base_path = REQUESTOR_DATA_PATH REQUESTOR
}, },
.bind = {
.from = "",
.to = "",
},
.init = "",
}; };
struct stat st; struct stat st;
int c, socket_serv_fd, fd; int c, socket_serv_fd, fd;
@ -756,7 +742,7 @@ int su_main_nodaemon(int argc, char **argv) {
printf("%d\n", VERSION_CODE); printf("%d\n", VERSION_CODE);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
case 'v': case 'v':
printf("%s cm-su topjohnwu\n", VERSION); printf("%s\n", VERSION);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
case 'u': case 'u':
switch (get_multiuser_mode()) { switch (get_multiuser_mode()) {
@ -851,12 +837,6 @@ int su_main_nodaemon(int argc, char **argv) {
allow(&ctx); allow(&ctx);
} }
// autogrant shell at this point
if (ctx.from.uid == AID_SHELL) {
LOGD("Allowing shell.");
allow(&ctx);
}
// deny if this is a non owner request and owner mode only // deny if this is a non owner request and owner mode only
if (ctx.user.multiuser_mode == MULTIUSER_MODE_OWNER_ONLY && ctx.user.android_user_id != 0) { if (ctx.user.multiuser_mode == MULTIUSER_MODE_OWNER_ONLY && ctx.user.android_user_id != 0) {
deny(&ctx); deny(&ctx);
@ -883,7 +863,6 @@ int su_main_nodaemon(int argc, char **argv) {
deny(&ctx); deny(&ctx);
} }
//TODO: Ignore database check for init and bind?
dballow = database_check(&ctx); dballow = database_check(&ctx);
switch (dballow) { switch (dballow) {
case INTERACTIVE: case INTERACTIVE:

23
su.h
View File

@ -46,29 +46,28 @@
#define CM_ROOT_ACCESS_APPS_AND_ADB 3 #define CM_ROOT_ACCESS_APPS_AND_ADB 3
// DO NOT CHANGE LINE BELOW, java package name will always be the same // DO NOT CHANGE LINE BELOW, java package name will always be the same
#define JAVA_PACKAGE_NAME "com.koushikdutta.superuser" #define JAVA_PACKAGE_NAME "com.topjohnwu.magisk"
// If --rename-manifest-package is used in AAPT, this // If --rename-manifest-package is used in AAPT, this
// must be changed to correspond to the new APK package name // must be changed to correspond to the new APK package name
// See the two Android.mk files for more details. // See the two Android.mk files for more details.
#ifndef REQUESTOR #ifndef REQUESTOR
#define REQUESTOR "me.phh.superuser" #define REQUESTOR JAVA_PACKAGE_NAME
#endif #endif
// This is used if wrapping the fragment classes and activities // This is used if wrapping the fragment classes and activities
// with classes in another package. CM requirement. // with classes in another package. CM requirement.
#ifndef REQUESTOR_PREFIX #ifndef REQUESTOR_PREFIX
#define REQUESTOR_PREFIX JAVA_PACKAGE_NAME #define REQUESTOR_PREFIX JAVA_PACKAGE_NAME ".superuser"
#endif #endif
#define REQUESTOR_DATA_PATH "/data/data/" #define REQUESTOR_DATA_PATH "/data/data/"
#define REQUESTOR_FILES_PATH REQUESTOR_DATA_PATH REQUESTOR "/files" #define REQUESTOR_FILES_PATH REQUESTOR_DATA_PATH REQUESTOR "/files"
#define REQUESTOR_USER_PATH "/data/user/" #define REQUESTOR_USER_PATH "/data/user/"
#define REQUESTOR_CACHE_PATH "/dev/" REQUESTOR #define REQUESTOR_CACHE_PATH "/dev/" REQUESTOR
#define REQUESTOR_DAEMON_PATH REQUESTOR_CACHE_PATH ".daemon" #define REQUESTOR_DAEMON_PATH "\0MAGISKSU"
// there's no guarantee that the db or files are actually created named as such by // there's no guarantee that the db or files are actually created named as such by
// SQLiteOpenHelper, etc. Though that is the behavior as of current. // SQLiteOpenHelper, etc. Though that is the behavior as of current.
// it is up to the Android application to symlink as appropriate. // it is up to the Android application to symlink as appropriate.
#define REQUESTOR_DATABASE_PATH REQUESTOR "/databases/su.sqlite" #define REQUESTOR_DATABASE_PATH REQUESTOR "/databases/su.db"
#define REQUESTOR_MULTIUSER_MODE REQUESTOR_FILES_PATH "/multiuser_mode" #define REQUESTOR_MULTIUSER_MODE REQUESTOR_FILES_PATH "/multiuser_mode"
#define DEFAULT_SHELL "/system/bin/sh" #define DEFAULT_SHELL "/system/bin/sh"
@ -77,10 +76,9 @@
#define str(a) #a #define str(a) #a
#ifndef VERSION_CODE #ifndef VERSION_CODE
#define VERSION_CODE 17 #define VERSION_CODE 1
#endif #endif
#define VERSION xstr(VERSION_CODE) " " REQUESTOR #define VERSION "MAGISKSU:" xstr(VERSION_CODE)
// #define VERSION REQUESTOR " topjohnwu r1"
#define PROTO_VERSION 1 #define PROTO_VERSION 1
@ -123,17 +121,10 @@ struct su_user_info {
char database_path[PATH_MAX]; char database_path[PATH_MAX];
}; };
struct su_bind {
const char *from;
const char *to;
};
struct su_context { struct su_context {
struct su_initiator from; struct su_initiator from;
struct su_request to; struct su_request to;
struct su_user_info user; struct su_user_info user;
struct su_bind bind;
const char *init;
mode_t umask; mode_t umask;
char sock_path[PATH_MAX]; char sock_path[PATH_MAX];
}; };