Fix app request issue

This commit is contained in:
topjohnwu 2016-12-31 01:05:20 +08:00
parent f31d2486c9
commit 04fcb33d7e
3 changed files with 42 additions and 158 deletions

121
daemon.c
View File

@ -444,133 +444,12 @@ static int daemon_accept(int fd) {
return run_daemon_child(infd, outfd, errfd, argc, argv); return run_daemon_child(infd, outfd, errfd, argc, argv);
} }
static int copy_file(const char* src, const char* dst, int mode) {
int ifd = open(src, O_RDONLY);
if(ifd<0)
return 1;
if(mode == 0) {
struct stat stbuf;
if(fstat(ifd, &stbuf))
return 1;
mode = stbuf.st_mode & 0777;
LOGE("File %s found mode %o", src, mode);
}
int ofd = open(dst, O_WRONLY|O_CREAT, mode);
if(ofd<0)
return 1;
size_t s = lseek(ifd, 0, SEEK_END);
if(s<0)
return 1;
lseek(ifd, 0, SEEK_SET);
int ret = sendfile(ofd, ifd, NULL, s);
if(ret<0)
return 1;
close(ofd);
close(ifd);
return 0;
}
static void prepare_su_bind() {
int ret = 0;
//Check if there is a use to mount bind
if(access("/system/xbin/su", R_OK) != 0)
return;
ret = copy_file("/sbin/su", "/dev/su/su", 0755);
if(ret) {
PLOGE("Failed to copy su");
return;
}
chmod("/dev/su/su", 0755);
ret = setfilecon("/dev/su/su", "u:object_r:system_file:s0");
if(ret) {
LOGE("Failed to set file context");
return;
}
ret = mount("/dev/su/su", "/system/xbin/su", "", MS_BIND, NULL);
if(ret) {
LOGE("Failed to mount bind");
return;
}
}
static void bind_cb_func(void *arg, int uid, const char *src, const char *dst) {
int ret = 0, i = 0;
char *tmpfile = NULL;
asprintf(&tmpfile, "/dev/su/bind%d", i++);
struct stat stbuf;
ret = stat(src, &stbuf);
if(ret) {
free(tmpfile);
LOGE("Failed to stat src %s file", src);
return;
}
//Only shell uid is allowed to bind files not his own
if(uid != 2000 && uid != stbuf.st_uid) {
LOGE("File %s has wrong owner: %d vs %d", src, uid, stbuf.st_uid);
return;
}
ret = copy_file(src, tmpfile, 0);
if(ret) {
free(tmpfile);
PLOGE("Failed to copy su");
return;
}
chmod(tmpfile, stbuf.st_mode);
ret = setfilecon(tmpfile, "u:object_r:system_file:s0");
if(ret) {
LOGE("Failed to set file context");
return;
}
ret = mount(tmpfile, dst, "", MS_BIND, NULL);
if(ret) {
LOGE("Failed to mount bind");
return;
}
}
static void init_cb_func(void *arg, int uid, const char *path) {
int ret = 0;
int p = fork();
if(p)
return;
while(access("/system/bin/sh", R_OK)) sleep(1);
ret = setexeccon("u:r:su:s0");
execl(path, path, NULL);
LOGE("Failed to execute %s. Trying as shell script, ret = %d", path, ret);
ret = setexeccon("u:r:su:s0");
execl("/system/bin/sh", "/system/bin/sh", path, NULL);
LOGE("Failed to execute %s as shell script", path);
_exit(1);
}
static void prepare() {
setfscreatecon("u:object_r:su_daemon:s0");
mkdir("/dev/su", 0700);
prepare_su_bind();
setfscreatecon(NULL);
}
int run_daemon() { int run_daemon() {
if (getuid() != 0 || getgid() != 0) { if (getuid() != 0 || getgid() != 0) {
PLOGE("daemon requires root. uid/gid not root"); PLOGE("daemon requires root. uid/gid not root");
return -1; return -1;
} }
prepare();
switch (fork()) { switch (fork()) {
case 0: case 0:
break; break;

37
su.c
View File

@ -562,10 +562,10 @@ static __attribute__ ((noreturn)) void allow(struct su_context *ctx) {
arg0, PARG(0), PARG(1), PARG(2), PARG(3), PARG(4), PARG(5), arg0, PARG(0), PARG(1), PARG(2), PARG(3), PARG(4), PARG(5),
(ctx->to.optind + 6 < ctx->to.argc) ? " ..." : ""); (ctx->to.optind + 6 < ctx->to.argc) ? " ..." : "");
if(ctx->to.context && strcmp(ctx->to.context, "u:r:su_light:s0") == 0) { if(ctx->to.context && strcmp(ctx->to.context, "u:r:su_light:s0") == 0) {
setexeccon(ctx->to.context); setexeccon(ctx->to.context);
} else { } else {
setexeccon("u:r:su:s0"); setexeccon("u:r:su:s0");
} }
ctx->to.argv[--argc] = arg0; ctx->to.argv[--argc] = arg0;
@ -610,7 +610,7 @@ static void fork_for_samsung(void)
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
if (argc == 2 && strcmp(argv[1], "--daemon") == 0) { if (argc == 2 && strcmp(argv[1], "--daemon") == 0) {
//Everything we'll exec will be in su, not su_daemon //Everything we'll exec will be in su, not su_daemon
setexeccon("u:r:su:s0"); setexeccon("u:r:su:s0");
return run_daemon(); return run_daemon();
} }
return su_main(argc, argv); return su_main(argc, argv);
@ -618,15 +618,15 @@ int main(int argc, char *argv[]) {
int su_main(int argc, char *argv[]) { int su_main(int argc, char *argv[]) {
int ppid = getppid(); int ppid = getppid();
if ((geteuid() != AID_ROOT && getuid() != AID_ROOT) || if ((geteuid() != AID_ROOT && getuid() != AID_ROOT) ||
(get_api_version() >= 18 && getuid() == AID_SHELL) || (get_api_version() >= 18 && getuid() == AID_SHELL) ||
get_api_version() >= 19) { get_api_version() >= 19) {
// attempt to connect to daemon... // attempt to connect to daemon...
LOGD("starting daemon client %d %d", getuid(), geteuid()); LOGD("starting daemon client %d %d", getuid(), geteuid());
return connect_daemon(argc, argv, ppid); return connect_daemon(argc, argv, ppid);
} else { } else {
return su_main_nodaemon(argc, argv); return su_main_nodaemon(argc, argv);
} }
} }
@ -700,7 +700,7 @@ int su_main_nodaemon(int argc, char **argv) {
.keepenv = 0, .keepenv = 0,
.shell = NULL, .shell = NULL,
.command = NULL, .command = NULL,
.context = NULL, .context = NULL,
.argv = argv, .argv = argv,
.argc = argc, .argc = argc,
.optind = 0, .optind = 0,
@ -712,6 +712,11 @@ int su_main_nodaemon(int argc, char **argv) {
.database_path = REQUESTOR_DATA_PATH REQUESTOR_DATABASE_PATH, .database_path = REQUESTOR_DATA_PATH REQUESTOR_DATABASE_PATH,
.base_path = REQUESTOR_DATA_PATH REQUESTOR .base_path = REQUESTOR_DATA_PATH REQUESTOR
}, },
.bind = {
.from = "",
.to = "",
},
.init = "",
}; };
struct stat st; struct stat st;
int c, socket_serv_fd, fd; int c, socket_serv_fd, fd;
@ -751,7 +756,7 @@ int su_main_nodaemon(int argc, char **argv) {
printf("%d\n", VERSION_CODE); printf("%d\n", VERSION_CODE);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
case 'v': case 'v':
printf("%s (topjohnwu v1)\n", VERSION); printf("%s\n", VERSION);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
case 'u': case 'u':
switch (get_multiuser_mode()) { switch (get_multiuser_mode()) {

42
su.h
View File

@ -79,7 +79,7 @@
#ifndef VERSION_CODE #ifndef VERSION_CODE
#define VERSION_CODE 1 #define VERSION_CODE 1
#endif #endif
#define VERSION xstr(VERSION_CODE) " " REQUESTOR #define VERSION REQUESTOR " topjohnwu r" xstr(VERSION_CODE)
#define PROTO_VERSION 1 #define PROTO_VERSION 1
@ -98,7 +98,7 @@ struct su_request {
int login; int login;
int keepenv; int keepenv;
char *shell; char *shell;
char *context; char *context;
char *command; char *command;
char **argv; char **argv;
int argc; int argc;
@ -123,29 +123,29 @@ struct su_user_info {
}; };
struct su_bind { struct su_bind {
const char *from; const char *from;
const char *to; const char *to;
}; };
struct su_context { struct su_context {
struct su_initiator from; struct su_initiator from;
struct su_request to; struct su_request to;
struct su_user_info user; struct su_user_info user;
struct su_bind bind; struct su_bind bind;
const char *init; const char *init;
mode_t umask; mode_t umask;
char sock_path[PATH_MAX]; char sock_path[PATH_MAX];
}; };
// multiuser su behavior // multiuser su behavior
typedef enum { typedef enum {
// only owner can su // only owner can su
MULTIUSER_MODE_OWNER_ONLY = 0, MULTIUSER_MODE_OWNER_ONLY = 0,
// owner gets a su prompt // owner gets a su prompt
MULTIUSER_MODE_OWNER_MANAGED = 1, MULTIUSER_MODE_OWNER_MANAGED = 1,
// user gets a su prompt // user gets a su prompt
MULTIUSER_MODE_USER = 2, MULTIUSER_MODE_USER = 2,
MULTIUSER_MODE_NONE = 3, MULTIUSER_MODE_NONE = 3,
} multiuser_mode_t; } multiuser_mode_t;
#define MULTIUSER_VALUE_OWNER_ONLY "owner" #define MULTIUSER_VALUE_OWNER_ONLY "owner"
@ -166,14 +166,14 @@ extern int send_result(struct su_context *ctx, policy_t policy);
static inline char *get_command(const struct su_request *to) static inline char *get_command(const struct su_request *to)
{ {
if (to->command) if (to->command)
return to->command; return to->command;
if (to->shell) if (to->shell)
return to->shell; return to->shell;
char* ret = to->argv[to->optind]; char* ret = to->argv[to->optind];
if (ret) if (ret)
return ret; return ret;
return DEFAULT_SHELL; return DEFAULT_SHELL;
} }
void exec_loge(const char* fmt, ...); void exec_loge(const char* fmt, ...);