Magisk/native/jni/su/connect.cpp

123 lines
2.8 KiB
C++
Raw Normal View History

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdio.h>
2019-02-10 08:57:51 +00:00
#include <daemon.h>
#include <utils.h>
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.
2019-10-21 17:59:04 +00:00
#include <logging.h>
2019-02-10 08:57:51 +00:00
#include "su.h"
using namespace std;
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
#define CALL_PROVIDER \
"/system/bin/app_process", "/system/bin", "com.android.commands.content.Content", \
"call", "--uri", nullptr, "--user", nullptr, "--method"
#define content_exec_info(info, ...) {\
const char *cmd[] = { CALL_PROVIDER, __VA_ARGS__, nullptr }; \
exec_content_cmd(cmd, info); \
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.
2019-10-21 17:59:04 +00:00
}
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
#define content_exec(...) content_exec_info(ctx.info.get(), __VA_ARGS__)
#define ex(s) "--extra", s
#define get_user(info) \
(info->cfg[SU_MULTIUSER_MODE] == MULTIUSER_MODE_USER \
? info->uid / 100000 \
: 0)
#define get_uid(info) \
(info->cfg[SU_MULTIUSER_MODE] == MULTIUSER_MODE_OWNER_MANAGED \
? info->uid % 100000 \
: info->uid)
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.
2019-10-21 17:59:04 +00:00
static const char *get_command(const su_request *to) {
2018-10-04 08:59:51 +00:00
if (to->command[0])
return to->command;
2018-10-04 08:59:51 +00:00
if (to->shell[0])
return to->shell;
return DEFAULT_SHELL;
}
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
static void exec_content_cmd(const char **args, const su_info *info) {
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.
2019-10-21 17:59:04 +00:00
char target[128];
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
sprintf(target, "content://%s.provider", info->str[SU_MANAGER].data());
char user[4];
sprintf(user, "%d", get_user(info));
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.
2019-10-21 17:59:04 +00:00
// Fill in non static arguments
args[5] = target;
args[7] = user;
exec_t exec {
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
.pre_exec = [] {
int null = xopen("/dev/null", O_WRONLY | O_CLOEXEC);
dup2(null, STDOUT_FILENO);
dup2(null, STDERR_FILENO);
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
setenv("CLASSPATH", "/system/framework/content.jar", 1);
},
.fork = fork_dont_care,
.argv = args
};
exec_command(exec);
}
#define LOG_BODY \
"log", \
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
ex(fromUid), ex(toUid), ex(pid), ex(policy), \
ex(command.data()), ex(notify)
void app_log(const su_context &ctx) {
2019-11-05 06:46:46 +00:00
char fromUid[32];
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
sprintf(fromUid, "from.uid:i:%d", get_uid(ctx.info));
2019-11-05 06:46:46 +00:00
char toUid[32];
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
sprintf(toUid, "to.uid:i:%d", ctx.req.uid);
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
char pid[16];
sprintf(pid, "pid:i:%d", ctx.pid);
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
char policy[16];
sprintf(policy, "policy:i:%d", ctx.info->access.policy);
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
string command("command:s:");
command += get_command(&ctx.req);
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
char notify[16];
sprintf(notify, "notify:b:%s", ctx.info->access.notify ? "true" : "false");
content_exec(LOG_BODY)
}
#define NOTIFY_BODY \
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
"notify", ex(fromUid), ex(policy)
void app_notify(const su_context &ctx) {
2019-11-05 06:46:46 +00:00
char fromUid[32];
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
sprintf(fromUid, "from.uid:i:%d", get_uid(ctx.info));
2018-10-28 02:06:24 +00:00
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
char policy[16];
sprintf(policy, "policy:i:%d", ctx.info->access.policy);
2018-10-28 02:06:24 +00:00
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
content_exec(NOTIFY_BODY)
2018-10-28 02:06:24 +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.
2019-10-21 17:59:04 +00:00
#define SOCKET_BODY \
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
"request", ex(sock)
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.
2019-10-21 17:59:04 +00:00
void app_socket(const char *socket, const shared_ptr<su_info> &info) {
Use ContentProvider call method for communication Previously, we use either BroadcastReceivers or Activities to receive messages from our native daemon, but both have their own downsides. Some OEMs blocks broadcasts if the app is not running in the background, regardless of who the caller is. Activities on the other hand, despite working 100% of the time, will steal the focus of the current foreground app, even though we are just doing some logging and showing a toast. In addition, since stubs for hiding Magisk Manager is introduced, our only communication method is left with the broadcast option, as only broadcasting allows targeting a specific package name, not a component name (which will be obfuscated in the case of stubs). To make sure root requests will work on all devices, Magisk had to do some experiments every boot to test whether broadcast is deliverable or not. This makes the whole thing even more complicated then ever. So lets take a look at another kind of component in Android apps: ContentProviders. It is a vital part of Android's ecosystem, and as far as I know no OEMs will block requests to ContentProviders (or else tons of functionality will break catastrophically). Starting at API 11, the system supports calling a specific method in ContentProviders, optionally sending extra data along with the method call. This is perfect for the native daemon to start a communication with Magisk Manager. Another cool thing is that we no longer need to know the component name of the reciever, as ContentProviders identify themselves with an "authority" name, which in Magisk Manager's case is tied to the package name. We already have a mechanism to keep track of our current manager package name, so this works out of the box. So yay! No more flaky broadcast tests, no more stupid OEMs blocking broadcasts for some bizzare reasons. This method should in theory work on almost all devices and situations.
2019-11-04 19:32:28 +00:00
char sock[128];
sprintf(sock, "socket:s:%s", socket);
content_exec_info(info.get(), SOCKET_BODY)
}
void socket_send_request(int fd, const shared_ptr<su_info> &info) {
2018-10-04 08:59:51 +00:00
write_key_token(fd, "uid", info->uid);
write_string_be(fd, "eof");
}