From d952cc2327839855002951d5ee7c6586698fe119 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 7 Nov 2019 17:41:59 -0500 Subject: [PATCH] Properly solve the connection problem --- app/src/main/AndroidManifest.xml | 9 +- .../magisk/ui/surequest/SuRequestActivity.kt | 23 +- build.gradle | 2 +- native/jni/su/connect.cpp | 219 ++++++++++++------ native/jni/su/su.h | 6 +- native/jni/utils/misc.cpp | 7 +- shared/src/main/AndroidManifest.xml | 4 +- stub/src/main/AndroidManifest.xml | 9 +- 8 files changed, 194 insertions(+), 85 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 86d1c906b..7a536d0f7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -43,10 +43,15 @@ + android:exported="false" + tools:ignore="AppLinkUrlError"> + + + + + () { @@ -28,13 +30,28 @@ open class SuRequestActivity : BaseActivitycfg[SU_MULTIUSER_MODE] == MULTIUSER_MODE_USER \ -? info->uid / 100000 \ -: 0) +? info->uid / 100000 : 0) #define get_uid(info) \ (info->cfg[SU_MULTIUSER_MODE] == MULTIUSER_MODE_OWNER_MANAGED \ -? info->uid % 100000 \ -: info->uid) +? info->uid % 100000 : info->uid) -static const char *get_command(const su_request *to) { - if (to->command[0]) - return to->command; - if (to->shell[0]) - return to->shell; - return DEFAULT_SHELL; +#define get_cmd(to) \ +(to.command[0] ? to.command : to.shell[0] ? to.shell : DEFAULT_SHELL) + +class Extra { + const char *key; + enum { + INT, + BOOL, + STRING + } type; + union { + int int_val; + bool bool_val; + const char * str_val; + }; + char i_buf[16]; + char b_buf[32]; +public: + Extra(const char *k, int v): key(k), type(INT), int_val(v) {} + Extra(const char *k, bool v): key(k), type(BOOL), bool_val(v) {} + Extra(const char *k, const char *v): key(k), type(STRING), str_val(v) {} + + void add_intent(vector &vec) { + const char *val; + switch (type) { + case INT: + vec.push_back("--ei"); + sprintf(i_buf, "%d", int_val); + val = i_buf; + break; + case BOOL: + vec.push_back("--ez"); + val = bool_val ? "true" : "false"; + break; + case STRING: + vec.push_back("--es"); + val = str_val; + break; + } + vec.push_back(key); + vec.push_back(val); + } + + void add_bind(vector &vec) { + switch (type) { + case INT: + sprintf(b_buf, "%s:i:%d", key, int_val); + break; + case BOOL: + sprintf(b_buf, "%s:b:%s", key, bool_val ? "true" : "false"); + break; + case STRING: + sprintf(b_buf, "%s:s:%s", key, str_val); + break; + } + vec.push_back("--extra"); + vec.push_back(b_buf); + } +}; + +static bool check_error(int fd) { + char buf[1024]; + unique_ptr out(xfdopen(fd, "r"), fclose); + while (fgets(buf, sizeof(buf), out.get())) { + if (strncmp(buf, "Error", 5) == 0) + return false; + } + return true; } -static void exec_content_cmd(const char **args, const su_info *info) { +static void exec_cmd(const char *action, vector &data, + const shared_ptr &info, int mode = CONTENT_PROVIDER) { char target[128]; - sprintf(target, "content://%s.provider", info->str[SU_MANAGER].data()); char user[4]; sprintf(user, "%d", get_user(info)); - // Fill in non static arguments - args[5] = target; - args[7] = user; + // First try content provider call method + if (mode >= CONTENT_PROVIDER) { + sprintf(target, "content://%s.provider", info->str[SU_MANAGER].data()); + vector args{ CALL_PROVIDER }; + for (auto &e : data) { + e.add_bind(args); + } + args.push_back(nullptr); + exec_t exec { + .err = true, + .fd = -1, + .pre_exec = [] { setenv("CLASSPATH", "/system/framework/content.jar", 1); }, + .argv = args.data() + }; + exec_command_sync(exec); + if (check_error(exec.fd)) + return; + } + vector args{ START_ACTIVITY }; + for (auto &e : data) { + e.add_intent(args); + } + args.push_back(nullptr); exec_t exec { - .pre_exec = [] { - int null = xopen("/dev/null", O_WRONLY | O_CLOEXEC); - dup2(null, STDOUT_FILENO); - dup2(null, STDERR_FILENO); - setenv("CLASSPATH", "/system/framework/content.jar", 1); - }, - .fork = fork_dont_care, - .argv = args + .err = true, + .fd = -1, + .pre_exec = [] { setenv("CLASSPATH", "/system/framework/am.jar", 1); }, + .argv = args.data() }; + + if (mode >= PKG_ACTIVITY) { + // Then try start activity without component name + strcpy(target, info->str[SU_MANAGER].data()); + exec_command_sync(exec); + if (check_error(exec.fd)) + return; + } + + // Finally, fallback to start activity with component name + args[4] = "-n"; + sprintf(target, "%s/a.m", info->str[SU_MANAGER].data()); + exec.fd = -2; + exec.fork = fork_dont_care; exec_command(exec); } -#define LOG_BODY \ -"log", \ -ex(fromUid), ex(toUid), ex(pid), ex(policy), \ -ex(command.data()), ex(notify) - void app_log(const su_context &ctx) { - char fromUid[32]; - sprintf(fromUid, "from.uid:i:%d", get_uid(ctx.info)); + if (fork_dont_care() == 0) { + vector extras; + extras.reserve(6); + extras.emplace_back("from.uid", get_uid(ctx.info)); + extras.emplace_back("to.uid", ctx.req.uid); + extras.emplace_back("pid", ctx.pid); + extras.emplace_back("policy", ctx.info->access.policy); + extras.emplace_back("command", get_cmd(ctx.req)); + extras.emplace_back("notify", (bool) ctx.info->access.notify); - char toUid[32]; - sprintf(toUid, "to.uid:i:%d", ctx.req.uid); - - char pid[16]; - sprintf(pid, "pid:i:%d", ctx.pid); - - char policy[16]; - sprintf(policy, "policy:i:%d", ctx.info->access.policy); - - string command("command:s:"); - command += get_command(&ctx.req); - - char notify[16]; - sprintf(notify, "notify:b:%s", ctx.info->access.notify ? "true" : "false"); - - content_exec(LOG_BODY) + exec_cmd("log", extras, ctx.info); + exit(0); + } } -#define NOTIFY_BODY \ -"notify", ex(fromUid), ex(policy) - void app_notify(const su_context &ctx) { - char fromUid[32]; - sprintf(fromUid, "from.uid:i:%d", get_uid(ctx.info)); + if (fork_dont_care() == 0) { + vector extras; + extras.reserve(2); + extras.emplace_back("from.uid", get_uid(ctx.info)); + extras.emplace_back("policy", ctx.info->access.policy); - char policy[16]; - sprintf(policy, "policy:i:%d", ctx.info->access.policy); - - content_exec(NOTIFY_BODY) + exec_cmd("notify", extras, ctx.info); + exit(0); + } } -#define SOCKET_BODY \ -"request", ex(sock) - void app_socket(const char *socket, const shared_ptr &info) { - char sock[128]; - sprintf(sock, "socket:s:%s", socket); - content_exec_info(info.get(), SOCKET_BODY) + vector extras; + extras.reserve(1); + extras.emplace_back("socket", socket); + + exec_cmd("request", extras, info, PKG_ACTIVITY); } void socket_send_request(int fd, const shared_ptr &info) { diff --git a/native/jni/su/su.h b/native/jni/su/su.h index 2c18fc5c8..02fc0aebc 100644 --- a/native/jni/su/su.h +++ b/native/jni/su/su.h @@ -17,7 +17,7 @@ class su_info { public: /* Unique key */ - const unsigned uid; + const int uid; /* These should be guarded with internal lock */ db_settings cfg; @@ -39,7 +39,7 @@ private: }; struct su_req_base { - unsigned uid = UID_ROOT; + int uid = UID_ROOT; bool login = false; bool keepenv = false; bool mount_master = false; @@ -63,7 +63,7 @@ private: struct su_context { std::shared_ptr info; su_request req; - pid_t pid; + int pid; }; void app_log(const su_context &ctx); diff --git a/native/jni/utils/misc.cpp b/native/jni/utils/misc.cpp index 4678fb41e..2db95f556 100644 --- a/native/jni/utils/misc.cpp +++ b/native/jni/utils/misc.cpp @@ -73,7 +73,8 @@ int strend(const char *s1, const char *s2) { } int exec_command(exec_t &exec) { - int pipefd[2] = {-1, -1}, outfd = -1; + int pipefd[] = {-1, -1}; + int outfd = -1; if (exec.fd == -1) { if (xpipe2(pipefd, O_CLOEXEC) == -1) @@ -113,10 +114,10 @@ int exec_command(exec_t &exec) { } int exec_command_sync(exec_t &exec) { - int pid, status; - pid = exec_command(exec); + int pid = exec_command(exec); if (pid < 0) return -1; + int status; waitpid(pid, &status, 0); return WEXITSTATUS(status); } diff --git a/shared/src/main/AndroidManifest.xml b/shared/src/main/AndroidManifest.xml index c42a2dd7f..bcec9546e 100644 --- a/shared/src/main/AndroidManifest.xml +++ b/shared/src/main/AndroidManifest.xml @@ -9,11 +9,11 @@ android:icon="@drawable/ic_launcher" android:installLocation="internalOnly" android:label="Magisk Manager" - android:supportsRtl="true"> + android:supportsRtl="true" + android:theme="@android:style/Theme.Translucent.NoTitleBar"> + android:exported="false" + tools:ignore="AppLinkUrlError"> + + + + +