mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-24 20:37:39 +00:00
Introduce component agnostic communication
Usually, the communication between native and the app is done via sending intents to either broadcast or activity. These communication channels are for launching root requests dialogs, sending root request notifications (the toast you see when an app gained root access), and root request logging. Sending intents by am (activity manager) usually requires specifying the component name in the format of <pkg>/<class name>. This means parts of Magisk Manager cannot be randomized or else the native daemon is unable to know where to send data to the app. On modern Android (not sure which API is it introduced), it is possible to send broadcasts to a package, not a specific component. Which component will receive the intent depends on the intent filter declared in AndroidManifest.xml. Since we already have a mechanism in native code to keep track of the package name of Magisk Manager, this makes it perfect to pass intents to Magisk Manager that have components being randomly obfuscated (stub APKs). There are a few caveats though. Although this broadcasting method works perfectly fine on AOSP and most systems, there are OEMs out there shipping ROMs blocking broadcasts unexpectedly. In order to make sure Magisk works in all kinds of scenarios, we run actual tests every boot to determine which communication method should be used. We have 3 methods in total, ordered in preference: 1. Broadcasting to a package 2. Broadcasting to a specific component 3. Starting a specific activity component Method 3 will always work on any device, but the downside is anytime a communication happens, Magisk Manager will steal foreground focus regardless of whether UI is drawn. Method 1 is the only way to support obfuscated stub APKs. The communication test will test method 1 and 2, and if Magisk Manager is able to receive the messages, it will then update the daemon configuration to use whichever is preferable. If none of the broadcasts can be delivered, then the fallback method 3 will be used.
This commit is contained in:
parent
953c40b083
commit
0f74e89b44
@ -76,6 +76,7 @@
|
||||
android:name="a.h"
|
||||
android:directBootAware="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.REBOOT" />
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="android.intent.action.LOCALE_CHANGED" />
|
||||
</intent-filter>
|
||||
|
@ -20,13 +20,15 @@ import androidx.annotation.ColorRes
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.net.toUri
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.utils.DynamicClassLoader
|
||||
import com.topjohnwu.magisk.utils.FileProvider
|
||||
import com.topjohnwu.magisk.utils.Utils
|
||||
import com.topjohnwu.magisk.utils.currentLocale
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.util.*
|
||||
import java.lang.reflect.Array as JArray
|
||||
|
||||
val packageName: String get() = get<Context>().packageName
|
||||
|
||||
@ -97,33 +99,38 @@ fun Context.readUri(uri: Uri) =
|
||||
|
||||
fun Intent.startActivity(context: Context) = context.startActivity(this)
|
||||
|
||||
fun Intent.toCommand(args: MutableList<String>) {
|
||||
if (action != null) {
|
||||
fun Intent.startActivityWithRoot() {
|
||||
val args = mutableListOf("am", "start", "--user", Const.USER_ID.toString())
|
||||
val cmd = toCommand(args).joinToString(" ")
|
||||
Shell.su(cmd).submit()
|
||||
}
|
||||
|
||||
fun Intent.toCommand(args: MutableList<String> = mutableListOf()): MutableList<String> {
|
||||
action?.also {
|
||||
args.add("-a")
|
||||
args.add(action!!)
|
||||
args.add(it)
|
||||
}
|
||||
if (component != null) {
|
||||
component?.also {
|
||||
args.add("-n")
|
||||
args.add(component!!.flattenToString())
|
||||
args.add(it.flattenToString())
|
||||
}
|
||||
if (data != null) {
|
||||
data?.also {
|
||||
args.add("-d")
|
||||
args.add(dataString!!)
|
||||
args.add(it.toString())
|
||||
}
|
||||
if (categories != null) {
|
||||
for (cat in categories) {
|
||||
categories?.also {
|
||||
for (cat in it) {
|
||||
args.add("-c")
|
||||
args.add(cat)
|
||||
}
|
||||
}
|
||||
if (type != null) {
|
||||
type?.also {
|
||||
args.add("-t")
|
||||
args.add(type!!)
|
||||
args.add(it)
|
||||
}
|
||||
val extras = extras
|
||||
if (extras != null) {
|
||||
loop@ for (key in extras.keySet()) {
|
||||
val v = extras.get(key) ?: continue
|
||||
extras?.also {
|
||||
loop@ for (key in it.keySet()) {
|
||||
val v = it[key] ?: continue
|
||||
var value: Any = v
|
||||
val arg: String
|
||||
when {
|
||||
@ -137,9 +144,8 @@ fun Intent.toCommand(args: MutableList<String>) {
|
||||
arg = "--ecn"
|
||||
value = v.flattenToString()
|
||||
}
|
||||
v is ArrayList<*> -> {
|
||||
if (v.size <= 0)
|
||||
/* Impossible to know the type due to type erasure */
|
||||
v is List<*> -> {
|
||||
if (v.isEmpty())
|
||||
continue@loop
|
||||
|
||||
arg = if (v[0] is Int)
|
||||
@ -175,9 +181,9 @@ fun Intent.toCommand(args: MutableList<String>) {
|
||||
continue@loop /* Unsupported */
|
||||
|
||||
val sb = StringBuilder()
|
||||
val len = java.lang.reflect.Array.getLength(v)
|
||||
val len = JArray.getLength(v)
|
||||
for (i in 0 until len) {
|
||||
sb.append(java.lang.reflect.Array.get(v, i)!!.toString().replace(",", "\\,"))
|
||||
sb.append(JArray.get(v, i)!!.toString().replace(",", "\\,"))
|
||||
sb.append(',')
|
||||
}
|
||||
// Remove trailing comma
|
||||
@ -194,6 +200,7 @@ fun Intent.toCommand(args: MutableList<String>) {
|
||||
}
|
||||
args.add("-f")
|
||||
args.add(flags.toString())
|
||||
return args
|
||||
}
|
||||
|
||||
fun File.provide(context: Context = get()): Uri {
|
||||
|
@ -2,14 +2,14 @@ package com.topjohnwu.magisk.model.receiver
|
||||
|
||||
import android.content.ContextWrapper
|
||||
import android.content.Intent
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.Const
|
||||
import com.topjohnwu.magisk.Info
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import com.topjohnwu.magisk.*
|
||||
import com.topjohnwu.magisk.base.BaseReceiver
|
||||
import com.topjohnwu.magisk.data.database.PolicyDao
|
||||
import com.topjohnwu.magisk.data.database.base.su
|
||||
import com.topjohnwu.magisk.extensions.reboot
|
||||
import com.topjohnwu.magisk.intent
|
||||
import com.topjohnwu.magisk.extensions.startActivity
|
||||
import com.topjohnwu.magisk.extensions.startActivityWithRoot
|
||||
import com.topjohnwu.magisk.model.download.DownloadService
|
||||
import com.topjohnwu.magisk.model.entity.ManagerJson
|
||||
import com.topjohnwu.magisk.model.entity.internal.Configuration
|
||||
@ -20,6 +20,7 @@ import com.topjohnwu.magisk.view.Notifications
|
||||
import com.topjohnwu.magisk.view.Shortcuts
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import org.koin.core.inject
|
||||
import timber.log.Timber
|
||||
|
||||
open class GeneralReceiver : BaseReceiver() {
|
||||
|
||||
@ -38,6 +39,17 @@ open class GeneralReceiver : BaseReceiver() {
|
||||
|
||||
override fun onReceive(context: ContextWrapper, intent: Intent?) {
|
||||
intent ?: return
|
||||
|
||||
// Debug messages
|
||||
if (BuildConfig.DEBUG) {
|
||||
Timber.d(intent.action)
|
||||
intent.extras?.let { bundle ->
|
||||
bundle.keySet().forEach {
|
||||
Timber.d("[%s]=[%s]", it, bundle[it])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (intent.action ?: return) {
|
||||
Intent.ACTION_REBOOT, Intent.ACTION_BOOT_COMPLETED -> {
|
||||
val action = intent.getStringExtra("action")
|
||||
@ -56,11 +68,19 @@ open class GeneralReceiver : BaseReceiver() {
|
||||
.putExtra("socket", intent.getStringExtra("socket"))
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
|
||||
context.startActivity(i)
|
||||
if (SDK_INT >= 29) {
|
||||
// Android Q does not allow starting activity from background
|
||||
i.startActivityWithRoot()
|
||||
} else {
|
||||
i.startActivity(context)
|
||||
}
|
||||
}
|
||||
LOG -> SuLogger.handleLogs(context, intent)
|
||||
NOTIFY -> SuLogger.handleNotify(context, intent)
|
||||
TEST -> {
|
||||
val mode = intent.getIntExtra("mode", 1 shl 1)
|
||||
Shell.su("magisk --connect-mode $mode").submit()
|
||||
}
|
||||
LOG -> SuLogger.handleLogs(intent)
|
||||
NOTIFY -> SuLogger.handleNotify(intent)
|
||||
TEST -> Shell.su("magisk --use-broadcast").submit()
|
||||
}
|
||||
}
|
||||
Intent.ACTION_PACKAGE_REPLACED ->
|
||||
|
@ -3,7 +3,6 @@ package com.topjohnwu.magisk.ui.surequest
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.view.Window
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.base.BaseActivity
|
||||
@ -31,18 +30,16 @@ open class SuRequestActivity : BaseActivity<SuRequestViewModel, ActivityRequestB
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val intent = intent
|
||||
val action = intent.action
|
||||
|
||||
if (TextUtils.equals(action, GeneralReceiver.REQUEST)) {
|
||||
when (intent?.action) {
|
||||
GeneralReceiver.REQUEST -> {
|
||||
if (!viewModel.handleRequest(intent))
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
if (TextUtils.equals(action, GeneralReceiver.LOG))
|
||||
SuLogger.handleLogs(intent)
|
||||
else if (TextUtils.equals(action, GeneralReceiver.NOTIFY))
|
||||
SuLogger.handleNotify(intent)
|
||||
GeneralReceiver.LOG -> SuLogger.handleLogs(this, intent)
|
||||
GeneralReceiver.NOTIFY -> SuLogger.handleNotify(this, intent)
|
||||
}
|
||||
|
||||
finish()
|
||||
}
|
||||
|
@ -2,14 +2,13 @@ package com.topjohnwu.magisk.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Process
|
||||
import android.widget.Toast
|
||||
import com.topjohnwu.magisk.Config
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.data.database.PolicyDao
|
||||
import com.topjohnwu.magisk.data.repository.LogRepository
|
||||
import com.topjohnwu.magisk.extensions.inject
|
||||
import com.topjohnwu.magisk.extensions.get
|
||||
import com.topjohnwu.magisk.model.entity.MagiskPolicy
|
||||
import com.topjohnwu.magisk.model.entity.toLog
|
||||
import com.topjohnwu.magisk.model.entity.toPolicy
|
||||
@ -17,15 +16,13 @@ import java.util.*
|
||||
|
||||
object SuLogger {
|
||||
|
||||
private val context: Context by inject()
|
||||
|
||||
fun handleLogs(intent: Intent) {
|
||||
fun handleLogs(context: Context, intent: Intent) {
|
||||
|
||||
val fromUid = intent.getIntExtra("from.uid", -1)
|
||||
if (fromUid < 0) return
|
||||
if (fromUid == Process.myUid()) return
|
||||
|
||||
val pm: PackageManager by inject()
|
||||
val pm = context.packageManager
|
||||
|
||||
val notify: Boolean
|
||||
val data = intent.extras
|
||||
@ -36,7 +33,7 @@ object SuLogger {
|
||||
}.getOrElse { return }
|
||||
} else {
|
||||
// Doesn't report whether notify or not, check database ourselves
|
||||
val policyDB: PolicyDao by inject()
|
||||
val policyDB = get<PolicyDao>()
|
||||
val policy = policyDB.fetch(fromUid).blockingGet() ?: return
|
||||
notify = policy.notification
|
||||
policy
|
||||
@ -46,7 +43,7 @@ object SuLogger {
|
||||
return
|
||||
|
||||
if (notify)
|
||||
handleNotify(policy)
|
||||
handleNotify(context, policy)
|
||||
|
||||
val toUid = intent.getIntExtra("to.uid", -1)
|
||||
if (toUid < 0) return
|
||||
@ -62,11 +59,11 @@ object SuLogger {
|
||||
date = Date()
|
||||
)
|
||||
|
||||
val logRepo: LogRepository by inject()
|
||||
val logRepo = get<LogRepository>()
|
||||
logRepo.put(log).blockingGet()?.printStackTrace()
|
||||
}
|
||||
|
||||
private fun handleNotify(policy: MagiskPolicy) {
|
||||
private fun handleNotify(context: Context, policy: MagiskPolicy) {
|
||||
if (policy.notification && Config.suNotification == Config.Value.NOTIFICATION_TOAST) {
|
||||
Utils.toast(
|
||||
context.getString(
|
||||
@ -80,16 +77,16 @@ object SuLogger {
|
||||
}
|
||||
}
|
||||
|
||||
fun handleNotify(intent: Intent) {
|
||||
fun handleNotify(context: Context, intent: Intent) {
|
||||
val fromUid = intent.getIntExtra("from.uid", -1)
|
||||
if (fromUid < 0) return
|
||||
if (fromUid == Process.myUid()) return
|
||||
runCatching {
|
||||
val packageManager: PackageManager by inject()
|
||||
val policy = fromUid.toPolicy(packageManager)
|
||||
val pm = context.packageManager
|
||||
val policy = fromUid.toPolicy(pm)
|
||||
.copy(policy = intent.getIntExtra("policy", -1))
|
||||
if (policy.policy >= 0)
|
||||
handleNotify(policy)
|
||||
handleNotify(context, policy)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ static void *request_handler(void *args) {
|
||||
case BOOT_COMPLETE:
|
||||
case SQLITE_CMD:
|
||||
case BROADCAST_ACK:
|
||||
case BROADCAST_TEST:
|
||||
if (credential.uid != 0) {
|
||||
write_int(client, ROOT_REQUIRED);
|
||||
close(client);
|
||||
@ -91,9 +92,10 @@ static void *request_handler(void *args) {
|
||||
exec_sql(client);
|
||||
break;
|
||||
case BROADCAST_ACK:
|
||||
LOGD("* Use broadcasts for su logging and notify\n");
|
||||
CONNECT_BROADCAST = true;
|
||||
close(client);
|
||||
broadcast_ack(client);
|
||||
break;
|
||||
case BROADCAST_TEST:
|
||||
broadcast_test(client);
|
||||
break;
|
||||
case REMOVE_MODULES:
|
||||
if (credential.uid == UID_SHELL || credential.uid == UID_ROOT) {
|
||||
|
@ -219,7 +219,6 @@ int get_db_strings(db_strings &str, int key) {
|
||||
char *err;
|
||||
auto string_cb = [&](db_row &row) -> bool {
|
||||
str[row["key"]] = row["value"];
|
||||
LOGD("magiskdb: query %s=[%s]\n", row["key"].data(), row["value"].data());
|
||||
return true;
|
||||
};
|
||||
if (key >= 0) {
|
||||
@ -273,6 +272,7 @@ int validate_manager(string &alt_pkg, int userid, struct stat *st) {
|
||||
}
|
||||
|
||||
void exec_sql(int client) {
|
||||
run_finally f([=]{ close(client); });
|
||||
char *sql = read_string(client);
|
||||
char *err = db_exec(sql, [&](db_row &row) -> bool {
|
||||
string out;
|
||||
@ -289,9 +289,6 @@ void exec_sql(int client) {
|
||||
return true;
|
||||
});
|
||||
free(sql);
|
||||
db_err_cmd(err,
|
||||
write_int(client, 0);
|
||||
return;
|
||||
);
|
||||
close(client);
|
||||
db_err_cmd(err, return; );
|
||||
}
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include <magisk.h>
|
||||
#include <daemon.h>
|
||||
#include <selinux.h>
|
||||
#include <db.h>
|
||||
#include <flags.h>
|
||||
|
||||
using namespace std::literals;
|
||||
@ -36,7 +35,8 @@ Advanced Options (Internal APIs):
|
||||
--clone-attr SRC DEST clone permission, owner, and selinux context
|
||||
--clone SRC DEST clone SRC to DEST
|
||||
--sqlite SQL exec SQL commands to Magisk database
|
||||
--use-broadcast use broadcast for su logging and notify
|
||||
--connect-mode [MODE] get/set connect mode for su request and notify
|
||||
--broadcast-test manually trigger broadcast tests
|
||||
|
||||
Supported init triggers:
|
||||
post-fs-data, service, boot-complete
|
||||
@ -79,12 +79,10 @@ int magisk_main(int argc, char *argv[]) {
|
||||
restore_rootcon();
|
||||
restorecon();
|
||||
return 0;
|
||||
} else if (argv[1] == "--clone-attr"sv) {
|
||||
if (argc < 4) usage();
|
||||
} else if (argc >= 4 && argv[1] == "--clone-attr"sv) {;
|
||||
clone_attr(argv[2], argv[3]);
|
||||
return 0;
|
||||
} else if (argv[1] == "--clone"sv) {
|
||||
if (argc < 4) usage();
|
||||
} else if (argc >= 4 && argv[1] == "--clone"sv) {
|
||||
cp_afc(argv[2], argv[3]);
|
||||
return 0;
|
||||
} else if (argv[1] == "--daemon"sv) {
|
||||
@ -103,7 +101,7 @@ int magisk_main(int argc, char *argv[]) {
|
||||
int fd = connect_daemon(true);
|
||||
write_int(fd, BOOT_COMPLETE);
|
||||
return read_int(fd);
|
||||
} else if (argv[1] == "--sqlite"sv) {
|
||||
} else if (argc >= 3 && argv[1] == "--sqlite"sv) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, SQLITE_CMD);
|
||||
write_string(fd, argv[2]);
|
||||
@ -115,14 +113,23 @@ int magisk_main(int argc, char *argv[]) {
|
||||
printf("%s\n", res);
|
||||
free(res);
|
||||
}
|
||||
} else if (argv[1] == "--use-broadcast"sv) {
|
||||
} else if (argv[1] == "--connect-mode"sv) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, BROADCAST_ACK);
|
||||
return 0;
|
||||
if (argc >= 3) {
|
||||
write_int(fd, parse_int(argv[2]));
|
||||
} else {
|
||||
write_int(fd, -1);
|
||||
}
|
||||
return read_int(fd);
|
||||
} else if (argv[1] == "--remove-modules"sv) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, REMOVE_MODULES);
|
||||
return read_int(fd);
|
||||
} else if (argv[1] == "--broadcast-test"sv) {
|
||||
int fd = connect_daemon();
|
||||
write_int(fd, BROADCAST_TEST);
|
||||
return read_int(fd);
|
||||
}
|
||||
#if 0
|
||||
/* Entry point for testing stuffs */
|
||||
|
@ -19,6 +19,7 @@ enum {
|
||||
SQLITE_CMD,
|
||||
BROADCAST_ACK,
|
||||
REMOVE_MODULES,
|
||||
BROADCAST_TEST,
|
||||
};
|
||||
|
||||
// Return codes for daemon
|
||||
@ -84,10 +85,13 @@ void magiskhide_handler(int client);
|
||||
*************/
|
||||
|
||||
void su_daemon_handler(int client, struct ucred *credential);
|
||||
void broadcast_test();
|
||||
void broadcast_test(int client = -1);
|
||||
void broadcast_ack(int client);
|
||||
|
||||
/*********************
|
||||
* Daemon Global Vars
|
||||
*********************/
|
||||
|
||||
extern int SDK_INT;
|
||||
extern bool RECOVERY_MODE;
|
||||
extern bool CONNECT_BROADCAST;
|
||||
|
||||
#define APP_DATA_DIR (SDK_INT >= 24 ? "/data/user_de" : "/data/user")
|
||||
|
@ -7,12 +7,20 @@
|
||||
|
||||
#include <daemon.h>
|
||||
#include <utils.h>
|
||||
#include <logging.h>
|
||||
|
||||
#include "su.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
bool CONNECT_BROADCAST;
|
||||
enum connect_mode {
|
||||
UNINITIALIZED = 0,
|
||||
MODE_ACTIVITY,
|
||||
MODE_BROADCAST_COMPONENT,
|
||||
MODE_BROADCAST_PACKAGE
|
||||
};
|
||||
|
||||
static connect_mode current_mode = UNINITIALIZED;
|
||||
|
||||
#define START_ACTIVITY \
|
||||
"/system/bin/app_process", "/system/bin", "com.android.commands.am.Am", \
|
||||
@ -25,9 +33,28 @@ bool CONNECT_BROADCAST;
|
||||
"broadcast", "-n", nullptr, "--user", nullptr, "-f", "0x00000020", \
|
||||
"-a", "android.intent.action.REBOOT", "--es", "action"
|
||||
|
||||
#define START_BROADCAST_PKG \
|
||||
"/system/bin/app_process", "/system/bin", "com.android.commands.am.Am", \
|
||||
"broadcast", "-p", nullptr, "--user", nullptr, "-f", "0x00000020", \
|
||||
"-a", "android.intent.action.REBOOT", "--es", "action"
|
||||
|
||||
// 0x00000020 = FLAG_INCLUDE_STOPPED_PACKAGES
|
||||
|
||||
static inline const char *get_command(const su_request *to) {
|
||||
#define am_app_info(info, ...) \
|
||||
if (current_mode == MODE_BROADCAST_PACKAGE) { \
|
||||
const char *cmd[] = { START_BROADCAST_PKG, __VA_ARGS__, nullptr }; \
|
||||
exec_am_cmd(cmd, info); \
|
||||
} else if (current_mode == MODE_BROADCAST_COMPONENT) { \
|
||||
const char *cmd[] = { START_BROADCAST, __VA_ARGS__, nullptr }; \
|
||||
exec_am_cmd(cmd, info); \
|
||||
} else { \
|
||||
const char *cmd[] = { START_ACTIVITY, __VA_ARGS__, nullptr }; \
|
||||
exec_am_cmd(cmd, info); \
|
||||
}
|
||||
|
||||
#define am_app(...) am_app_info(ctx.info.get(), __VA_ARGS__)
|
||||
|
||||
static const char *get_command(const su_request *to) {
|
||||
if (to->command[0])
|
||||
return to->command;
|
||||
if (to->shell[0])
|
||||
@ -35,14 +62,14 @@ static inline const char *get_command(const su_request *to) {
|
||||
return DEFAULT_SHELL;
|
||||
}
|
||||
|
||||
static inline void get_user(char *user, const su_info *info) {
|
||||
static void get_user(char *user, const 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, const su_info *info) {
|
||||
static void get_uid(char *uid, const su_info *info) {
|
||||
sprintf(uid, "%d",
|
||||
info->cfg[SU_MULTIUSER_MODE] == MULTIUSER_MODE_OWNER_MANAGED
|
||||
? info->uid % 100000
|
||||
@ -50,13 +77,25 @@ static inline void get_uid(char *uid, const su_info *info) {
|
||||
}
|
||||
|
||||
static void exec_am_cmd(const char **args, const su_info *info) {
|
||||
char component[128];
|
||||
sprintf(component, "%s/%s", info->str[SU_MANAGER].data(), args[3][0] == 'b' ? "a.h" : "a.m");
|
||||
char target[128];
|
||||
if (args[3][0] == 'b') {
|
||||
// Broadcast
|
||||
if (args[4][1] == 'p') {
|
||||
// Broadcast to package (receiver can be obfuscated)
|
||||
strcpy(target, info->str[SU_MANAGER].data());
|
||||
} else {
|
||||
// a.h is the broadcast receiver
|
||||
sprintf(target, "%s/a.h", info->str[SU_MANAGER].data());
|
||||
}
|
||||
} else {
|
||||
// a.m is the activity
|
||||
sprintf(target, "%s/a.m", info->str[SU_MANAGER].data());
|
||||
}
|
||||
char user[8];
|
||||
get_user(user, info);
|
||||
|
||||
/* Fill in dynamic arguments */
|
||||
args[5] = component;
|
||||
// Fill in non static arguments
|
||||
args[5] = target;
|
||||
args[7] = user;
|
||||
|
||||
exec_t exec {
|
||||
@ -79,8 +118,7 @@ static void exec_am_cmd(const char **args, const su_info *info) {
|
||||
"--ei", "pid", pid, \
|
||||
"--ei", "policy", policy, \
|
||||
"--es", "command", get_command(&ctx.req), \
|
||||
"--ez", "notify", ctx.info->access.notify ? "true" : "false", \
|
||||
nullptr
|
||||
"--ez", "notify", ctx.info->access.notify ? "true" : "false"
|
||||
|
||||
void app_log(const su_context &ctx) {
|
||||
char fromUid[8];
|
||||
@ -95,20 +133,13 @@ void app_log(const su_context &ctx) {
|
||||
char policy[2];
|
||||
sprintf(policy, "%d", ctx.info->access.policy);
|
||||
|
||||
if (CONNECT_BROADCAST) {
|
||||
const char *cmd[] = { START_BROADCAST, LOG_BODY };
|
||||
exec_am_cmd(cmd, ctx.info.get());
|
||||
} else {
|
||||
const char *cmd[] = { START_ACTIVITY, LOG_BODY };
|
||||
exec_am_cmd(cmd, ctx.info.get());
|
||||
}
|
||||
am_app(LOG_BODY)
|
||||
}
|
||||
|
||||
#define NOTIFY_BODY \
|
||||
"notify", \
|
||||
"--ei", "from.uid", fromUid, \
|
||||
"--ei", "policy", policy, \
|
||||
nullptr
|
||||
"--ei", "policy", policy
|
||||
|
||||
void app_notify(const su_context &ctx) {
|
||||
char fromUid[8];
|
||||
@ -117,33 +148,59 @@ void app_notify(const su_context &ctx) {
|
||||
char policy[2];
|
||||
sprintf(policy, "%d", ctx.info->access.policy);
|
||||
|
||||
if (CONNECT_BROADCAST) {
|
||||
const char *cmd[] = { START_BROADCAST, NOTIFY_BODY };
|
||||
exec_am_cmd(cmd, ctx.info.get());
|
||||
} else {
|
||||
const char *cmd[] = { START_ACTIVITY, NOTIFY_BODY };
|
||||
exec_am_cmd(cmd, ctx.info.get());
|
||||
am_app(NOTIFY_BODY)
|
||||
}
|
||||
|
||||
#define SOCKET_BODY \
|
||||
"request", \
|
||||
"--es", "socket", socket
|
||||
|
||||
void app_socket(const char *socket, const shared_ptr<su_info> &info) {
|
||||
am_app_info(info.get(), SOCKET_BODY)
|
||||
}
|
||||
|
||||
#define TEST_BODY \
|
||||
"test", "--ei", "mode", mode, nullptr
|
||||
|
||||
void broadcast_test(int client) {
|
||||
if (client >= 0) {
|
||||
// Make it not uninitialized
|
||||
current_mode = MODE_ACTIVITY;
|
||||
write_int(client, 0);
|
||||
close(client);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void app_connect(const char *socket, const shared_ptr<su_info> &info) {
|
||||
const char *cmd[] = {
|
||||
START_ACTIVITY, "request",
|
||||
"--es", "socket", socket,
|
||||
nullptr
|
||||
};
|
||||
exec_am_cmd(cmd, info.get());
|
||||
}
|
||||
|
||||
void broadcast_test() {
|
||||
su_info info;
|
||||
get_db_settings(info.cfg);
|
||||
get_db_strings(info.str);
|
||||
validate_manager(info.str[SU_MANAGER], 0, &info.mgr_st);
|
||||
|
||||
const char *cmd[] = { START_BROADCAST, "test", nullptr };
|
||||
char mode[2];
|
||||
{
|
||||
sprintf(mode, "%d", MODE_BROADCAST_PACKAGE);
|
||||
const char *cmd[] = { START_BROADCAST_PKG, TEST_BODY };
|
||||
exec_am_cmd(cmd, &info);
|
||||
}
|
||||
{
|
||||
sprintf(mode, "%d", MODE_BROADCAST_COMPONENT);
|
||||
const char *cmd[] = { START_BROADCAST, TEST_BODY };
|
||||
exec_am_cmd(cmd, &info);
|
||||
}
|
||||
}
|
||||
|
||||
void broadcast_ack(int client) {
|
||||
int mode = read_int(client);
|
||||
if (mode < 0) {
|
||||
// Return connection mode to client
|
||||
write_int(client, current_mode);
|
||||
} else {
|
||||
if (mode > current_mode) {
|
||||
LOGD("* Use connect mode [%d] for su request and notify\n", mode);
|
||||
current_mode = static_cast<connect_mode>(mode);
|
||||
}
|
||||
write_int(client, 0);
|
||||
}
|
||||
close(client);
|
||||
}
|
||||
|
||||
void socket_send_request(int fd, const shared_ptr<su_info> &info) {
|
||||
|
@ -68,5 +68,5 @@ struct su_context {
|
||||
|
||||
void app_log(const su_context &ctx);
|
||||
void app_notify(const su_context &ctx);
|
||||
void app_connect(const char *socket, const std::shared_ptr<su_info> &info);
|
||||
void app_socket(const char *socket, const std::shared_ptr<su_info> &info);
|
||||
void socket_send_request(int fd, const std::shared_ptr<su_info> &info);
|
||||
|
@ -144,7 +144,7 @@ static shared_ptr<su_info> get_su_info(unsigned uid) {
|
||||
int sockfd = create_rand_socket(&addr);
|
||||
|
||||
// Connect manager
|
||||
app_connect(addr.sun_path + 1, info);
|
||||
app_socket(addr.sun_path + 1, info);
|
||||
int fd = socket_accept(sockfd, 60);
|
||||
if (fd < 0) {
|
||||
info->access.policy = DENY;
|
||||
|
Loading…
x
Reference in New Issue
Block a user