You've already forked Magisk
mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-09-06 06:36:58 +00:00
Compare commits
9 Commits
v30.2
...
1333d3b986
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1333d3b986 | ||
|
|
335146a6a2 | ||
|
|
eaf9527971 | ||
|
|
da937a88c8 | ||
|
|
9476e7282d | ||
|
|
251c3c3e0e | ||
|
|
cd0eca20b0 | ||
|
|
6839cb9ab2 | ||
|
|
d11a3397d8 |
@@ -24,7 +24,6 @@ LOCAL_SRC_FILES := \
|
|||||||
core/core-rs.cpp \
|
core/core-rs.cpp \
|
||||||
core/resetprop/resetprop.cpp \
|
core/resetprop/resetprop.cpp \
|
||||||
core/su/su.cpp \
|
core/su/su.cpp \
|
||||||
core/su/connect.cpp \
|
|
||||||
core/zygisk/entry.cpp \
|
core/zygisk/entry.cpp \
|
||||||
core/zygisk/module.cpp \
|
core/zygisk/module.cpp \
|
||||||
core/zygisk/hook.cpp \
|
core/zygisk/hook.cpp \
|
||||||
|
|||||||
@@ -140,8 +140,14 @@ pub struct FileAttr {
|
|||||||
pub con: crate::Utf8CStrBufArr<128>,
|
pub con: crate::Utf8CStrBufArr<128>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for FileAttr {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FileAttr {
|
impl FileAttr {
|
||||||
fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
FileAttr {
|
FileAttr {
|
||||||
st: unsafe { mem::zeroed() },
|
st: unsafe { mem::zeroed() },
|
||||||
#[cfg(feature = "selinux")]
|
#[cfg(feature = "selinux")]
|
||||||
|
|||||||
@@ -112,9 +112,6 @@ void update_deny_flags(int uid, rust::Str process, uint32_t &flags);
|
|||||||
|
|
||||||
// MagiskSU
|
// MagiskSU
|
||||||
void exec_root_shell(int client, int pid, SuRequest &req, MntNsMode mode);
|
void exec_root_shell(int client, int pid, SuRequest &req, MntNsMode mode);
|
||||||
void app_log(const SuAppRequest &info, SuPolicy policy, bool notify);
|
|
||||||
void app_notify(const SuAppRequest &info, SuPolicy policy);
|
|
||||||
int app_request(const SuAppRequest &info);
|
|
||||||
|
|
||||||
// Rust bindings
|
// Rust bindings
|
||||||
static inline rust::Utf8CStr get_magisk_tmp_rs() { return get_magisk_tmp(); }
|
static inline rust::Utf8CStr get_magisk_tmp_rs() { return get_magisk_tmp(); }
|
||||||
|
|||||||
@@ -125,15 +125,6 @@ pub mod ffi {
|
|||||||
gids: Vec<u32>,
|
gids: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SuAppRequest<'a> {
|
|
||||||
uid: i32,
|
|
||||||
pid: i32,
|
|
||||||
eval_uid: i32,
|
|
||||||
mgr_pkg: &'a str,
|
|
||||||
mgr_uid: i32,
|
|
||||||
request: &'a SuRequest,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C++" {
|
unsafe extern "C++" {
|
||||||
#[namespace = "rust"]
|
#[namespace = "rust"]
|
||||||
#[cxx_name = "Utf8CStr"]
|
#[cxx_name = "Utf8CStr"]
|
||||||
@@ -161,9 +152,6 @@ pub mod ffi {
|
|||||||
fn set_zygisk_prop();
|
fn set_zygisk_prop();
|
||||||
fn restore_zygisk_prop();
|
fn restore_zygisk_prop();
|
||||||
fn switch_mnt_ns(pid: i32) -> i32;
|
fn switch_mnt_ns(pid: i32) -> i32;
|
||||||
fn app_request(req: &SuAppRequest) -> i32;
|
|
||||||
fn app_notify(req: &SuAppRequest, policy: SuPolicy);
|
|
||||||
fn app_log(req: &SuAppRequest, policy: SuPolicy, notify: bool);
|
|
||||||
fn exec_root_shell(client: i32, pid: i32, req: &mut SuRequest, mode: MntNsMode);
|
fn exec_root_shell(client: i32, pid: i32, req: &mut SuRequest, mode: MntNsMode);
|
||||||
|
|
||||||
include!("include/sqlite.hpp");
|
include!("include/sqlite.hpp");
|
||||||
@@ -211,7 +199,7 @@ pub mod ffi {
|
|||||||
fn send_fds(socket: i32, fds: &[i32]) -> bool;
|
fn send_fds(socket: i32, fds: &[i32]) -> bool;
|
||||||
fn recv_fd(socket: i32) -> i32;
|
fn recv_fd(socket: i32) -> i32;
|
||||||
fn recv_fds(socket: i32) -> Vec<i32>;
|
fn recv_fds(socket: i32) -> Vec<i32>;
|
||||||
unsafe fn write_to_fd(self: &SuRequest, fd: i32);
|
fn write_to_fd(self: &SuRequest, fd: i32);
|
||||||
fn pump_tty(infd: i32, outfd: i32);
|
fn pump_tty(infd: i32, outfd: i32);
|
||||||
fn get_pty_num(fd: i32) -> i32;
|
fn get_pty_num(fd: i32) -> i32;
|
||||||
fn restore_stdin() -> bool;
|
fn restore_stdin() -> bool;
|
||||||
@@ -266,7 +254,7 @@ unsafe impl ExternType for UCred {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SuRequest {
|
impl SuRequest {
|
||||||
unsafe fn write_to_fd(&self, fd: i32) {
|
fn write_to_fd(&self, fd: i32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut w = ManuallyDrop::new(File::from_raw_fd(fd));
|
let mut w = ManuallyDrop::new(File::from_raw_fd(fd));
|
||||||
self.encode(w.deref_mut()).ok();
|
self.encode(w.deref_mut()).ok();
|
||||||
|
|||||||
@@ -376,7 +376,7 @@ fn get_path_env() -> String {
|
|||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inject_magisk_bins(system: &mut FsNode) {
|
fn inject_magisk_bins(system: &mut FsNode, is_emulator: bool) {
|
||||||
fn inject(children: &mut FsNodeMap) {
|
fn inject(children: &mut FsNodeMap) {
|
||||||
let mut path = cstr::buf::default().join_path(get_magisk_tmp());
|
let mut path = cstr::buf::default().join_path(get_magisk_tmp());
|
||||||
|
|
||||||
@@ -418,7 +418,7 @@ fn inject_magisk_bins(system: &mut FsNode) {
|
|||||||
let mut candidates = vec![];
|
let mut candidates = vec![];
|
||||||
|
|
||||||
for orig_item in path_env.split(':') {
|
for orig_item in path_env.split(':') {
|
||||||
// Filter not suitbale paths
|
// Filter non-suitable paths
|
||||||
if !MAGISK_BIN_INJECT_PARTITIONS
|
if !MAGISK_BIN_INJECT_PARTITIONS
|
||||||
.iter()
|
.iter()
|
||||||
.any(|p| orig_item.starts_with(p.as_str()))
|
.any(|p| orig_item.starts_with(p.as_str()))
|
||||||
@@ -430,6 +430,11 @@ fn inject_magisk_bins(system: &mut FsNode) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We want to keep /system/xbin/su on emulators (for debugging)
|
||||||
|
if is_emulator && orig_item.starts_with("/system/xbin") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Override existing su first
|
// Override existing su first
|
||||||
let su_path = Utf8CString::from(format!("{orig_item}/su"));
|
let su_path = Utf8CString::from(format!("{orig_item}/su"));
|
||||||
if su_path.exists() {
|
if su_path.exists() {
|
||||||
@@ -555,7 +560,7 @@ fn inject_zygisk_bins(system: &mut FsNode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_modules(zygisk: bool, module_list: &[ModuleInfo]) {
|
fn apply_modules(zygisk: bool, module_list: &[ModuleInfo], is_emulator: bool) {
|
||||||
let mut system = FsNode::new_dir();
|
let mut system = FsNode::new_dir();
|
||||||
|
|
||||||
// Build all the base "prefix" paths
|
// Build all the base "prefix" paths
|
||||||
@@ -620,7 +625,7 @@ fn apply_modules(zygisk: bool, module_list: &[ModuleInfo]) {
|
|||||||
// step, treating Magisk just like a special "module".
|
// step, treating Magisk just like a special "module".
|
||||||
|
|
||||||
if get_magisk_tmp() != "/sbin" || get_path_env().split(":").all(|s| s != "/sbin") {
|
if get_magisk_tmp() != "/sbin" || get_path_env().split(":").all(|s| s != "/sbin") {
|
||||||
inject_magisk_bins(&mut system);
|
inject_magisk_bins(&mut system, is_emulator);
|
||||||
}
|
}
|
||||||
if zygisk {
|
if zygisk {
|
||||||
inject_zygisk_bins(&mut system);
|
inject_zygisk_bins(&mut system);
|
||||||
@@ -875,7 +880,7 @@ impl MagiskD {
|
|||||||
if zygisk {
|
if zygisk {
|
||||||
set_zygisk_prop();
|
set_zygisk_prop();
|
||||||
}
|
}
|
||||||
apply_modules(zygisk, &modules);
|
apply_modules(zygisk, &modules, self.is_emulator);
|
||||||
|
|
||||||
self.module_list.set(modules).ok();
|
self.module_list.set(modules).ok();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,232 +0,0 @@
|
|||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
#include <base.hpp>
|
|
||||||
#include <consts.hpp>
|
|
||||||
#include <core.hpp>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
#define CALL_PROVIDER \
|
|
||||||
"/system/bin/app_process", "/system/bin", "com.android.commands.content.Content", \
|
|
||||||
"call", "--uri", target, "--user", user, "--method", action
|
|
||||||
|
|
||||||
#define START_ACTIVITY \
|
|
||||||
"/system/bin/app_process", "/system/bin", "com.android.commands.am.Am", \
|
|
||||||
"start", "-p", target, "--user", user, "-a", "android.intent.action.VIEW", \
|
|
||||||
"-f", "0x18800020", "--es", "action", action
|
|
||||||
|
|
||||||
// 0x18800020 = FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_MULTIPLE_TASK|
|
|
||||||
// FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS|FLAG_INCLUDE_STOPPED_PACKAGES
|
|
||||||
|
|
||||||
class Extra {
|
|
||||||
const char *key;
|
|
||||||
enum {
|
|
||||||
INT,
|
|
||||||
BOOL,
|
|
||||||
STRING,
|
|
||||||
INTLIST,
|
|
||||||
} type;
|
|
||||||
union {
|
|
||||||
int int_val;
|
|
||||||
bool bool_val;
|
|
||||||
const char *str_val;
|
|
||||||
const vector<uint32_t> *intlist_val;
|
|
||||||
};
|
|
||||||
string str;
|
|
||||||
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) {}
|
|
||||||
Extra(const char *k, const vector<uint32_t> *v): key(k), type(INTLIST), intlist_val(v) {}
|
|
||||||
|
|
||||||
void add_intent(vector<const char *> &vec) {
|
|
||||||
const char *val;
|
|
||||||
switch (type) {
|
|
||||||
case INT:
|
|
||||||
vec.push_back("--ei");
|
|
||||||
str = to_string(int_val);
|
|
||||||
val = str.data();
|
|
||||||
break;
|
|
||||||
case BOOL:
|
|
||||||
vec.push_back("--ez");
|
|
||||||
val = bool_val ? "true" : "false";
|
|
||||||
break;
|
|
||||||
case STRING:
|
|
||||||
vec.push_back("--es");
|
|
||||||
val = str_val;
|
|
||||||
break;
|
|
||||||
case INTLIST:
|
|
||||||
vec.push_back("--es");
|
|
||||||
for (auto i : *intlist_val) {
|
|
||||||
str += to_string(i);
|
|
||||||
str += ",";
|
|
||||||
}
|
|
||||||
if (!str.empty()) str.pop_back();
|
|
||||||
val = str.data();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
vec.push_back(key);
|
|
||||||
vec.push_back(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_bind(vector<const char *> &vec) {
|
|
||||||
char buf[32];
|
|
||||||
str = key;
|
|
||||||
switch (type) {
|
|
||||||
case INT:
|
|
||||||
str += ":i:";
|
|
||||||
ssprintf(buf, sizeof(buf), "%d", int_val);
|
|
||||||
str += buf;
|
|
||||||
break;
|
|
||||||
case BOOL:
|
|
||||||
str += ":b:";
|
|
||||||
str += bool_val ? "true" : "false";
|
|
||||||
break;
|
|
||||||
case STRING:
|
|
||||||
str += ":s:";
|
|
||||||
if (SDK_INT >= 30) {
|
|
||||||
string tmp = str_val;
|
|
||||||
replace_all(tmp, "\\", "\\\\");
|
|
||||||
replace_all(tmp, ":", "\\:");
|
|
||||||
str += tmp;
|
|
||||||
} else {
|
|
||||||
str += str_val;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case INTLIST:
|
|
||||||
str += ":s:";
|
|
||||||
for (auto i : *intlist_val) {
|
|
||||||
str += to_string(i);
|
|
||||||
str += ",";
|
|
||||||
}
|
|
||||||
if (str.back() == ',') str.pop_back();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
vec.push_back("--extra");
|
|
||||||
vec.push_back(str.data());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool check_no_error(int fd) {
|
|
||||||
char buf[1024];
|
|
||||||
auto out = xopen_file(fd, "r");
|
|
||||||
while (fgets(buf, sizeof(buf), out.get())) {
|
|
||||||
if (strncasecmp(buf, "Error", 5) == 0) {
|
|
||||||
LOGD("exec_cmd: %s\n", buf);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void exec_cmd(const char *action, vector<Extra> &data,
|
|
||||||
const SuAppRequest &info, bool provider = true) {
|
|
||||||
char target[128];
|
|
||||||
char user[4];
|
|
||||||
ssprintf(user, sizeof(user), "%d", to_user_id(info.eval_uid));
|
|
||||||
|
|
||||||
// First try content provider call method
|
|
||||||
if (provider) {
|
|
||||||
ssprintf(target, sizeof(target), "content://%.*s.provider",
|
|
||||||
(int) info.mgr_pkg.size(), info.mgr_pkg.data());
|
|
||||||
vector<const char *> 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_no_error(exec.fd))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then try start activity with package name
|
|
||||||
ssprintf(target, sizeof(target), "%.*s", (int) info.mgr_pkg.size(), info.mgr_pkg.data());
|
|
||||||
vector<const char *> args{ START_ACTIVITY };
|
|
||||||
for (auto &e : data) {
|
|
||||||
e.add_intent(args);
|
|
||||||
}
|
|
||||||
args.push_back(nullptr);
|
|
||||||
exec_t exec {
|
|
||||||
.fd = -2,
|
|
||||||
.pre_exec = [] { setenv("CLASSPATH", "/system/framework/am.jar", 1); },
|
|
||||||
.fork = fork_dont_care,
|
|
||||||
.argv = args.data()
|
|
||||||
};
|
|
||||||
exec_command(exec);
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_log(const SuAppRequest &info, SuPolicy policy, bool notify) {
|
|
||||||
if (fork_dont_care() == 0) {
|
|
||||||
string context = (string) info.request.context;
|
|
||||||
string command = info.request.command.empty()
|
|
||||||
? (string) info.request.shell
|
|
||||||
: (string) info.request.command;
|
|
||||||
|
|
||||||
vector<Extra> extras;
|
|
||||||
extras.reserve(9);
|
|
||||||
extras.emplace_back("from.uid", info.uid);
|
|
||||||
extras.emplace_back("to.uid", info.request.target_uid);
|
|
||||||
extras.emplace_back("pid", info.pid);
|
|
||||||
extras.emplace_back("policy", +policy);
|
|
||||||
extras.emplace_back("target", info.request.target_pid);
|
|
||||||
extras.emplace_back("context", context.data());
|
|
||||||
extras.emplace_back("gids", &info.request.gids);
|
|
||||||
extras.emplace_back("command", command.data());
|
|
||||||
extras.emplace_back("notify", notify);
|
|
||||||
|
|
||||||
exec_cmd("log", extras, info);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void app_notify(const SuAppRequest &info, SuPolicy policy) {
|
|
||||||
if (fork_dont_care() == 0) {
|
|
||||||
vector<Extra> extras;
|
|
||||||
extras.reserve(3);
|
|
||||||
extras.emplace_back("from.uid", info.uid);
|
|
||||||
extras.emplace_back("pid", info.pid);
|
|
||||||
extras.emplace_back("policy", +policy);
|
|
||||||
|
|
||||||
exec_cmd("notify", extras, info);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int app_request(const SuAppRequest &info) {
|
|
||||||
// Create FIFO
|
|
||||||
char fifo[64];
|
|
||||||
ssprintf(fifo, sizeof(fifo), "%s/" INTLROOT "/su_request_%d", get_magisk_tmp(), info.pid);
|
|
||||||
mkfifo(fifo, 0600);
|
|
||||||
chown(fifo, info.mgr_uid, info.mgr_uid);
|
|
||||||
setfilecon(fifo, MAGISK_FILE_CON);
|
|
||||||
|
|
||||||
// Send request
|
|
||||||
vector<Extra> extras;
|
|
||||||
extras.reserve(3);
|
|
||||||
extras.emplace_back("fifo", fifo);
|
|
||||||
extras.emplace_back("uid", info.eval_uid);
|
|
||||||
extras.emplace_back("pid", info.pid);
|
|
||||||
exec_cmd("request", extras, info, false);
|
|
||||||
|
|
||||||
// Wait for data input for at most 70 seconds
|
|
||||||
// Open with O_RDWR to prevent FIFO open block
|
|
||||||
int fd = xopen(fifo, O_RDWR | O_CLOEXEC);
|
|
||||||
struct pollfd pfd = {
|
|
||||||
.fd = fd,
|
|
||||||
.events = POLLIN
|
|
||||||
};
|
|
||||||
if (xpoll(&pfd, 1, 70 * 1000) <= 0) {
|
|
||||||
close(fd);
|
|
||||||
fd = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unlink(fifo);
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
315
native/src/core/su/connect.rs
Normal file
315
native/src/core/su/connect.rs
Normal file
@@ -0,0 +1,315 @@
|
|||||||
|
use super::SuInfo;
|
||||||
|
use super::db::RootSettings;
|
||||||
|
use crate::consts::{INTERNAL_DIR, MAGISK_FILE_CON};
|
||||||
|
use crate::daemon::to_user_id;
|
||||||
|
use crate::ffi::{SuPolicy, SuRequest, get_magisk_tmp};
|
||||||
|
use crate::socket::IpcRead;
|
||||||
|
use ExtraVal::{Bool, Int, IntList, Str};
|
||||||
|
use base::{
|
||||||
|
BytesExt, FileAttr, LibcReturn, LoggedResult, OsError, ResultExt, cstr, fork_dont_care, libc,
|
||||||
|
};
|
||||||
|
use libc::pollfd as PollFd;
|
||||||
|
use num_traits::AsPrimitive;
|
||||||
|
use std::{fmt::Write, fs::File, os::fd::AsRawFd, process::Command, process::exit};
|
||||||
|
|
||||||
|
struct Extra<'a> {
|
||||||
|
key: &'static str,
|
||||||
|
value: ExtraVal<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ExtraVal<'a> {
|
||||||
|
Int(i32),
|
||||||
|
Bool(bool),
|
||||||
|
Str(&'a str),
|
||||||
|
IntList(&'a [u32]),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Extra<'_> {
|
||||||
|
fn add_intent(&self, cmd: &mut Command) {
|
||||||
|
match self.value {
|
||||||
|
Int(i) => {
|
||||||
|
cmd.args(["--ei", self.key, &i.to_string()]);
|
||||||
|
}
|
||||||
|
Bool(b) => {
|
||||||
|
cmd.args(["--ez", self.key, &b.to_string()]);
|
||||||
|
}
|
||||||
|
Str(s) => {
|
||||||
|
cmd.args(["--es", self.key, s]);
|
||||||
|
}
|
||||||
|
IntList(list) => {
|
||||||
|
cmd.args(["--es", self.key]);
|
||||||
|
let mut tmp = String::new();
|
||||||
|
list.iter().for_each(|i| write!(&mut tmp, "{i},").unwrap());
|
||||||
|
tmp.pop();
|
||||||
|
cmd.arg(&tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_bind(&self, cmd: &mut Command) {
|
||||||
|
let mut tmp: String;
|
||||||
|
match self.value {
|
||||||
|
Int(i) => {
|
||||||
|
tmp = format!("{}:i:{}", self.key, i);
|
||||||
|
}
|
||||||
|
Bool(b) => {
|
||||||
|
tmp = format!("{}:b:{}", self.key, b);
|
||||||
|
}
|
||||||
|
Str(s) => {
|
||||||
|
let s = s.replace("\\", "\\\\").replace(":", "\\:");
|
||||||
|
tmp = format!("{}:s:{}", self.key, s);
|
||||||
|
}
|
||||||
|
IntList(list) => {
|
||||||
|
tmp = format!("{}:s:", self.key);
|
||||||
|
if !list.is_empty() {
|
||||||
|
list.iter().for_each(|i| write!(&mut tmp, "{i},").unwrap());
|
||||||
|
tmp.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd.args(["--extra", &tmp]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_bind_legacy(&self, cmd: &mut Command) {
|
||||||
|
match self.value {
|
||||||
|
Str(s) => {
|
||||||
|
let tmp = format!("{}:s:{}", self.key, s);
|
||||||
|
cmd.args(["--extra", &tmp]);
|
||||||
|
}
|
||||||
|
_ => self.add_bind(cmd),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) struct SuAppContext<'a> {
|
||||||
|
pub(super) cred: libc::ucred,
|
||||||
|
pub(super) request: &'a SuRequest,
|
||||||
|
pub(super) info: &'a SuInfo,
|
||||||
|
pub(super) settings: &'a mut RootSettings,
|
||||||
|
pub(super) sdk_int: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SuAppContext<'_> {
|
||||||
|
fn exec_cmd(&self, action: &'static str, extras: &[Extra], use_provider: bool) {
|
||||||
|
let user = to_user_id(self.info.eval_uid);
|
||||||
|
let user = user.to_string();
|
||||||
|
|
||||||
|
if use_provider {
|
||||||
|
let provider = format!("content://{}.provider", self.info.mgr_pkg);
|
||||||
|
let mut cmd = Command::new("/system/bin/app_process");
|
||||||
|
cmd.args([
|
||||||
|
"/system/bin",
|
||||||
|
"com.android.commands.content.Content",
|
||||||
|
"call",
|
||||||
|
"--uri",
|
||||||
|
&provider,
|
||||||
|
"--user",
|
||||||
|
&user,
|
||||||
|
"--method",
|
||||||
|
action,
|
||||||
|
]);
|
||||||
|
if self.sdk_int >= 30 {
|
||||||
|
extras.iter().for_each(|e| e.add_bind(&mut cmd))
|
||||||
|
} else {
|
||||||
|
extras.iter().for_each(|e| e.add_bind_legacy(&mut cmd))
|
||||||
|
}
|
||||||
|
cmd.env("CLASSPATH", "/system/framework/content.jar");
|
||||||
|
|
||||||
|
if let Ok(output) = cmd.output()
|
||||||
|
&& !output.stderr.contains(b"Error")
|
||||||
|
&& !output.stdout.contains(b"Error")
|
||||||
|
{
|
||||||
|
// The provider call succeed
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut cmd = Command::new("/system/bin/app_process");
|
||||||
|
cmd.args([
|
||||||
|
"/system/bin",
|
||||||
|
"com.android.commands.am.Am",
|
||||||
|
"start",
|
||||||
|
"-p",
|
||||||
|
&self.info.mgr_pkg,
|
||||||
|
"--user",
|
||||||
|
&user,
|
||||||
|
"-a",
|
||||||
|
"android.intent.action.VIEW",
|
||||||
|
"-f",
|
||||||
|
// FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_MULTIPLE_TASK|
|
||||||
|
// FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS|FLAG_INCLUDE_STOPPED_PACKAGES
|
||||||
|
"0x18800020",
|
||||||
|
"--es",
|
||||||
|
"action",
|
||||||
|
action,
|
||||||
|
]);
|
||||||
|
extras.iter().for_each(|e| e.add_intent(&mut cmd));
|
||||||
|
cmd.env("CLASSPATH", "/system/framework/am.jar");
|
||||||
|
|
||||||
|
// Sometimes `am start` will fail, keep trying until it works
|
||||||
|
loop {
|
||||||
|
if let Ok(output) = cmd.output()
|
||||||
|
&& !output.stdout.is_empty()
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn app_request(&mut self) {
|
||||||
|
let mut fifo = cstr::buf::new::<64>();
|
||||||
|
fifo.write_fmt(format_args!(
|
||||||
|
"{}/{}/su_request_{}",
|
||||||
|
get_magisk_tmp(),
|
||||||
|
INTERNAL_DIR,
|
||||||
|
self.cred.pid
|
||||||
|
))
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
let fd: LoggedResult<File> = try {
|
||||||
|
let mut attr = FileAttr::new();
|
||||||
|
attr.st.st_mode = 0o600;
|
||||||
|
attr.st.st_uid = self.info.mgr_uid.as_();
|
||||||
|
attr.st.st_gid = self.info.mgr_uid.as_();
|
||||||
|
attr.con.write_str(MAGISK_FILE_CON).ok();
|
||||||
|
|
||||||
|
fifo.mkfifo(0o600)?;
|
||||||
|
fifo.set_attr(&attr)?;
|
||||||
|
|
||||||
|
let extras = [
|
||||||
|
Extra {
|
||||||
|
key: "fifo",
|
||||||
|
value: Str(&fifo),
|
||||||
|
},
|
||||||
|
Extra {
|
||||||
|
key: "uid",
|
||||||
|
value: Int(self.info.eval_uid),
|
||||||
|
},
|
||||||
|
Extra {
|
||||||
|
key: "pid",
|
||||||
|
value: Int(self.cred.pid),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
self.exec_cmd("request", &extras, false);
|
||||||
|
|
||||||
|
// Open with O_RDWR to prevent FIFO open block
|
||||||
|
let fd = fifo.open(libc::O_RDWR | libc::O_CLOEXEC)?;
|
||||||
|
|
||||||
|
// Wait for data input for at most 70 seconds
|
||||||
|
let mut pfd = PollFd {
|
||||||
|
fd: fd.as_raw_fd(),
|
||||||
|
events: libc::POLLIN,
|
||||||
|
revents: 0,
|
||||||
|
};
|
||||||
|
if unsafe { libc::poll(&mut pfd, 1, 70 * 1000).as_os_result("poll", None, None)? } == 0
|
||||||
|
{
|
||||||
|
Err(OsError::with_os_error(libc::ETIMEDOUT, "poll", None, None))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd
|
||||||
|
};
|
||||||
|
|
||||||
|
fifo.remove().log_ok();
|
||||||
|
|
||||||
|
if let Ok(mut fd) = fd {
|
||||||
|
self.settings.policy = SuPolicy {
|
||||||
|
repr: fd
|
||||||
|
.read_decodable::<i32>()
|
||||||
|
.log()
|
||||||
|
.map(i32::from_be)
|
||||||
|
.unwrap_or(SuPolicy::Deny.repr),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
self.settings.policy = SuPolicy::Deny;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn app_notify(&self) {
|
||||||
|
let extras = [
|
||||||
|
Extra {
|
||||||
|
key: "from.uid",
|
||||||
|
value: Int(self.cred.uid.as_()),
|
||||||
|
},
|
||||||
|
Extra {
|
||||||
|
key: "pid",
|
||||||
|
value: Int(self.cred.pid.as_()),
|
||||||
|
},
|
||||||
|
Extra {
|
||||||
|
key: "policy",
|
||||||
|
value: Int(self.settings.policy.repr),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
self.exec_cmd("notify", &extras, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn app_log(&self) {
|
||||||
|
let command = if self.request.command.is_empty() {
|
||||||
|
&self.request.shell
|
||||||
|
} else {
|
||||||
|
&self.request.command
|
||||||
|
};
|
||||||
|
let extras = [
|
||||||
|
Extra {
|
||||||
|
key: "from.uid",
|
||||||
|
value: Int(self.cred.uid.as_()),
|
||||||
|
},
|
||||||
|
Extra {
|
||||||
|
key: "to.uid",
|
||||||
|
value: Int(self.request.target_uid),
|
||||||
|
},
|
||||||
|
Extra {
|
||||||
|
key: "pid",
|
||||||
|
value: Int(self.cred.pid.as_()),
|
||||||
|
},
|
||||||
|
Extra {
|
||||||
|
key: "policy",
|
||||||
|
value: Int(self.settings.policy.repr),
|
||||||
|
},
|
||||||
|
Extra {
|
||||||
|
key: "target",
|
||||||
|
value: Int(self.request.target_pid),
|
||||||
|
},
|
||||||
|
Extra {
|
||||||
|
key: "context",
|
||||||
|
value: Str(&self.request.context),
|
||||||
|
},
|
||||||
|
Extra {
|
||||||
|
key: "gids",
|
||||||
|
value: IntList(&self.request.gids),
|
||||||
|
},
|
||||||
|
Extra {
|
||||||
|
key: "command",
|
||||||
|
value: Str(command),
|
||||||
|
},
|
||||||
|
Extra {
|
||||||
|
key: "notify",
|
||||||
|
value: Bool(self.settings.notify),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
self.exec_cmd("log", &extras, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn connect_app(&mut self) {
|
||||||
|
// If policy is undetermined, show dialog for user consent
|
||||||
|
if self.settings.policy == SuPolicy::Query {
|
||||||
|
self.app_request();
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.settings.log && !self.settings.notify {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if fork_dont_care() != 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify su usage to application
|
||||||
|
if self.settings.log {
|
||||||
|
self.app_log();
|
||||||
|
} else if self.settings.notify {
|
||||||
|
self.app_notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
|
use super::connect::SuAppContext;
|
||||||
|
use super::db::RootSettings;
|
||||||
use crate::UCred;
|
use crate::UCred;
|
||||||
use crate::daemon::{AID_ROOT, AID_SHELL, MagiskD, to_app_id, to_user_id};
|
use crate::daemon::{AID_ROOT, AID_SHELL, MagiskD, to_app_id, to_user_id};
|
||||||
use crate::db::{DbSettings, MultiuserMode, RootAccess};
|
use crate::db::{DbSettings, MultiuserMode, RootAccess};
|
||||||
use crate::ffi::{
|
use crate::ffi::{SuPolicy, SuRequest, exec_root_shell};
|
||||||
SuAppRequest, SuPolicy, SuRequest, app_log, app_notify, app_request, exec_root_shell,
|
|
||||||
};
|
|
||||||
use crate::socket::IpcRead;
|
use crate::socket::IpcRead;
|
||||||
use crate::su::db::RootSettings;
|
|
||||||
use base::{LoggedResult, ResultExt, WriteExt, debug, error, exit_on_error, libc, warn};
|
use base::{LoggedResult, ResultExt, WriteExt, debug, error, exit_on_error, libc, warn};
|
||||||
use std::fs::File;
|
|
||||||
use std::os::fd::{FromRawFd, IntoRawFd};
|
use std::os::fd::{FromRawFd, IntoRawFd};
|
||||||
use std::os::unix::net::UnixStream;
|
use std::os::unix::net::UnixStream;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
@@ -32,11 +30,11 @@ impl Default for SuRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct SuInfo {
|
pub struct SuInfo {
|
||||||
uid: i32,
|
pub(super) uid: i32,
|
||||||
eval_uid: i32,
|
pub(super) eval_uid: i32,
|
||||||
|
pub(super) mgr_pkg: String,
|
||||||
|
pub(super) mgr_uid: i32,
|
||||||
cfg: DbSettings,
|
cfg: DbSettings,
|
||||||
mgr_pkg: String,
|
|
||||||
mgr_uid: i32,
|
|
||||||
access: Mutex<AccessInfo>,
|
access: Mutex<AccessInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,39 +130,18 @@ impl MagiskD {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let info = self.get_su_info(cred.uid as i32);
|
let info = self.get_su_info(cred.uid as i32);
|
||||||
let app_req = SuAppRequest {
|
|
||||||
uid: cred.uid as i32,
|
|
||||||
pid: cred.pid,
|
|
||||||
eval_uid: info.eval_uid,
|
|
||||||
mgr_pkg: &info.mgr_pkg,
|
|
||||||
mgr_uid: info.mgr_uid,
|
|
||||||
request: &req,
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut access = info.access.lock().unwrap();
|
let mut access = info.access.lock().unwrap();
|
||||||
|
|
||||||
if access.settings.policy == SuPolicy::Query {
|
// Talk to su manager
|
||||||
let fd = app_request(&app_req);
|
let mut app = SuAppContext {
|
||||||
if fd < 0 {
|
cred,
|
||||||
access.settings.policy = SuPolicy::Deny;
|
request: &req,
|
||||||
} else {
|
info: &info,
|
||||||
let mut fd = unsafe { File::from_raw_fd(fd) };
|
settings: &mut access.settings,
|
||||||
access.settings.policy = SuPolicy {
|
sdk_int: self.sdk_int(),
|
||||||
repr: fd
|
};
|
||||||
.read_decodable::<i32>()
|
app.connect_app();
|
||||||
.log()
|
|
||||||
.map(i32::from_be)
|
|
||||||
.unwrap_or(SuPolicy::Deny.repr),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if access.settings.log {
|
|
||||||
app_log(&app_req, access.settings.policy, access.settings.notify);
|
|
||||||
} else if access.settings.notify {
|
|
||||||
app_notify(&app_req, access.settings.policy);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Before unlocking, refresh the timestamp
|
// Before unlocking, refresh the timestamp
|
||||||
access.refresh();
|
access.refresh();
|
||||||
@@ -291,9 +268,9 @@ impl MagiskD {
|
|||||||
Arc::new(SuInfo {
|
Arc::new(SuInfo {
|
||||||
uid,
|
uid,
|
||||||
eval_uid,
|
eval_uid,
|
||||||
cfg,
|
|
||||||
mgr_pkg,
|
mgr_pkg,
|
||||||
mgr_uid,
|
mgr_uid,
|
||||||
|
cfg,
|
||||||
access: Mutex::new(AccessInfo::new(access)),
|
access: Mutex::new(AccessInfo::new(access)),
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
mod connect;
|
||||||
mod daemon;
|
mod daemon;
|
||||||
mod db;
|
mod db;
|
||||||
mod pts;
|
mod pts;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::consts::MODULEROOT;
|
use crate::consts::MODULEROOT;
|
||||||
use crate::daemon::{MagiskD, to_user_id};
|
use crate::daemon::{MagiskD, to_user_id};
|
||||||
use crate::ffi::{
|
use crate::ffi::{
|
||||||
ZygiskRequest, ZygiskStateFlags, get_magisk_tmp, restore_zygisk_prop, update_deny_flags,
|
ZygiskRequest, ZygiskStateFlags, get_magisk_tmp, restore_zygisk_prop, set_zygisk_prop, update_deny_flags,
|
||||||
};
|
};
|
||||||
use crate::socket::{IpcRead, UnixSocketExt};
|
use crate::socket::{IpcRead, UnixSocketExt};
|
||||||
use base::libc::{O_CLOEXEC, O_CREAT, O_RDONLY, STDOUT_FILENO};
|
use base::libc::{O_CLOEXEC, O_CREAT, O_RDONLY, STDOUT_FILENO};
|
||||||
@@ -89,6 +89,8 @@ impl MagiskD {
|
|||||||
|
|
||||||
if restore {
|
if restore {
|
||||||
restore_zygisk_prop();
|
restore_zygisk_prop();
|
||||||
|
} else {
|
||||||
|
set_zygisk_prop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -496,7 +496,7 @@ void HookContext::hook_jni_methods(JNIEnv *env, const char *clz, JNIMethods meth
|
|||||||
auto &new_method = new_methods[i];
|
auto &new_method = new_methods[i];
|
||||||
if (new_method.fnPtr == method.fnPtr) {
|
if (new_method.fnPtr == method.fnPtr) {
|
||||||
auto &old_method = old_methods[i];
|
auto &old_method = old_methods[i];
|
||||||
ZLOGD("replace %s#%s%s %p -> %p\n", clz, method.name, method.signature, old_method.fnPtr, method.fnPtr);
|
ZLOGV("replace %s#%s%s %p -> %p\n", clz, method.name, method.signature, old_method.fnPtr, method.fnPtr);
|
||||||
method.fnPtr = old_method.fnPtr;
|
method.fnPtr = old_method.fnPtr;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Extreme verbose logging
|
// Extreme verbose logging
|
||||||
#define ZLOGV(...) ZLOGD(__VA_ARGS__)
|
//#define ZLOGV(...) ZLOGD(__VA_ARGS__)
|
||||||
//#define ZLOGV(...) (void*)0
|
#define ZLOGV(...) (void*)0
|
||||||
|
|
||||||
void hook_entry();
|
void hook_entry();
|
||||||
void hookJniNativeMethods(JNIEnv *env, const char *clz, JNINativeMethod *methods, int numMethods);
|
void hookJniNativeMethods(JNIEnv *env, const char *clz, JNINativeMethod *methods, int numMethods);
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ pub const DATABIN: &str = concatcp!(SECURE_DIR, "/magisk");
|
|||||||
pub const MAGISKDB: &str = concatcp!(SECURE_DIR, "/magisk.db");
|
pub const MAGISKDB: &str = concatcp!(SECURE_DIR, "/magisk.db");
|
||||||
|
|
||||||
// tmpfs paths
|
// tmpfs paths
|
||||||
const INTERNAL_DIR: &str = ".magisk";
|
pub const INTERNAL_DIR: &str = ".magisk";
|
||||||
pub const MAIN_CONFIG: &str = concatcp!(INTERNAL_DIR, "/config");
|
pub const MAIN_CONFIG: &str = concatcp!(INTERNAL_DIR, "/config");
|
||||||
pub const PREINITMIRR: &str = concatcp!(INTERNAL_DIR, "/preinit");
|
pub const PREINITMIRR: &str = concatcp!(INTERNAL_DIR, "/preinit");
|
||||||
pub const MODULEMNT: &str = concatcp!(INTERNAL_DIR, "/modules");
|
pub const MODULEMNT: &str = concatcp!(INTERNAL_DIR, "/modules");
|
||||||
@@ -37,6 +37,7 @@ pub const SEPOL_PROC_DOMAIN: &str = "magisk";
|
|||||||
pub const MAGISK_PROC_CON: &str = concatcp!("u:r:", SEPOL_PROC_DOMAIN, ":s0");
|
pub const MAGISK_PROC_CON: &str = concatcp!("u:r:", SEPOL_PROC_DOMAIN, ":s0");
|
||||||
// Unconstrained file type that anyone can access
|
// Unconstrained file type that anyone can access
|
||||||
pub const SEPOL_FILE_TYPE: &str = "magisk_file";
|
pub const SEPOL_FILE_TYPE: &str = "magisk_file";
|
||||||
|
pub const MAGISK_FILE_CON: &str = concatcp!("u:object_r:", SEPOL_FILE_TYPE, ":s0");
|
||||||
// Log pipe that only root and zygote can open
|
// Log pipe that only root and zygote can open
|
||||||
pub const SEPOL_LOG_TYPE: &str = "magisk_log_file";
|
pub const SEPOL_LOG_TYPE: &str = "magisk_log_file";
|
||||||
pub const MAGISK_LOG_CON: &str = concatcp!("u:object_r:", SEPOL_LOG_TYPE, ":s0");
|
pub const MAGISK_LOG_CON: &str = concatcp!("u:object_r:", SEPOL_LOG_TYPE, ":s0");
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ emu_args=
|
|||||||
emu_pid=
|
emu_pid=
|
||||||
|
|
||||||
atd_min_api=30
|
atd_min_api=30
|
||||||
atd_max_api=35
|
atd_max_api=36
|
||||||
huge_ram_min_api=26
|
huge_ram_min_api=26
|
||||||
|
|
||||||
case $(uname -m) in
|
case $(uname -m) in
|
||||||
@@ -94,7 +94,7 @@ resolve_vars() {
|
|||||||
UpsideDownCakePrivacySandbox) api=34 ;;
|
UpsideDownCakePrivacySandbox) api=34 ;;
|
||||||
VanillaIceCream) api=35 ;;
|
VanillaIceCream) api=35 ;;
|
||||||
Baklava) api=36 ;;
|
Baklava) api=36 ;;
|
||||||
36*CANARY) api=36 ;;
|
36*CANARY) api=10000 ;;
|
||||||
*)
|
*)
|
||||||
print_error "! Unknown system image version '$ver'"
|
print_error "! Unknown system image version '$ver'"
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# AVD MagiskInit Setup
|
# AVD MagiskInit Setup
|
||||||
#####################################################################
|
#####################################################################
|
||||||
#
|
#
|
||||||
# Support API level: 23 - 35
|
# Support API level: 23 - 36
|
||||||
#
|
#
|
||||||
# With an emulator booted and accessible via ADB, usage:
|
# With an emulator booted and accessible via ADB, usage:
|
||||||
# ./build.py avd_patch path/to/booted/avd-image/ramdisk.img
|
# ./build.py avd_patch path/to/booted/avd-image/ramdisk.img
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# AVD Magisk Setup
|
# AVD Magisk Setup
|
||||||
#####################################################################
|
#####################################################################
|
||||||
#
|
#
|
||||||
# Support API level: 23 - 35
|
# Support API level: 23 - 36
|
||||||
#
|
#
|
||||||
# For developing Magisk, just use:
|
# For developing Magisk, just use:
|
||||||
# ./build.py emulator
|
# ./build.py emulator
|
||||||
|
|||||||
Reference in New Issue
Block a user