diff --git a/binds.c b/binds.c deleted file mode 100644 index adb4581b7..000000000 --- a/binds.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - Copyright 2016, Pierre-Hugues Husson - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "binds.h" - -int bind_foreach(bind_cb cb, void* arg) { - int res = 0; - char *str = NULL; - int fd = open("/data/su/binds", O_RDONLY); - if(fd<0) - return 1; - - off_t size = lseek(fd, 0, SEEK_END); - lseek(fd, 0, SEEK_SET); - - str = malloc(size); - if(read(fd, str, size) != size) - goto error; - - char *base = str; - while(base < str+size) { - char *parse_src, *parse_dst; - int uid; - - char *ptr = memchr(base, 0, size-(base-str)); - if(ptr == NULL) - goto error; - sscanf(base, "%d", &uid); - - parse_src = strchr(base, ':'); - if(!parse_src) - goto error; - parse_src++; - - parse_dst = strchr(parse_src, ':'); - if(!parse_dst) - goto error; - *parse_dst = 0; // Split parse_src string - parse_dst++; - - cb(arg, uid, parse_src, parse_dst); - - base = ptr+1; - } - - res = 1; -error: - if(str) free(str); - close(fd); - return res; -} - -int bind_uniq_dst(const char *dst) { - static int _res; - static const char *_dst; - - _res = 1; - _dst = dst; - auto void cb(void *arg, int uid, const char *src, const char *dst) { - if(strcmp(dst, _dst) == 0) - _res = 0; - } - if(!bind_foreach(cb, NULL)) - return 0; - return _res; -} - -void bind_ls(int uid) { - static int _uid; - _uid=uid; - auto void cb(void *arg, int uid, const char *src, const char *dst) { - if(_uid == 0 || _uid == 2000 || _uid == uid) { - fprintf(stderr, "%d %s => %s\n", uid, src, dst); - } - } - bind_foreach(cb, NULL); -} - -int bind_remove(const char *path, int uid) { - static int _found = 0; - static const char *_path; - static int _fd; - static int _uid; - - - _path = path; - _found = 0; - _uid = uid; - - unlink("/data/su/bind.new"); - _fd = open("/data/su/bind.new", O_WRONLY|O_CREAT, 0600); - if(_fd<0) - return 0; - - auto void cb(void *arg, int uid, const char *src, const char *dst) { - //The one we want to drop - if(strcmp(dst, _path) == 0 && - (_uid == 0 || _uid == 2000 || _uid == uid)) { - _found = 1; - return; - } - char *str = NULL; - int len = asprintf(&str, "%d:%s:%s", uid, src, dst); - write(_fd, str, len+1); //len doesn't include final \0 and we want to write it - free(str); - } - bind_foreach(cb, NULL); - close(_fd); - unlink("/data/su/bind"); - rename("/data/su/bind.new", "/data/su/bind"); - return _found; -} - -int init_foreach(init_cb icb, void* arg) { - int res = 0; - char *str = NULL; - int fd = open("/data/su/init", O_RDONLY); - if(fd<0) - return 1; - - off_t size = lseek(fd, 0, SEEK_END); - lseek(fd, 0, SEEK_SET); - - str = malloc(size); - if(read(fd, str, size) != size) - goto error; - - char *base = str; - while(base < str+size) { - char *parsed; - int uid; - - char *ptr = memchr(base, 0, size-(base-str)); - if(ptr == NULL) - goto error; - sscanf(base, "%d", &uid); - - parsed = strchr(base, ':'); - if(!parsed) - goto error; - parsed++; - - - icb(arg, uid, parsed); - - base = ptr+1; - } - - res = 1; -error: - if(str) free(str); - close(fd); - return res; -} - -int init_uniq(const char *path) { - static int _res; - static const char *_path; - - _res = 1; - _path = path; - auto void cb(void *arg, int uid, const char *path) { - if(strcmp(path, _path) == 0) - _res = 0; - } - if(!init_foreach(cb, NULL)) - return 0; - return _res; -} - -int init_remove(const char *path, int uid) { - static int _found = 0; - static const char *_path; - static int fd; - static int _uid; - - _path = path; - _found = 0; - _uid = uid; - - unlink("/data/su/init.new"); - fd = open("/data/su/init.new", O_WRONLY|O_CREAT, 0600); - if(fd<0) - return 0; - - auto void cb(void *arg, int uid, const char *path) { - //The one we want to drop - if(strcmp(path, _path) == 0 && - (_uid == 0 || _uid == 2000 || uid == _uid)) { - _found = 1; - return; - } - char *str = NULL; - int len = asprintf(&str, "%d:%s", uid, path); - write(fd, str, len+1); //len doesn't include final \0 and we want to write it - free(str); - } - init_foreach(cb, NULL); - close(fd); - unlink("/data/su/init"); - rename("/data/su/init.new", "/data/su/init"); - return _found; -} - -void init_ls(int uid) { - static int _uid; - _uid = uid; - auto void cb(void *arg, int uid, const char *path) { - if(_uid == 2000 || _uid == 0 || _uid == uid) - fprintf(stderr, "%d %s\n", uid, path); - } - init_foreach(cb, NULL); -} diff --git a/binds.h b/binds.h deleted file mode 100644 index 46e883807..000000000 --- a/binds.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - Copyright 2016, Pierre-Hugues Husson - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef BINDSH -#define BINDS_H - -typedef void (*bind_cb)(void *arg, int uid, const char *src, const char *dst); -extern int bind_foreach(bind_cb cb, void* arg); -extern int bind_uniq_dst(const char *dst); -extern int bind_remove(const char *path, int uid); -extern void bind_ls(int uid); - -typedef void (*init_cb)(void *arg, int uid, const char *path); -extern int init_foreach(init_cb cb, void* arg); -extern int init_uniq(const char *dst); -extern int init_remove(const char *path, int uid); -extern void init_ls(int uid); - - -#endif /* BINDS_H */ diff --git a/daemon.c b/daemon.c index 3a6001760..5718d7300 100644 --- a/daemon.c +++ b/daemon.c @@ -47,7 +47,6 @@ #include #endif -#include "binds.h" #include "su.h" #include "utils.h" #include "pts.h" @@ -499,79 +498,68 @@ static void prepare_su_bind() { } } -static void prepare_binds() { - mkdir("/data/su", 0700); - static int i = 0; +static void bind_cb_func(void *arg, int uid, const char *src, const char *dst) { + int ret = 0, i = 0; - auto void cb(void *arg, int uid, const char *src, const char *dst) { - int ret = 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; + } - 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; + } - //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 = 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 = 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; - } - } - bind_foreach(cb, NULL); + ret = mount(tmpfile, dst, "", MS_BIND, NULL); + if(ret) { + LOGE("Failed to mount bind"); + return; + } } -static void do_init() { - auto void cb(void *arg, int uid, const char *path) { - int ret = 0; +static void init_cb_func(void *arg, int uid, const char *path) { + int ret = 0; - int p = fork(); - if(p) - return; + 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); + 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); - } - init_foreach(cb, NULL); + 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(); - prepare_binds(); - do_init(); setfscreatecon(NULL); } diff --git a/su.c b/su.c index 6284a4b48..ab8d95dbc 100644 --- a/su.c +++ b/su.c @@ -42,7 +42,6 @@ #include "su.h" #include "utils.h" -#include "binds.h" extern int is_daemon; extern int daemon_from_uid; @@ -470,70 +469,6 @@ static void usage(int status) { exit(status); } -static __attribute__ ((noreturn)) void allow_bind(struct su_context *ctx) { - if(ctx->from.uid == 0) - exit(1); - - if(ctx->bind.from[0] == '!') { - int ret = bind_remove(ctx->bind.to, ctx->from.uid); - if(!ret) { - fprintf(stderr, "The mentioned bind destination path didn't exist\n"); - exit(1); - } - exit(0); - } - if(strcmp("--ls", ctx->bind.from)==0) { - bind_ls(ctx->from.uid); - exit(0); - } - - if(!bind_uniq_dst(ctx->bind.to)) { - fprintf(stderr, "BIND: Distant file NOT unique. I refuse.\n"); - exit(1); - } - int fd = open("/data/su/binds", O_WRONLY|O_APPEND|O_CREAT, 0600); - if(fd<0) { - fprintf(stderr, "Failed to open binds file\n"); - exit(1); - } - char *str = NULL; - int len = asprintf(&str, "%d:%s:%s", ctx->from.uid, ctx->bind.from, ctx->bind.to); - write(fd, str, len+1); //len doesn't include final \0 and we want to write it - free(str); - close(fd); - exit(0); -} - -static __attribute__ ((noreturn)) void allow_init(struct su_context *ctx) { - if(ctx->init[0]=='!') { - int ret = init_remove(ctx->init+1, ctx->from.uid); - if(!ret) { - fprintf(stderr, "The mentioned init path didn't exist\n"); - exit(1); - } - exit(0); - } - if(strcmp("--ls", ctx->init) == 0) { - init_ls(ctx->from.uid); - exit(0); - } - if(!init_uniq(ctx->init)) - //This script is already in init list - exit(1); - - int fd = open("/data/su/init", O_WRONLY|O_APPEND|O_CREAT, 0600); - if(fd<0) { - fprintf(stderr, "Failed to open init file\n"); - exit(1); - } - char *str = NULL; - int len = asprintf(&str, "%d:%s", ctx->from.uid, ctx->init); - write(fd, str, len+1); //len doesn't include final \0 and we want to write it - free(str); - close(fd); - exit(0); -} - static __attribute__ ((noreturn)) void deny(struct su_context *ctx) { char *cmd = get_command(&ctx->to); @@ -575,11 +510,11 @@ static __attribute__ ((noreturn)) void allow(struct su_context *ctx) { if (send_to_app) send_result(ctx, ALLOW); - if(ctx->bind.from[0] && ctx->bind.to[0]) - allow_bind(ctx); + // if(ctx->bind.from[0] && ctx->bind.to[0]) + // allow_bind(ctx); - if(ctx->init[0]) - allow_init(ctx); + // if(ctx->init[0]) + // allow_init(ctx); char *binary; argc = ctx->to.optind; @@ -777,21 +712,14 @@ int su_main_nodaemon(int argc, char **argv) { .database_path = REQUESTOR_DATA_PATH REQUESTOR_DATABASE_PATH, .base_path = REQUESTOR_DATA_PATH REQUESTOR }, - .bind = { - .from = "", - .to = "", - }, - .init = "", }; struct stat st; int c, socket_serv_fd, fd; char buf[64], *result; policy_t dballow; struct option long_opts[] = { - { "bind", required_argument, NULL, 'b' }, { "command", required_argument, NULL, 'c' }, { "help", no_argument, NULL, 'h' }, - { "init", required_argument, NULL, 'i' }, { "login", no_argument, NULL, 'l' }, { "preserve-environment", no_argument, NULL, 'p' }, { "shell", required_argument, NULL, 's' }, @@ -800,71 +728,54 @@ int su_main_nodaemon(int argc, char **argv) { { NULL, 0, NULL, 0 }, }; - while ((c = getopt_long(argc, argv, "+b:c:hlmps:Vvuz:", long_opts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "c:hlmps:Vvuz:", long_opts, NULL)) != -1) { switch(c) { - case 'b': { - char *s = strdup(optarg); - - char *pos = strchr(s, ':'); - if(pos) { - pos[0] = 0; - ctx.bind.to = pos + 1; - ctx.bind.from = s; - } else { - ctx.bind.from = "--ls"; - ctx.bind.to = "--ls"; - } + case 'c': + ctx.to.shell = DEFAULT_SHELL; + ctx.to.command = optarg; + break; + case 'h': + usage(EXIT_SUCCESS); + break; + case 'l': + ctx.to.login = 1; + break; + case 'm': + case 'p': + ctx.to.keepenv = 1; + break; + case 's': + ctx.to.shell = optarg; + break; + case 'V': + printf("%d\n", VERSION_CODE); + exit(EXIT_SUCCESS); + case 'v': + printf("%s (topjohnwu v1)\n", VERSION); + exit(EXIT_SUCCESS); + case 'u': + switch (get_multiuser_mode()) { + case MULTIUSER_MODE_USER: + printf("%s\n", MULTIUSER_VALUE_USER); + break; + case MULTIUSER_MODE_OWNER_MANAGED: + printf("%s\n", MULTIUSER_VALUE_OWNER_MANAGED); + break; + case MULTIUSER_MODE_OWNER_ONLY: + printf("%s\n", MULTIUSER_VALUE_OWNER_ONLY); + break; + case MULTIUSER_MODE_NONE: + printf("%s\n", MULTIUSER_VALUE_NONE); + break; } + exit(EXIT_SUCCESS); + case 'z': + ctx.to.context = optarg; break; - case 'c': - ctx.to.shell = DEFAULT_SHELL; - ctx.to.command = optarg; - break; - case 'h': - usage(EXIT_SUCCESS); - break; - case 'i': - ctx.init = optarg; - break; - case 'l': - ctx.to.login = 1; - break; - case 'm': - case 'p': - ctx.to.keepenv = 1; - break; - case 's': - ctx.to.shell = optarg; - break; - case 'V': - printf("%d\n", VERSION_CODE); - exit(EXIT_SUCCESS); - case 'v': - printf("%s cm-su subind suinit\n", VERSION); - exit(EXIT_SUCCESS); - case 'u': - switch (get_multiuser_mode()) { - case MULTIUSER_MODE_USER: - printf("%s\n", MULTIUSER_VALUE_USER); - break; - case MULTIUSER_MODE_OWNER_MANAGED: - printf("%s\n", MULTIUSER_VALUE_OWNER_MANAGED); - break; - case MULTIUSER_MODE_OWNER_ONLY: - printf("%s\n", MULTIUSER_VALUE_OWNER_ONLY); - break; - case MULTIUSER_MODE_NONE: - printf("%s\n", MULTIUSER_VALUE_NONE); - break; - } - exit(EXIT_SUCCESS); - case 'z': - ctx.to.context = optarg; - break; - default: - /* Bionic getopt_long doesn't terminate its error output by newline */ - fprintf(stderr, "\n"); - usage(2); + default: + /* Bionic getopt_long doesn't terminate its error output by newline */ + fprintf(stderr, "\n"); + usage(2); } } hacks_init(); diff --git a/su.h b/su.h index a690a8cb6..5aaa28f6f 100644 --- a/su.h +++ b/su.h @@ -77,7 +77,7 @@ #define str(a) #a #ifndef VERSION_CODE -#define VERSION_CODE 17 +#define VERSION_CODE 1 #endif #define VERSION xstr(VERSION_CODE) " " REQUESTOR