Add mount-master option

This commit is contained in:
topjohnwu 2017-07-08 01:12:47 +08:00
parent 7c4d5cee95
commit 60ca704a9e
3 changed files with 61 additions and 54 deletions

55
su.c
View File

@ -8,6 +8,7 @@
/* su.c - The main function running in the daemon /* su.c - The main function running in the daemon
*/ */
#define _GNU_SOURCE
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -17,6 +18,7 @@
#include <pwd.h> #include <pwd.h>
#include <errno.h> #include <errno.h>
#include <signal.h> #include <signal.h>
#include <sched.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/auxv.h> #include <sys/auxv.h>
@ -45,7 +47,10 @@ static void usage(int status) {
" -u display the multiuser mode and exit\n" " -u display the multiuser mode and exit\n"
" -v, --version display version number and exit\n" " -v, --version display version number and exit\n"
" -V display version code 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); 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; int c, socket_serv_fd, fd;
char result[64]; char result[64];
struct option long_opts[] = { struct option long_opts[] = {
@ -207,10 +204,11 @@ int su_daemon_main(int argc, char **argv) {
{ "shell", required_argument, NULL, 's' }, { "shell", required_argument, NULL, 's' },
{ "version", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'v' },
{ "context", required_argument, NULL, 'z' }, { "context", required_argument, NULL, 'z' },
{ "mount-master", no_argument, NULL, 'M' },
{ NULL, 0, NULL, 0 }, { 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) { switch (c) {
case 'c': case 'c':
su_ctx->to.command = concat_commands(argc, argv); su_ctx->to.command = concat_commands(argc, argv);
@ -252,6 +250,9 @@ int su_daemon_main(int argc, char **argv) {
case 'z': case 'z':
// Do nothing, placed here for legacy support :) // Do nothing, placed here for legacy support :)
break; break;
case 'M':
su_ctx->info->mnt_ns = NAMESPACE_MODE_GLOBAL;
break;
default: default:
/* Bionic getopt_long doesn't terminate its error output by newline */ /* Bionic getopt_long doesn't terminate its error output by newline */
fprintf(stderr, "\n"); fprintf(stderr, "\n");
@ -293,6 +294,27 @@ int su_daemon_main(int argc, char **argv) {
// Setup done, now every error leads to deny // Setup done, now every error leads to deny
err_handler = 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 // Check root_access configuration
switch (su_ctx->info->root_access) { switch (su_ctx->info->root_access) {
case ROOT_ACCESS_DISABLED: 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 // New request or no db exist, notify user for response
if (su_ctx->info->policy == QUERY) { 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)); socket_serv_fd = socket_create_temp(su_ctx->sock_path, sizeof(su_ctx->sock_path));
setup_sighandlers(cleanup_signal); setup_sighandlers(cleanup_signal);

3
su.h
View File

@ -6,6 +6,7 @@
#include <limits.h> #include <limits.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h>
#include "list.h" #include "list.h"
@ -101,6 +102,8 @@ struct su_context {
pid_t pid; pid_t pid;
int notify; int notify;
mode_t umask; mode_t umask;
char *cwd;
struct stat st;
char sock_path[PATH_MAX]; char sock_path[PATH_MAX];
}; };

View File

@ -10,7 +10,6 @@
#include <fcntl.h> #include <fcntl.h>
#include <string.h> #include <string.h>
#include <signal.h> #include <signal.h>
#include <sched.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -159,11 +158,10 @@ void su_daemon_receiver(int client) {
USER_DATA_PATH, su_ctx->user.android_user_id, REQUESTOR); USER_DATA_PATH, su_ctx->user.android_user_id, REQUESTOR);
// verify if Magisk Manager is installed // verify if Magisk Manager is installed
struct stat st; xstat(su_ctx->user.base_path, &su_ctx->st);
xstat(su_ctx->user.base_path, &st);
// odd perms on superuser data dir // odd perms on superuser data dir
if (st.st_gid != st.st_uid) { if (su_ctx->st.st_gid != su_ctx->st.st_uid) {
LOGE("Bad uid/gid %d/%d for Superuser Requestor application", st.st_uid, st.st_gid); LOGE("Bad uid/gid %d/%d for Superuser Requestor application", su_ctx->st.st_uid, su_ctx->st.st_gid);
info->policy = DENY; info->policy = DENY;
} }
@ -180,7 +178,7 @@ void su_daemon_receiver(int client) {
} }
// always allow if this is Magisk Manager // 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->policy = ALLOW;
info->root_access = ROOT_ACCESS_APPS_AND_ADB; info->root_access = ROOT_ACCESS_APPS_AND_ADB;
su_ctx->notify = 0; su_ctx->notify = 0;
@ -251,24 +249,6 @@ void su_daemon_receiver(int client) {
// Become session leader // Become session leader
xsetsid(); 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 // Let's read some info from the socket
int argc = read_int(client); int argc = read_int(client);
if (argc < 0 || argc > 512) { if (argc < 0 || argc > 512) {
@ -282,13 +262,16 @@ void su_daemon_receiver(int client) {
for (int i = 0; i < argc; i++) { for (int i = 0; i < argc; i++) {
argv[i] = read_string(client); argv[i] = read_string(client);
LOGD("su: argv[%d]=[%s]\n", i, argv[i]); 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 // Get cwd
char *cwd = read_string(client); su_ctx->cwd = read_string(client);
LOGD("su: cwd=[%s]\n", cwd); LOGD("su: cwd=[%s]\n", su_ctx->cwd);
chdir(cwd);
free(cwd);
// Get pts_slave // Get pts_slave
char *pts_slave = read_string(client); char *pts_slave = read_string(client);
@ -342,20 +325,6 @@ void su_daemon_receiver(int client) {
close(ptsfd); 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); su_daemon_main(argc, argv);
} }