diff --git a/su.c b/su.c index f99bca040..6c27a7e60 100644 --- a/su.c +++ b/su.c @@ -8,6 +8,7 @@ /* su.c - The main function running in the daemon */ +#define _GNU_SOURCE #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -45,7 +47,10 @@ static void usage(int status) { " -u display the multiuser mode and exit\n" " -v, --version display version number and exit\n" " -V display version code and exit,\n" - " this is used almost exclusively by Superuser.apk\n"); + " this is used almost exclusively by Superuser.apk\n" + " -mm, -M,\n" + " --mount-master run in the global mount namespace,\n" + " use if you need to publicly apply mounts"); exit2(status); } @@ -189,14 +194,6 @@ int su_daemon_main(int argc, char **argv) { } } - // Replace -cn with z, for CF compatibility - for (int i = 0; i < argc; ++i) { - if (strcmp(argv[i], "-cn") == 0) { - strcpy(argv[i], "-z"); - break; - } - } - int c, socket_serv_fd, fd; char result[64]; struct option long_opts[] = { @@ -207,10 +204,11 @@ int su_daemon_main(int argc, char **argv) { { "shell", required_argument, NULL, 's' }, { "version", no_argument, NULL, 'v' }, { "context", required_argument, NULL, 'z' }, + { "mount-master", no_argument, NULL, 'M' }, { NULL, 0, NULL, 0 }, }; - while ((c = getopt_long(argc, argv, "c:hlmps:Vvuz:", long_opts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "c:hlmps:Vvuz:M", long_opts, NULL)) != -1) { switch (c) { case 'c': su_ctx->to.command = concat_commands(argc, argv); @@ -252,6 +250,9 @@ int su_daemon_main(int argc, char **argv) { case 'z': // Do nothing, placed here for legacy support :) break; + case 'M': + su_ctx->info->mnt_ns = NAMESPACE_MODE_GLOBAL; + break; default: /* Bionic getopt_long doesn't terminate its error output by newline */ fprintf(stderr, "\n"); @@ -293,6 +294,27 @@ int su_daemon_main(int argc, char **argv) { // Setup done, now every error leads to deny err_handler = deny; + // Handle namespaces + switch (su_ctx->info->mnt_ns) { + case NAMESPACE_MODE_GLOBAL: + LOGD("su: use global namespace\n"); + break; + case NAMESPACE_MODE_REQUESTER: + LOGD("su: use namespace of pid=[%d]\n", su_ctx->pid); + if (switch_mnt_ns(su_ctx->pid)) { + LOGD("su: setns failed, fallback to isolated\n"); + unshare(CLONE_NEWNS); + } + break; + case NAMESPACE_MODE_ISOLATE: + LOGD("su: use new isolated namespace\n"); + unshare(CLONE_NEWNS); + break; + } + + // Change directory to cwd + chdir(su_ctx->cwd); + // Check root_access configuration switch (su_ctx->info->root_access) { case ROOT_ACCESS_DISABLED: @@ -317,6 +339,19 @@ int su_daemon_main(int argc, char **argv) { // New request or no db exist, notify user for response if (su_ctx->info->policy == QUERY) { + mkdir(REQUESTOR_CACHE_PATH, 0770); + if (chown(REQUESTOR_CACHE_PATH, su_ctx->st.st_uid, su_ctx->st.st_gid)) + PLOGE("chown (%s, %u, %u)", REQUESTOR_CACHE_PATH, su_ctx->st.st_uid, su_ctx->st.st_gid); + + if (setgroups(0, NULL)) + PLOGE("setgroups"); + + if (setegid(su_ctx->st.st_gid)) + PLOGE("setegid (%u)", su_ctx->st.st_gid); + + if (seteuid(su_ctx->st.st_uid)) + PLOGE("seteuid (%u)", su_ctx->st.st_uid); + socket_serv_fd = socket_create_temp(su_ctx->sock_path, sizeof(su_ctx->sock_path)); setup_sighandlers(cleanup_signal); diff --git a/su.h b/su.h index 4c8775cbf..3742ce39f 100644 --- a/su.h +++ b/su.h @@ -6,6 +6,7 @@ #include #include +#include #include "list.h" @@ -101,6 +102,8 @@ struct su_context { pid_t pid; int notify; mode_t umask; + char *cwd; + struct stat st; char sock_path[PATH_MAX]; }; diff --git a/su_daemon.c b/su_daemon.c index 1639570a8..b4b083ba0 100644 --- a/su_daemon.c +++ b/su_daemon.c @@ -1,7 +1,7 @@ /* su_client.c - The entrypoint for su, connect to daemon and send correct info */ -#define _GNU_SOURCE +#define _GNU_SOURCE #include #include #include @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -159,11 +158,10 @@ void su_daemon_receiver(int client) { USER_DATA_PATH, su_ctx->user.android_user_id, REQUESTOR); // verify if Magisk Manager is installed - struct stat st; - xstat(su_ctx->user.base_path, &st); + xstat(su_ctx->user.base_path, &su_ctx->st); // odd perms on superuser data dir - if (st.st_gid != st.st_uid) { - LOGE("Bad uid/gid %d/%d for Superuser Requestor application", st.st_uid, st.st_gid); + if (su_ctx->st.st_gid != su_ctx->st.st_uid) { + LOGE("Bad uid/gid %d/%d for Superuser Requestor application", su_ctx->st.st_uid, su_ctx->st.st_gid); info->policy = DENY; } @@ -180,7 +178,7 @@ void su_daemon_receiver(int client) { } // always allow if this is Magisk Manager - if (info->policy == QUERY && (info->uid % 100000) == (st.st_uid % 100000)) { + if (info->policy == QUERY && (info->uid % 100000) == (su_ctx->st.st_uid % 100000)) { info->policy = ALLOW; info->root_access = ROOT_ACCESS_APPS_AND_ADB; su_ctx->notify = 0; @@ -251,24 +249,6 @@ void su_daemon_receiver(int client) { // Become session leader xsetsid(); - // Handle namespaces - switch (info->mnt_ns) { - case NAMESPACE_MODE_GLOBAL: - LOGD("su: use global namespace\n"); - break; - case NAMESPACE_MODE_REQUESTER: - LOGD("su: use namespace of pid=[%d]\n", su_ctx->pid); - if (switch_mnt_ns(su_ctx->pid)) { - LOGD("su: setns failed, fallback to isolated\n"); - unshare(CLONE_NEWNS); - } - break; - case NAMESPACE_MODE_ISOLATE: - LOGD("su: use new isolated namespace\n"); - unshare(CLONE_NEWNS); - break; - } - // Let's read some info from the socket int argc = read_int(client); if (argc < 0 || argc > 512) { @@ -282,13 +262,16 @@ void su_daemon_receiver(int client) { for (int i = 0; i < argc; i++) { argv[i] = read_string(client); LOGD("su: argv[%d]=[%s]\n", i, argv[i]); + // Replace -cn with -z, -mm with -M for supporting getopt_long + if (strcmp(argv[i], "-cn") == 0) + strcpy(argv[i], "-z"); + else if (strcmp(argv[i], "-mm") == 0) + strcpy(argv[i], "-M"); } - // Change directory to cwd - char *cwd = read_string(client); - LOGD("su: cwd=[%s]\n", cwd); - chdir(cwd); - free(cwd); + // Get cwd + su_ctx->cwd = read_string(client); + LOGD("su: cwd=[%s]\n", su_ctx->cwd); // Get pts_slave char *pts_slave = read_string(client); @@ -342,20 +325,6 @@ void su_daemon_receiver(int client) { close(ptsfd); - mkdir(REQUESTOR_CACHE_PATH, 0770); - - if (chown(REQUESTOR_CACHE_PATH, st.st_uid, st.st_gid)) - PLOGE("chown (%s, %u, %u)", REQUESTOR_CACHE_PATH, st.st_uid, st.st_gid); - - if (setgroups(0, NULL)) - PLOGE("setgroups"); - - if (setegid(st.st_gid)) - PLOGE("setegid (%u)", st.st_gid); - - if (seteuid(st.st_uid)) - PLOGE("seteuid (%u)", st.st_uid); - su_daemon_main(argc, argv); }