8d4c407201
Since Android Q does not allow launching activities from the background (Services/BroadcastReceivers) and our native process is root, directly launch activities and use it for communication between native and app. The target activity is not exported, so non-root apps cannot send an intent to fool Magisk Manager. This is as safe as the previous implementation, which uses protected system broadcasts. This also workaround broadcast limitations in many ROMs (especially in Chinese ROMs) which blocks the su request dialog if the app is frozen/force stopped by the system. Close #1326
120 lines
2.7 KiB
C++
120 lines
2.7 KiB
C++
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
|
|
#include <magisk.h>
|
|
#include <daemon.h>
|
|
#include <utils.h>
|
|
|
|
#include "su.h"
|
|
|
|
#define START_ACTIVITY \
|
|
"/system/bin/app_process", "/system/bin", "com.android.commands.am.Am", \
|
|
"start", "-n", nullptr, "--user", nullptr, "-f", "0x18000020", "-a"
|
|
|
|
// 0x18000020 = FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_MULTIPLE_TASK|FLAG_INCLUDE_STOPPED_PACKAGES
|
|
|
|
static inline const char *get_command(const struct su_request *to) {
|
|
if (to->command[0])
|
|
return to->command;
|
|
if (to->shell[0])
|
|
return to->shell;
|
|
return DEFAULT_SHELL;
|
|
}
|
|
|
|
static inline void get_user(char *user, struct su_info *info) {
|
|
sprintf(user, "%d",
|
|
info->cfg[SU_MULTIUSER_MODE] == MULTIUSER_MODE_USER
|
|
? info->uid / 100000
|
|
: 0);
|
|
}
|
|
|
|
static inline void get_uid(char *uid, struct su_info *info) {
|
|
sprintf(uid, "%d",
|
|
info->cfg[SU_MULTIUSER_MODE] == MULTIUSER_MODE_OWNER_MANAGED
|
|
? info->uid % 100000
|
|
: info->uid);
|
|
}
|
|
|
|
static void silent_run(const char **args, struct su_info *info) {
|
|
char component[128];
|
|
sprintf(component, "%s/a.m", info->str[SU_MANAGER].data());
|
|
char user[8];
|
|
get_user(user, info);
|
|
|
|
/* Fill in dynamic arguments */
|
|
args[5] = component;
|
|
args[7] = user;
|
|
|
|
exec_t exec {
|
|
.pre_exec = []() -> void {
|
|
int null = xopen("/dev/null", O_WRONLY | O_CLOEXEC);
|
|
dup2(null, STDOUT_FILENO);
|
|
dup2(null, STDERR_FILENO);
|
|
setenv("CLASSPATH", "/system/framework/am.jar", 1);
|
|
},
|
|
.fork = fork_dont_care,
|
|
.argv = args
|
|
};
|
|
exec_command(exec);
|
|
}
|
|
|
|
void app_log(struct su_context *ctx) {
|
|
char fromUid[8];
|
|
get_uid(fromUid, ctx->info);
|
|
|
|
char toUid[8];
|
|
sprintf(toUid, "%d", ctx->req.uid);
|
|
|
|
char pid[8];
|
|
sprintf(pid, "%d", ctx->pid);
|
|
|
|
char policy[2];
|
|
sprintf(policy, "%d", ctx->info->access.policy);
|
|
|
|
const char *cmd[] = {
|
|
START_ACTIVITY, "log",
|
|
"--ei", "from.uid", fromUid,
|
|
"--ei", "to.uid", toUid,
|
|
"--ei", "pid", pid,
|
|
"--ei", "policy", policy,
|
|
"--es", "command", get_command(&ctx->req),
|
|
"--ez", "notify", ctx->info->access.notify ? "true" : "false",
|
|
nullptr
|
|
};
|
|
silent_run(cmd, ctx->info);
|
|
}
|
|
|
|
void app_notify(struct su_context *ctx) {
|
|
char fromUid[8];
|
|
get_uid(fromUid, ctx->info);
|
|
|
|
char policy[2];
|
|
sprintf(policy, "%d", ctx->info->access.policy);
|
|
|
|
const char *cmd[] = {
|
|
START_ACTIVITY, "notify",
|
|
"--ei", "from.uid", fromUid,
|
|
"--ei", "policy", policy,
|
|
nullptr
|
|
};
|
|
silent_run(cmd, ctx->info);
|
|
}
|
|
|
|
void app_connect(const char *socket, struct su_info *info) {
|
|
const char *cmd[] = {
|
|
START_ACTIVITY, "request",
|
|
"--es", "socket", socket,
|
|
nullptr
|
|
};
|
|
silent_run(cmd, info);
|
|
}
|
|
|
|
void socket_send_request(int fd, struct su_info *info) {
|
|
write_key_token(fd, "uid", info->uid);
|
|
write_string_be(fd, "eof");
|
|
}
|