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() {
if (getuid() != 0 || getgid() != 0) {
if (getuid() != AID_ROOT || getgid() != AID_ROOT) {
PLOGE("daemon requires root. uid/gid not root");
return -1;
}
@ -455,13 +455,19 @@ int run_daemon() {
break;
case -1:
PLOGE("fork");
return 1;
return -1;
default:
return 0;
}
if (setsid() < 0 || setcon("u:r:su_daemon:s0") < 0)
return 1;
if (setsid() < 0) {
PLOGE("setsid");
return -1;
}
if (setcon("u:r:su_daemon:s0") < 0) {
PLOGE("setcon");
return -1;
}
int fd;
struct sockaddr_un sun;
@ -478,32 +484,17 @@ int run_daemon() {
memset(&sun, 0, sizeof(sun));
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(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) {
PLOGE("daemon bind");
goto err;
}
chmod(REQUESTOR_DAEMON_PATH, 0755);
chmod(sun.sun_path, 0777);
umask(previous_umask);
if (listen(fd, 10) < 0) {
PLOGE("daemon listen");
goto err;
@ -600,10 +591,7 @@ int connect_daemon(int argc, char *argv[], int ppid) {
memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_LOCAL;
sprintf(sun.sun_path, "%s/server", REQUESTOR_DAEMON_PATH);
memset(sun.sun_path, 0, sizeof(sun.sun_path));
memcpy(sun.sun_path, "\0" "SUPERUSER", strlen("SUPERUSER") + 1);
strcpy(sun.sun_path, REQUESTOR_DAEMON_PATH);
if (0 != connect(socketfd, (struct sockaddr*)&sun, sizeof(sun))) {
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){
struct callback_data_t *data = (struct callback_data_t *)v;
int command_match = 0;
policy_t policy = DENY;
policy_t policy = INTERACTIVE;
int i;
time_t until = 0;
for(i = 0; i < argc; i++) {
if (strcmp(azColName[i], "policy") == 0) {
if (argv[i] == NULL) {
policy = DENY;
if (argv[i] != NULL) {
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) {
if (argv[i] != NULL) {
until = atoi(argv[i]);
until = atol(argv[i]);
}
}
}
// check for command match
if (command_match) {
// also make sure this policy has not expired
if (until == 0 || until > time(NULL)) {
if (policy == DENY) {
data->policy = DENY;
return -1;
}
data->policy = ALLOW;
// even though we allow, continue, so we can see if there's another policy
// that denies...
}
if (policy == DENY) {
data->policy = DENY;
return -1;
} else if (policy == ALLOW && (until == 0 || until > time(NULL))) {
data->policy = ALLOW;
// even though we allow, continue, so we can see if there's another policy
// that denies...
}
return 0;
}
@ -81,7 +61,7 @@ policy_t database_check(struct su_context *ctx) {
sqlite3 *db = NULL;
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);
if (ret) {
LOGE("sqlite3 open failure: %d", ret);
@ -89,7 +69,6 @@ policy_t database_check(struct su_context *ctx) {
return INTERACTIVE;
}
int result;
char *err = NULL;
struct callback_data_t data;
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, "to.uid", ctx->to.uid);
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
write_string_data(fd, "command", get_command(&ctx->to));
write_token(fd, "eof", PROTO_VERSION);
@ -510,12 +507,6 @@ static __attribute__ ((noreturn)) void allow(struct su_context *ctx) {
if (send_to_app)
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;
argc = ctx->to.optind;
if (ctx->to.command) {
@ -712,11 +703,6 @@ int su_main_nodaemon(int argc, char **argv) {
.database_path = REQUESTOR_DATA_PATH REQUESTOR_DATABASE_PATH,
.base_path = REQUESTOR_DATA_PATH REQUESTOR
},
.bind = {
.from = "",
.to = "",
},
.init = "",
};
struct stat st;
int c, socket_serv_fd, fd;
@ -756,7 +742,7 @@ int su_main_nodaemon(int argc, char **argv) {
printf("%d\n", VERSION_CODE);
exit(EXIT_SUCCESS);
case 'v':
printf("%s cm-su topjohnwu\n", VERSION);
printf("%s\n", VERSION);
exit(EXIT_SUCCESS);
case 'u':
switch (get_multiuser_mode()) {
@ -851,12 +837,6 @@ int su_main_nodaemon(int argc, char **argv) {
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
if (ctx.user.multiuser_mode == MULTIUSER_MODE_OWNER_ONLY && ctx.user.android_user_id != 0) {
deny(&ctx);
@ -883,7 +863,6 @@ int su_main_nodaemon(int argc, char **argv) {
deny(&ctx);
}
//TODO: Ignore database check for init and bind?
dballow = database_check(&ctx);
switch (dballow) {
case INTERACTIVE:

23
su.h
View File

@ -46,29 +46,28 @@
#define CM_ROOT_ACCESS_APPS_AND_ADB 3
// 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
// must be changed to correspond to the new APK package name
// See the two Android.mk files for more details.
#ifndef REQUESTOR
#define REQUESTOR "me.phh.superuser"
#define REQUESTOR JAVA_PACKAGE_NAME
#endif
// This is used if wrapping the fragment classes and activities
// with classes in another package. CM requirement.
#ifndef REQUESTOR_PREFIX
#define REQUESTOR_PREFIX JAVA_PACKAGE_NAME
#define REQUESTOR_PREFIX JAVA_PACKAGE_NAME ".superuser"
#endif
#define REQUESTOR_DATA_PATH "/data/data/"
#define REQUESTOR_FILES_PATH REQUESTOR_DATA_PATH REQUESTOR "/files"
#define REQUESTOR_USER_PATH "/data/user/"
#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
// SQLiteOpenHelper, etc. Though that is the behavior as of current.
// 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 DEFAULT_SHELL "/system/bin/sh"
@ -77,10 +76,9 @@
#define str(a) #a
#ifndef VERSION_CODE
#define VERSION_CODE 17
#define VERSION_CODE 1
#endif
#define VERSION xstr(VERSION_CODE) " " REQUESTOR
// #define VERSION REQUESTOR " topjohnwu r1"
#define VERSION "MAGISKSU:" xstr(VERSION_CODE)
#define PROTO_VERSION 1
@ -123,17 +121,10 @@ struct su_user_info {
char database_path[PATH_MAX];
};
struct su_bind {
const char *from;
const char *to;
};
struct su_context {
struct su_initiator from;
struct su_request to;
struct su_user_info user;
struct su_bind bind;
const char *init;
mode_t umask;
char sock_path[PATH_MAX];
};