Fully migrate Magisk to C++

This commit is contained in:
topjohnwu
2018-11-04 03:38:06 -05:00
parent 4351de503f
commit cda57dd4b4
27 changed files with 548 additions and 607 deletions

View File

@@ -19,7 +19,7 @@
#define AM_PATH "/system/bin/app_process", "/system/bin", "com.android.commands.am.Am"
static char *get_command(const struct su_request *to) {
static const char *get_command(const struct su_request *to) {
if (to->command[0])
return to->command;
if (to->shell[0])
@@ -27,7 +27,7 @@ static char *get_command(const struct su_request *to) {
return DEFAULT_SHELL;
}
static void silent_run(char * const args[]) {
static void silent_run(const char *args[]) {
if (fork_dont_care())
return;
int zero = open("/dev/zero", O_RDONLY | O_CLOEXEC);
@@ -36,7 +36,7 @@ static void silent_run(char * const args[]) {
xdup2(null, 1);
xdup2(null, 2);
setenv("CLASSPATH", "/system/framework/am.jar", 1);
execv(args[0], args);
execv(args[0], (char **) args);
PLOGE("exec am");
_exit(EXIT_FAILURE);
}
@@ -71,7 +71,7 @@ void app_log(struct su_context *ctx) {
char policy[2];
sprintf(policy, "%d", ctx->info->access.policy);
char *cmd[] = {
const char *cmd[] = {
AM_PATH, "broadcast",
"-a", "android.intent.action.BOOT_COMPLETED",
"-p", DB_STR(ctx->info, SU_MANAGER),
@@ -84,7 +84,7 @@ void app_log(struct su_context *ctx) {
"--ei", "policy", policy,
"--es", "command", get_command(&ctx->req),
"--ez", "notify", ctx->info->access.notify ? "true" : "false",
NULL
nullptr
};
silent_run(cmd);
}
@@ -101,7 +101,7 @@ void app_notify(struct su_context *ctx) {
char policy[2];
sprintf(policy, "%d", ctx->info->access.policy);
char *cmd[] = {
const char *cmd[] = {
AM_PATH, "broadcast",
"-a", "android.intent.action.BOOT_COMPLETED",
"-p", DB_STR(ctx->info, SU_MANAGER),
@@ -110,7 +110,7 @@ void app_notify(struct su_context *ctx) {
"--es", "action", "notify",
"--ei", "from.uid", fromUid,
"--ei", "policy", policy,
NULL
nullptr
};
silent_run(cmd);
}
@@ -118,15 +118,15 @@ void app_notify(struct su_context *ctx) {
void app_connect(const char *socket, struct su_info *info) {
char user[8];
setup_user(user, info);
char *cmd[] = {
const char *cmd[] = {
AM_PATH, "broadcast",
"-a", "android.intent.action.BOOT_COMPLETED",
"-p", DB_STR(info, SU_MANAGER),
"-f", "0x00000020",
"--user", user,
"--es", "action", "request",
"--es", "socket", (char *) socket,
NULL
"--es", "socket", socket,
nullptr
};
silent_run(cmd);
}
@@ -135,4 +135,3 @@ void socket_send_request(int fd, struct su_info *info) {
write_key_token(fd, "uid", info->uid);
write_string_be(fd, "eof");
}

View File

@@ -9,7 +9,6 @@
* helper functions to handle raw input mode and terminal window resizing
*/
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

View File

@@ -8,7 +8,6 @@
/* su.c - The main function running in the daemon
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -95,6 +94,12 @@ static void setup_sighandlers(void (*handler)(int)) {
}
}
// Default values
su_req_base::su_req_base()
: uid(UID_ROOT), login(false), keepenv(false), mount_master(false) {}
su_request::su_request()
: shell(DEFAULT_SHELL), command("") {}
/*
* Connect daemon, send argc, argv, cwd, pts slave
*/
@@ -112,15 +117,7 @@ int su_client_main(int argc, char *argv[]) {
{ NULL, 0, NULL, 0 },
};
struct su_request su_req = {
.uid = UID_ROOT,
.login = 0,
.keepenv = 0,
.mount_master = 0,
.shell = DEFAULT_SHELL,
.command = "",
};
su_request su_req;
for (int i = 0; i < argc; i++) {
// Replace -cn with -z, -mm with -M for supporting getopt_long
@@ -140,11 +137,11 @@ int su_client_main(int argc, char *argv[]) {
usage(EXIT_SUCCESS);
break;
case 'l':
su_req.login = 1;
su_req.login = true;
break;
case 'm':
case 'p':
su_req.keepenv = 1;
su_req.keepenv = true;
break;
case 's':
su_req.shell = optarg;
@@ -159,7 +156,7 @@ int su_client_main(int argc, char *argv[]) {
// Do nothing, placed here for legacy support :)
break;
case 'M':
su_req.mount_master = 1;
su_req.mount_master = true;
break;
default:
/* Bionic getopt_long doesn't terminate its error output by newline */
@@ -169,7 +166,7 @@ int su_client_main(int argc, char *argv[]) {
}
if (optind < argc && strcmp(argv[optind], "-") == 0) {
su_req.login = 1;
su_req.login = true;
optind++;
}
/* username or uid */
@@ -200,7 +197,7 @@ int su_client_main(int argc, char *argv[]) {
}
// Send su_request
xwrite(fd, &su_req, 4 * sizeof(unsigned));
xwrite(fd, &su_req, sizeof(su_req_base));
write_string(fd, su_req.shell);
write_string(fd, su_req.command);
@@ -242,4 +239,4 @@ int su_client_main(int argc, char *argv[]) {
close(fd);
return code;
}
}

View File

@@ -17,9 +17,9 @@
#define ATTY_OUT 2
#define ATTY_ERR 4
struct su_info {
class su_info {
public:
unsigned uid; /* Unique 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 */
@@ -31,19 +31,33 @@ struct su_info {
/* These should be guarded with global cache lock */
int ref;
int life;
su_info(unsigned uid);
~su_info();
void lock();
void unlock();
private:
pthread_mutex_t _lock; /* Internal lock */
};
#define DB_SET(i, e) (i)->dbs.v[e]
#define DB_STR(i, e) (i)->str.s[e]
struct su_request {
struct su_req_base {
unsigned uid;
unsigned login;
unsigned keepenv;
unsigned mount_master;
char *shell;
char *command;
};
bool login;
bool keepenv;
bool mount_master;
protected:
su_req_base();
} __attribute__((packed));
struct su_request : public su_req_base {
const char *shell;
const char *command;
su_request();
} __attribute__((packed));
struct su_context {
struct su_info *info;

View File

@@ -1,8 +1,3 @@
/* su_daemon.c - The entrypoint for su, connect to daemon and send correct info
*/
#define _GNU_SOURCE
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
@@ -25,32 +20,45 @@
#define TIMEOUT 3
#define LOCK_CACHE() pthread_mutex_lock(&cache_lock)
#define LOCK_INFO() pthread_mutex_lock(&info->lock)
#define UNLOCK_CACHE() pthread_mutex_unlock(&cache_lock)
#define UNLOCK_INFO() pthread_mutex_unlock(&info->lock)
static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
static struct su_info *cache;
static su_info *cache;
su_info::su_info(unsigned uid) :
uid(uid), access(DEFAULT_SU_ACCESS), _lock(PTHREAD_MUTEX_INITIALIZER),
count(0), ref(0), life(0), mgr_st({}) {}
su_info::~su_info() {
pthread_mutex_destroy(&_lock);
}
void su_info::lock() {
pthread_mutex_lock(&_lock);
}
void su_info::unlock() {
pthread_mutex_unlock(&_lock);
}
static void *info_collector(void *node) {
struct su_info *info = node;
su_info *info = (su_info *) node;
while (1) {
sleep(1);
if (info->life) {
LOCK_CACHE();
if (--info->life == 0 && cache && info->uid == cache->uid)
cache = NULL;
cache = nullptr;
UNLOCK_CACHE();
}
if (!info->life && !info->ref) {
pthread_mutex_destroy(&info->lock);
free(info);
return NULL;
delete info;
return nullptr;
}
}
}
static void database_check(struct su_info *info) {
static void database_check(su_info *info) {
int uid = info->uid;
sqlite3 *db = get_magiskdb();
if (db) {
@@ -84,20 +92,16 @@ static void database_check(struct su_info *info) {
}
static struct su_info *get_su_info(unsigned uid) {
struct su_info *info;
int cache_miss = 0;
su_info *info;
bool cache_miss = false;
LOCK_CACHE();
if (cache && cache->uid == uid) {
info = cache;
} else {
cache_miss = 1;
info = xcalloc(1, sizeof(*info));
info->uid = uid;
info->dbs = DEFAULT_DB_SETTINGS;
info->access = DEFAULT_SU_ACCESS;
pthread_mutex_init(&info->lock, NULL);
cache_miss = true;
info = new su_info(uid);
cache = info;
}
@@ -108,7 +112,7 @@ static struct su_info *get_su_info(unsigned uid) {
// Start a thread to maintain the cache
if (cache_miss) {
pthread_t thread;
xpthread_create(&thread, NULL, info_collector, info);
xpthread_create(&thread, nullptr, info_collector, info);
pthread_detach(thread);
}
@@ -117,7 +121,7 @@ static struct su_info *get_su_info(unsigned uid) {
LOGD("su: request from uid=[%d] (#%d)\n", info->uid, ++info->count);
// Lock before the policy is determined
LOCK_INFO();
info->lock();
if (info->access.policy == QUERY) {
// Not cached, get data from database
@@ -173,14 +177,14 @@ static struct su_info *get_su_info(unsigned uid) {
} else {
socket_send_request(fd, info);
int ret = read_int_be(fd);
info->access.policy = ret < 0 ? DENY : ret;
info->access.policy = ret < 0 ? DENY : static_cast<policy_t>(ret);
close(fd);
}
close(sockfd);
}
// Unlock
UNLOCK_INFO();
info->unlock();
return info;
}
@@ -224,7 +228,7 @@ static void set_identity(unsigned uid) {
void su_daemon_handler(int client, struct ucred *credential) {
LOGD("su: request from client: %d\n", client);
struct su_info *info = get_su_info(credential->uid);
su_info *info = get_su_info(credential->uid);
// Fail fast
if (info->access.policy == DENY && DB_STR(info, SU_MANAGER)[0] == '\0') {
@@ -289,7 +293,7 @@ void su_daemon_handler(int client, struct ucred *credential) {
}
// Read su_request
xxread(client, &ctx.req, 4 * sizeof(unsigned));
xxread(client, &ctx.req, sizeof(su_req_base));
ctx.req.shell = read_string(client);
ctx.req.command = read_string(client);
@@ -367,7 +371,7 @@ void su_daemon_handler(int client, struct ucred *credential) {
app_notify(&ctx);
if (info->access.policy == ALLOW) {
char* argv[] = { NULL, NULL, NULL, NULL };
const char *argv[] = { nullptr, nullptr, nullptr, nullptr };
argv[0] = ctx.req.login ? "-" : ctx.req.shell;
@@ -381,7 +385,7 @@ void su_daemon_handler(int client, struct ucred *credential) {
populate_environment(&ctx.req);
set_identity(ctx.req.uid);
execvp(ctx.req.shell, argv);
execvp(ctx.req.shell, (char **) argv);
fprintf(stderr, "Cannot execute %s: %s\n", ctx.req.shell, strerror(errno));
PLOGE("exec");
exit(EXIT_FAILURE);
@@ -391,4 +395,3 @@ void su_daemon_handler(int client, struct ucred *credential) {
exit(EXIT_FAILURE);
}
}