Update su to match Linux's implementation
This commit is contained in:
parent
257308d5db
commit
b0c1a6f73a
@ -74,7 +74,7 @@ void app_send_result(struct su_context *ctx, policy_t policy) {
|
||||
int notify = setup_user(ctx, user);
|
||||
|
||||
char activity[128];
|
||||
sprintf(activity, ACTION_RESULT, ctx->pkg_name);
|
||||
sprintf(activity, ACTION_RESULT, ctx->info->pkg_name);
|
||||
|
||||
// Send notice to manager, enable logging
|
||||
char *result_command[] = {
|
||||
@ -113,7 +113,7 @@ void app_send_request(struct su_context *ctx) {
|
||||
int notify = setup_user(ctx, user);
|
||||
|
||||
char activity[128];
|
||||
sprintf(activity, ACTION_REQUEST, ctx->pkg_name);
|
||||
sprintf(activity, ACTION_REQUEST, ctx->info->pkg_name);
|
||||
|
||||
char *request_command[] = {
|
||||
AM_PATH, "start", "-n",
|
||||
@ -128,7 +128,7 @@ void app_send_request(struct su_context *ctx) {
|
||||
// Send notice to user to tell them root is managed by owner
|
||||
if (notify) {
|
||||
sprintf(user, "%d", notify);
|
||||
sprintf(activity, ACTION_RESULT, ctx->pkg_name);
|
||||
sprintf(activity, ACTION_RESULT, ctx->info->pkg_name);
|
||||
char *notify_command[] = {
|
||||
AM_PATH, "broadcast", "-n",
|
||||
activity,
|
||||
|
12
db.c
12
db.c
@ -63,7 +63,7 @@ static int strings_callback(void *v, int argc, char **argv, char **azColName) {
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if (strcmp(azColName[i], "key") == 0) {
|
||||
if (strcmp(argv[i], REQUESTER_ENTRY) == 0)
|
||||
target = ctx->pkg_name;
|
||||
target = ctx->info->pkg_name;
|
||||
entry = argv[i];
|
||||
} else if (strcmp(azColName[i], "value") == 0) {
|
||||
value = argv[i];
|
||||
@ -84,7 +84,7 @@ void database_check(struct su_context *ctx) {
|
||||
ctx->info->root_access = ROOT_ACCESS_APPS_AND_ADB;
|
||||
ctx->info->multiuser_mode = MULTIUSER_MODE_OWNER_ONLY;
|
||||
ctx->info->mnt_ns = NAMESPACE_MODE_REQUESTER;
|
||||
strcpy(ctx->pkg_name, "???"); /* bad string so it doesn't exist */
|
||||
strcpy(ctx->info->pkg_name, "???"); /* bad string so it doesn't exist */
|
||||
|
||||
// Open database
|
||||
ret = sqlite3_open_v2(DATABASE_PATH, &db, SQLITE_OPEN_READONLY, NULL);
|
||||
@ -136,11 +136,11 @@ void database_check(struct su_context *ctx) {
|
||||
stat_requester:
|
||||
// We prefer the original name
|
||||
sprintf(buffer, "%s/0/" JAVA_PACKAGE_NAME, base);
|
||||
if (stat(buffer, &ctx->st) == 0) {
|
||||
strcpy(ctx->pkg_name, JAVA_PACKAGE_NAME);
|
||||
if (stat(buffer, &ctx->info->st) == 0) {
|
||||
strcpy(ctx->info->pkg_name, JAVA_PACKAGE_NAME);
|
||||
} else {
|
||||
sprintf(buffer, "%s/0/%s", base, ctx->pkg_name);
|
||||
if (stat(buffer, &ctx->st) == -1) {
|
||||
sprintf(buffer, "%s/0/%s", base, ctx->info->pkg_name);
|
||||
if (stat(buffer, &ctx->info->st) == -1) {
|
||||
LOGE("su: cannot find requester");
|
||||
ctx->info->policy = DENY;
|
||||
ctx->notify = 0;
|
||||
|
93
su.c
93
su.c
@ -19,6 +19,7 @@
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sched.h>
|
||||
#include <libgen.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/auxv.h>
|
||||
@ -35,15 +36,14 @@ static void usage(int status) {
|
||||
|
||||
fprintf(stream,
|
||||
"MagiskSU v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ")\n\n"
|
||||
"Usage: su [options] [--] [-] [LOGIN] [--] [args...]\n\n"
|
||||
"Usage: su [options] [-] [user [argument...]]\n\n"
|
||||
"Options:\n"
|
||||
" -c, --command COMMAND pass COMMAND to the invoked shell\n"
|
||||
" -h, --help display this help message and exit\n"
|
||||
" -, -l, --login pretend the shell to be a login shell\n"
|
||||
" -m, -p,\n"
|
||||
" --preserve-environment do not change environment variables\n"
|
||||
" --preserve-environment preserve the entire environment\n"
|
||||
" -s, --shell SHELL use SHELL instead of the default " DEFAULT_SHELL "\n"
|
||||
" -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"
|
||||
@ -57,10 +57,10 @@ static char *concat_commands(int argc, char *argv[]) {
|
||||
char command[ARG_MAX];
|
||||
command[0] = '\0';
|
||||
for (int i = optind - 1; i < argc; ++i) {
|
||||
if (strlen(command))
|
||||
if (command[0])
|
||||
sprintf(command, "%s %s", command, argv[i]);
|
||||
else
|
||||
sprintf(command, "%s", argv[i]);
|
||||
strcpy(command, argv[i]);
|
||||
}
|
||||
return strdup(command);
|
||||
}
|
||||
@ -102,37 +102,29 @@ void set_identity(unsigned uid) {
|
||||
}
|
||||
|
||||
static __attribute__ ((noreturn)) void allow() {
|
||||
char *arg0;
|
||||
|
||||
umask(su_ctx->umask);
|
||||
char* argv[] = { NULL, NULL, NULL, NULL };
|
||||
|
||||
if (su_ctx->notify)
|
||||
app_send_result(su_ctx, ALLOW);
|
||||
|
||||
char *binary = su_ctx->to.shell;
|
||||
if (su_ctx->to.login)
|
||||
argv[0] = "-";
|
||||
else
|
||||
argv[0] = basename(su_ctx->to.shell);
|
||||
|
||||
if (su_ctx->to.command) {
|
||||
su_ctx->to.argv[--su_ctx->to.argc] = su_ctx->to.command;
|
||||
su_ctx->to.argv[--su_ctx->to.argc] = "-c";
|
||||
}
|
||||
|
||||
arg0 = strrchr(binary, '/');
|
||||
arg0 = arg0 ? (arg0 + 1) : binary;
|
||||
if (su_ctx->to.login) {
|
||||
int s = strlen(arg0) + 2;
|
||||
char *p = xmalloc(s);
|
||||
*p = '-';
|
||||
strcpy(p + 1, arg0);
|
||||
arg0 = p;
|
||||
argv[1] = "-c";
|
||||
argv[2] = su_ctx->to.command;
|
||||
}
|
||||
|
||||
// Setup shell
|
||||
umask(022);
|
||||
populate_environment(su_ctx);
|
||||
set_identity(su_ctx->to.uid);
|
||||
|
||||
setexeccon("u:r:su:s0");
|
||||
|
||||
su_ctx->to.argv[--su_ctx->to.argc] = arg0;
|
||||
execvp(binary, su_ctx->to.argv + su_ctx->to.argc);
|
||||
fprintf(stderr, "Cannot execute %s: %s\n", binary, strerror(errno));
|
||||
execvp(su_ctx->to.shell, argv);
|
||||
fprintf(stderr, "Cannot execute %s: %s\n", su_ctx->to.shell, strerror(errno));
|
||||
PLOGE("exec");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -199,15 +191,11 @@ int su_daemon_main(int argc, char **argv) {
|
||||
"LD_AOUT_PRELOAD",
|
||||
// not listed in linker, used due to system() call
|
||||
"IFS",
|
||||
NULL
|
||||
};
|
||||
if(getauxval(AT_SECURE)) {
|
||||
const char* const* cp = unsec_vars;
|
||||
const char* const* endp = cp + sizeof(unsec_vars)/sizeof(unsec_vars[0]);
|
||||
while (cp < endp) {
|
||||
unsetenv(*cp);
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
if (getauxval(AT_SECURE))
|
||||
for (int i = 0; unsec_vars[i]; ++i)
|
||||
unsetenv(unsec_vars[i]);
|
||||
|
||||
int c, socket_serv_fd, fd;
|
||||
char result[64];
|
||||
@ -249,19 +237,6 @@ int su_daemon_main(int argc, char **argv) {
|
||||
case 'v':
|
||||
printf("%s\n", MAGISKSU_VER_STR);
|
||||
exit2(EXIT_SUCCESS);
|
||||
case 'u':
|
||||
switch (su_ctx->info->multiuser_mode) {
|
||||
case MULTIUSER_MODE_USER:
|
||||
printf("Owner only: Only owner has root access\n");
|
||||
break;
|
||||
case MULTIUSER_MODE_OWNER_MANAGED:
|
||||
printf("Owner managed: Only owner can manage root access and receive request prompts\n");
|
||||
break;
|
||||
case MULTIUSER_MODE_OWNER_ONLY:
|
||||
printf("User independent: Each user has its own separate root rules\n");
|
||||
break;
|
||||
}
|
||||
exit2(EXIT_SUCCESS);
|
||||
case 'z':
|
||||
// Do nothing, placed here for legacy support :)
|
||||
break;
|
||||
@ -275,34 +250,18 @@ int su_daemon_main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
|
||||
su_ctx->to.argc = argc;
|
||||
su_ctx->to.argv = argv;
|
||||
|
||||
if (optind < argc && !strcmp(argv[optind], "-")) {
|
||||
if (optind < argc && strcmp(argv[optind], "-") == 0) {
|
||||
su_ctx->to.login = 1;
|
||||
optind++;
|
||||
}
|
||||
/* username or uid */
|
||||
if (optind < argc && strcmp(argv[optind], "--")) {
|
||||
if (optind < argc) {
|
||||
struct passwd *pw;
|
||||
pw = getpwnam(argv[optind]);
|
||||
if (!pw) {
|
||||
char *endptr;
|
||||
|
||||
/* It seems we shouldn't do this at all */
|
||||
errno = 0;
|
||||
su_ctx->to.uid = strtoul(argv[optind], &endptr, 10);
|
||||
if (errno || *endptr) {
|
||||
LOGE("Unknown id: %s\n", argv[optind]);
|
||||
fprintf(stderr, "Unknown id: %s\n", argv[optind]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else {
|
||||
if (pw)
|
||||
su_ctx->to.uid = pw->pw_uid;
|
||||
}
|
||||
optind++;
|
||||
}
|
||||
if (optind < argc && !strcmp(argv[optind], "--")) {
|
||||
else
|
||||
su_ctx->to.uid = atoi(argv[optind]);
|
||||
optind++;
|
||||
}
|
||||
|
||||
|
11
su.h
11
su.h
@ -59,6 +59,8 @@ struct su_info {
|
||||
int multiuser_mode;
|
||||
int root_access;
|
||||
int mnt_ns;
|
||||
char pkg_name[PATH_MAX];
|
||||
struct stat st;
|
||||
|
||||
/* These should be guarded with global list lock */
|
||||
struct list_head pos;
|
||||
@ -72,20 +74,15 @@ struct su_request {
|
||||
int keepenv;
|
||||
char *shell;
|
||||
char *command;
|
||||
char **argv;
|
||||
int argc;
|
||||
};
|
||||
|
||||
struct su_context {
|
||||
struct su_info *info;
|
||||
struct su_request to;
|
||||
char pkg_name[PATH_MAX];
|
||||
char sock_path[PATH_MAX];
|
||||
pid_t pid;
|
||||
int notify;
|
||||
mode_t umask;
|
||||
char *cwd;
|
||||
struct stat st;
|
||||
char cwd[PATH_MAX];
|
||||
char sock_path[PATH_MAX];
|
||||
int pipefd[2];
|
||||
};
|
||||
|
||||
|
41
su_daemon.c
41
su_daemon.c
@ -88,7 +88,7 @@ static void *collector(void *args) {
|
||||
}
|
||||
}
|
||||
|
||||
void su_daemon_receiver(int client) {
|
||||
void su_daemon_receiver(int client, struct ucred *credential) {
|
||||
LOGD("su: request from client: %d\n", client);
|
||||
|
||||
struct su_info *info = NULL, *node;
|
||||
@ -102,13 +102,9 @@ void su_daemon_receiver(int client) {
|
||||
xpthread_create(&su_collector, NULL, collector, NULL);
|
||||
}
|
||||
|
||||
// Get client credential
|
||||
struct ucred credential;
|
||||
get_client_cred(client, &credential);
|
||||
|
||||
// Search for existing in the active list
|
||||
list_for_each(node, &active_list, struct su_info, pos) {
|
||||
if (node->uid == credential.uid) {
|
||||
if (node->uid == credential->uid) {
|
||||
info = node;
|
||||
break;
|
||||
}
|
||||
@ -118,7 +114,7 @@ void su_daemon_receiver(int client) {
|
||||
if (info == NULL) {
|
||||
new_request = 1;
|
||||
info = malloc(sizeof(*info));
|
||||
info->uid = credential.uid;
|
||||
info->uid = credential->uid;
|
||||
info->policy = QUERY;
|
||||
info->ref = 0;
|
||||
info->count = 0;
|
||||
@ -142,8 +138,7 @@ void su_daemon_receiver(int client) {
|
||||
.shell = DEFAULT_SHELL,
|
||||
.command = NULL,
|
||||
},
|
||||
.pid = credential.pid,
|
||||
.umask = 022,
|
||||
.pid = credential->pid,
|
||||
.notify = new_request,
|
||||
};
|
||||
|
||||
@ -157,11 +152,11 @@ void su_daemon_receiver(int client) {
|
||||
|
||||
// Check requester
|
||||
if (info->policy == QUERY) {
|
||||
if (ctx.st.st_gid != ctx.st.st_uid) {
|
||||
LOGE("Bad uid/gid %d/%d for Superuser Requestor", ctx.st.st_uid, ctx.st.st_gid);
|
||||
if (info->st.st_gid != info->st.st_uid) {
|
||||
LOGE("Bad uid/gid %d/%d for Superuser Requestor", info->st.st_gid, info->st.st_uid);
|
||||
info->policy = DENY;
|
||||
ctx.notify = 0;
|
||||
} else if ((info->uid % 100000) == (ctx.st.st_uid % 100000)) {
|
||||
} else if ((info->uid % 100000) == (info->st.st_uid % 100000)) {
|
||||
info->policy = ALLOW;
|
||||
info->root_access = ROOT_ACCESS_APPS_AND_ADB;
|
||||
ctx.notify = 0;
|
||||
@ -243,6 +238,20 @@ void su_daemon_receiver(int client) {
|
||||
// Become session leader
|
||||
xsetsid();
|
||||
|
||||
// Migrate environment from client
|
||||
char path[32], buf[4096];
|
||||
snprintf(path, sizeof(path), "/proc/%d/cwd", ctx.pid);
|
||||
xreadlink(path, ctx.cwd, sizeof(ctx.cwd));
|
||||
snprintf(path, sizeof(path), "/proc/%d/environ", ctx.pid);
|
||||
memset(buf, 0, sizeof(buf));
|
||||
int fd = open(path, O_RDONLY);
|
||||
read(fd, buf, sizeof(buf));
|
||||
clearenv();
|
||||
for (size_t pos = 0; buf[pos];) {
|
||||
putenv(buf + pos);
|
||||
pos += strlen(buf + pos) + 1;
|
||||
}
|
||||
|
||||
// Let's read some info from the socket
|
||||
int argc = read_int(client);
|
||||
if (argc < 0 || argc > 512) {
|
||||
@ -263,10 +272,6 @@ void su_daemon_receiver(int client) {
|
||||
strcpy(argv[i], "-M");
|
||||
}
|
||||
|
||||
// Get cwd
|
||||
ctx.cwd = read_string(client);
|
||||
LOGD("su: cwd=[%s]\n", ctx.cwd);
|
||||
|
||||
// Get pts_slave
|
||||
char *pts_slave = read_string(client);
|
||||
LOGD("su: pts_slave=[%s]\n", pts_slave);
|
||||
@ -345,10 +350,6 @@ int su_client_main(int argc, char *argv[]) {
|
||||
write_string(socketfd, argv[i]);
|
||||
}
|
||||
|
||||
// CWD
|
||||
getcwd(buffer, sizeof(buffer));
|
||||
write_string(socketfd, buffer);
|
||||
|
||||
// Determine which one of our streams are attached to a TTY
|
||||
int atty = 0;
|
||||
if (isatty(STDIN_FILENO)) atty |= ATTY_IN;
|
||||
|
@ -43,7 +43,7 @@ int socket_create_temp(char *path, size_t len) {
|
||||
|
||||
// Set attributes so requester can access it
|
||||
setfilecon(path, "u:object_r:su_file:s0");
|
||||
chown(path, su_ctx->st.st_uid, su_ctx->st.st_gid);
|
||||
chown(path, su_ctx->info->st.st_uid, su_ctx->info->st.st_gid);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user