diff --git a/native/src/core/db.rs b/native/src/core/db.rs index b2fd9e993..af3486430 100644 --- a/native/src/core/db.rs +++ b/native/src/core/db.rs @@ -27,7 +27,7 @@ pub struct SqliteError(i32); pub type SqliteResult = Result<(), SqliteError>; -trait SqliteReturn { +pub trait SqliteReturn { fn sql_result(self) -> SqliteResult; } @@ -41,7 +41,7 @@ impl SqliteReturn for i32 { } } -trait SqlTable { +pub trait SqlTable { fn on_row(&mut self, columns: &[String], values: &DbValues); } @@ -132,7 +132,7 @@ extern "C" { ) -> i32; } -enum DbArg<'a> { +pub enum DbArg<'a> { Text(&'a str), Integer(i64), } @@ -178,7 +178,13 @@ impl MagiskD { } } - fn db_exec_with_output(&self, sql: &str, args: &[DbArg], out: &mut T) -> i32 { + fn db_exec_impl( + &self, + sql: &str, + args: &[DbArg], + exec_callback: SqlExecCallback, + exec_cookie: *mut c_void, + ) -> i32 { let mut bind_callback: SqlBindCallback = None; let mut bind_cookie: *mut c_void = ptr::null_mut(); let mut db_args = DbArgs { args, curr: 0 }; @@ -186,32 +192,29 @@ impl MagiskD { bind_callback = Some(bind_arguments); bind_cookie = (&mut db_args) as *mut DbArgs as *mut c_void; } - let out_ptr: *mut T = out; - self.with_db(|db| unsafe { sql_exec_impl( db, sql, bind_callback, bind_cookie, - Some(read_db_row::), - out_ptr.cast(), + exec_callback, + exec_cookie, ) }) } - fn db_exec(&self, sql: &str, args: &[DbArg]) -> i32 { - let mut bind_callback: SqlBindCallback = None; - let mut bind_cookie: *mut c_void = ptr::null_mut(); - let mut db_args = DbArgs { args, curr: 0 }; - if !args.is_empty() { - bind_callback = Some(bind_arguments); - bind_cookie = (&mut db_args) as *mut DbArgs as *mut c_void; - } + pub fn db_exec_with_rows(&self, sql: &str, args: &[DbArg], out: &mut T) -> i32 { + self.db_exec_impl( + sql, + args, + Some(read_db_row::), + out as *mut T as *mut c_void, + ) + } - self.with_db(|db| unsafe { - sql_exec_impl(db, sql, bind_callback, bind_cookie, None, ptr::null_mut()) - }) + fn db_exec(&self, sql: &str, args: &[DbArg]) -> i32 { + self.db_exec_impl(sql, args, None, ptr::null_mut()) } pub fn set_db_setting(&self, key: DbEntryKey, value: i32) -> SqliteResult { @@ -236,7 +239,7 @@ impl MagiskD { let mut func = |_: &[String], values: &DbValues| { val = values.get_int(0); }; - self.db_exec_with_output( + self.db_exec_with_rows( "SELECT value FROM settings WHERE key=?", &[Text(key.to_str())], &mut func, @@ -249,7 +252,7 @@ impl MagiskD { pub fn get_db_settings(&self, cfg: &mut DbSettings) -> SqliteResult { cfg.zygisk = self.is_emulator(); - self.db_exec_with_output("SELECT * FROM settings", &[], cfg) + self.db_exec_with_rows("SELECT * FROM settings", &[], cfg) .sql_result() } @@ -258,7 +261,7 @@ impl MagiskD { let mut func = |_: &[String], values: &DbValues| { val.push_str(values.get_text(0)); }; - self.db_exec_with_output( + self.db_exec_with_rows( "SELECT value FROM strings WHERE key=?", &[Text(key.to_str())], &mut func, @@ -291,7 +294,7 @@ impl MagiskD { } writer.ipc_write_string(&out).log().ok(); }; - self.db_exec_with_output(&sql, &[], &mut output_fn); + self.db_exec_with_rows(&sql, &[], &mut output_fn); writer.ipc_write_string("").log() } } diff --git a/native/src/core/lib.rs b/native/src/core/lib.rs index 2a45dbcba..a0b76f19b 100644 --- a/native/src/core/lib.rs +++ b/native/src/core/lib.rs @@ -13,6 +13,7 @@ use logging::{ }; use mount::{clean_mounts, find_preinit_device, revert_unmount, setup_mounts}; use resetprop::{persist_delete_prop, persist_get_prop, persist_get_props, persist_set_prop}; +use su::get_default_root_settings; mod cert; #[path = "../include/consts.rs"] @@ -22,6 +23,7 @@ mod db; mod logging; mod mount; mod resetprop; +mod su; #[cxx::bridge] pub mod ffi { @@ -121,6 +123,19 @@ pub mod ffi { zygisk: bool, } + #[repr(i32)] + enum SuPolicy { + Query, + Deny, + Allow, + } + + struct RootSettings { + policy: SuPolicy, + log: bool, + notify: bool, + } + unsafe extern "C++" { include!("include/sqlite.hpp"); @@ -165,12 +180,12 @@ pub mod ffi { // FFI for MagiskD extern "Rust" { type MagiskD; - fn setup_logfile(self: &MagiskD); - fn is_recovery(self: &MagiskD) -> bool; - fn boot_stage_handler(self: &MagiskD, client: i32, code: i32); + fn setup_logfile(&self); + fn is_recovery(&self) -> bool; + fn boot_stage_handler(&self, client: i32, code: i32); #[cxx_name = "get_db_settings"] - fn get_db_settings_for_cxx(self: &MagiskD, cfg: &mut DbSettings) -> bool; + fn get_db_settings_for_cxx(&self, cfg: &mut DbSettings) -> bool; fn get_db_setting(&self, key: DbEntryKey) -> i32; #[cxx_name = "set_db_setting"] fn set_db_setting_for_cxx(&self, key: DbEntryKey, value: i32) -> bool; @@ -179,9 +194,13 @@ pub mod ffi { fn rm_db_string_for_cxx(&self, key: DbEntryKey) -> bool; #[cxx_name = "db_exec"] fn db_exec_for_cxx(&self, client_fd: i32); + #[cxx_name = "get_root_settings"] + fn get_root_settings_for_cxx(&self, uid: i32, settings: &mut RootSettings) -> bool; + #[cxx_name = "DbSettings"] fn get_default_db_settings() -> DbSettings; - + #[cxx_name = "RootSettings"] + fn get_default_root_settings() -> RootSettings; #[cxx_name = "MagiskD"] fn get_magiskd() -> &'static MagiskD; } diff --git a/native/src/core/su/connect.cpp b/native/src/core/su/connect.cpp index 2466a4cc1..1b5eb7974 100644 --- a/native/src/core/su/connect.cpp +++ b/native/src/core/su/connect.cpp @@ -175,7 +175,7 @@ void app_log(const su_context &ctx) { extras.emplace_back("from.uid", ctx.info->uid); extras.emplace_back("to.uid", static_cast(ctx.req.uid)); extras.emplace_back("pid", ctx.pid); - extras.emplace_back("policy", ctx.info->access.policy); + extras.emplace_back("policy", +ctx.info->access.policy); extras.emplace_back("target", ctx.req.target); extras.emplace_back("context", ctx.req.context.data()); extras.emplace_back("gids", &ctx.req.gids); @@ -193,7 +193,7 @@ void app_notify(const su_context &ctx) { extras.reserve(3); extras.emplace_back("from.uid", ctx.info->uid); extras.emplace_back("pid", ctx.pid); - extras.emplace_back("policy", ctx.info->access.policy); + extras.emplace_back("policy", +ctx.info->access.policy); exec_cmd("notify", extras, ctx.info); exit(0); diff --git a/native/src/core/su/mod.rs b/native/src/core/su/mod.rs new file mode 100644 index 000000000..e4acc1e83 --- /dev/null +++ b/native/src/core/su/mod.rs @@ -0,0 +1,60 @@ +use crate::daemon::MagiskD; +use crate::db::DbArg::Integer; +use crate::db::{SqlTable, SqliteResult, SqliteReturn}; +use crate::ffi::{DbValues, RootSettings, SuPolicy}; +use base::{libc, ResultExt}; +use std::ptr; + +impl Default for SuPolicy { + fn default() -> Self { + SuPolicy::Query + } +} + +impl Default for RootSettings { + fn default() -> Self { + RootSettings { + policy: Default::default(), + log: true, + notify: true, + } + } +} + +impl SqlTable for RootSettings { + fn on_row(&mut self, columns: &[String], values: &DbValues) { + for (i, column) in columns.iter().enumerate() { + let val = values.get_int(i as i32); + if column == "policy" { + self.policy.repr = val; + } else if column == "logging" { + self.log = val != 0; + } else if column == "notify" { + self.notify = val != 0; + } + } + } +} + +impl MagiskD { + fn get_root_settings(&self, uid: i32, settings: &mut RootSettings) -> SqliteResult { + self.db_exec_with_rows( + "SELECT policy, logging, notification FROM policies \ + WHERE uid=? AND (until=0 OR until>?)", + &[ + Integer(uid as i64), + Integer(unsafe { libc::time(ptr::null_mut()).into() }), + ], + settings, + ) + .sql_result() + } + + pub fn get_root_settings_for_cxx(&self, uid: i32, settings: &mut RootSettings) -> bool { + self.get_root_settings(uid, settings).log().is_ok() + } +} + +pub fn get_default_root_settings() -> RootSettings { + RootSettings::default() +} diff --git a/native/src/core/su/su.hpp b/native/src/core/su/su.hpp index 28db2e747..b4cbccd19 100644 --- a/native/src/core/su/su.hpp +++ b/native/src/core/su/su.hpp @@ -14,31 +14,8 @@ #define ATTY_OUT (1 << 1) #define ATTY_ERR (1 << 2) -typedef enum { - QUERY = 0, - DENY = 1, - ALLOW = 2, -} policy_t; - -struct su_access { - policy_t policy; - int log; - int notify; - - su_access() : policy(QUERY), log(1), notify(1) {} - - void operator()(StringSlice columns, const DbValues &data); - void silent_deny() { - policy = DENY; - log = 0; - notify = 0; - } - void silent_allow() { - policy = ALLOW; - log = 0; - notify = 0; - } -}; +#define SILENT_ALLOW { SuPolicy::Allow, false, false } +#define SILENT_DENY { SuPolicy::Deny, false, false } class su_info { public: @@ -48,7 +25,7 @@ public: // These should be guarded with internal lock int eval_uid; // The effective UID, taking multiuser settings into consideration struct DbSettings cfg; - su_access access; + struct RootSettings access; std::string mgr_pkg; int mgr_uid; void check_db(); diff --git a/native/src/core/su/su_daemon.cpp b/native/src/core/su/su_daemon.cpp index 15bfc334c..eac41997d 100644 --- a/native/src/core/su/su_daemon.cpp +++ b/native/src/core/su/su_daemon.cpp @@ -18,7 +18,7 @@ static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER; static shared_ptr cached; su_info::su_info(int uid) : -uid(uid), eval_uid(-1), cfg(DbSettings()), +uid(uid), eval_uid(-1), cfg(DbSettings()), access(RootSettings()), mgr_uid(-1), timestamp(0), _lock(PTHREAD_MUTEX_INITIALIZER) {} su_info::~su_info() { @@ -42,20 +42,6 @@ void su_info::refresh() { timestamp = ts.tv_sec * 1000L + ts.tv_nsec / 1000000L; } -void su_access::operator()(StringSlice columns, const DbValues &data) { - for (int i = 0; i < columns.size(); ++i) { - const auto &name = columns[i]; - if (name == "policy") { - policy = (policy_t) data.get_int(i); - } else if (name == "logging") { - log = data.get_int(i); - } else if (name == "notification") { - notify = data.get_int(i); - } - } - LOGD("magiskdb: query policy=[%d] log=[%d] notify=[%d]\n", policy, log, notify); -} - void su_info::check_db() { eval_uid = uid; MagiskD().get_db_settings(cfg); @@ -65,7 +51,7 @@ void su_info::check_db() { case MultiuserMode::OwnerOnly: if (to_user_id(uid) != 0) { eval_uid = -1; - access.silent_deny(); + access = SILENT_DENY; } break; case MultiuserMode::OwnerManaged: @@ -77,15 +63,12 @@ void su_info::check_db() { } if (eval_uid > 0) { - bool res = db_exec( - "SELECT policy, logging, notification FROM policies " - "WHERE uid=? AND (until=0 OR until>?)", { eval_uid, time(nullptr) }, access); - if (!res) + if (!MagiskD().get_root_settings(eval_uid, access)) return; } // We need to check our manager - if (access.policy == QUERY || access.log || access.notify) { + if (access.policy == SuPolicy::Query || access.log || access.notify) { mgr_uid = get_manager(to_user_id(eval_uid), &mgr_pkg, true); } } @@ -130,7 +113,7 @@ bool uid_granted_root(int uid) { bool granted = false; db_exec("SELECT policy FROM policies WHERE uid=? AND (until=0 OR until>?)", { uid, time(nullptr) }, - [&](auto, const DbValues &values) { granted = values.get_int(0) == ALLOW; }); + [&](auto, const DbValues &values) { granted = values.get_int(0) == +SuPolicy::Allow; }); return granted; } @@ -167,7 +150,7 @@ void prune_su_access() { static shared_ptr get_su_info(unsigned uid) { if (uid == AID_ROOT) { auto info = make_shared(uid); - info->access.silent_allow(); + info->access = SILENT_ALLOW; return info; } @@ -182,13 +165,13 @@ static shared_ptr get_su_info(unsigned uid) { mutex_guard lock = info->lock(); - if (info->access.policy == QUERY) { + if (info->access.policy == SuPolicy::Query) { // Not cached, get data from database info->check_db(); // If it's the manager, allow it silently if (to_app_id(info->uid) == to_app_id(info->mgr_uid)) { - info->access.silent_allow(); + info->access = SILENT_ALLOW; return info; } @@ -196,18 +179,18 @@ static shared_ptr get_su_info(unsigned uid) { switch (info->cfg.root_access) { case RootAccess::Disabled: LOGW("Root access is disabled!\n"); - info->access.silent_deny(); + info->access = SILENT_DENY; break; case RootAccess::AdbOnly: if (info->uid != AID_SHELL) { LOGW("Root access limited to ADB only!\n"); - info->access.silent_deny(); + info->access = SILENT_DENY; } break; case RootAccess::AppsOnly: if (info->uid == AID_SHELL) { LOGW("Root access is disabled for ADB!\n"); - info->access.silent_deny(); + info->access = SILENT_DENY; } break; case RootAccess::AppsAndAdb: @@ -215,12 +198,12 @@ static shared_ptr get_su_info(unsigned uid) { break; } - if (info->access.policy != QUERY) + if (info->access.policy != SuPolicy::Query) return info; // If still not determined, check if manager exists if (info->mgr_uid < 0) { - info->access.silent_deny(); + info->access = SILENT_DENY; return info; } } @@ -266,19 +249,19 @@ void su_daemon_handler(int client, const sock_cred *cred) { || !read_vector(client, ctx.req.gids)) { LOGW("su: remote process probably died, abort\n"); ctx.info.reset(); - write_int(client, DENY); + write_int(client, +SuPolicy::Deny); close(client); return; } // If still not determined, ask manager - if (ctx.info->access.policy == QUERY) { + if (ctx.info->access.policy == SuPolicy::Query) { int fd = app_request(ctx); if (fd < 0) { - ctx.info->access.policy = DENY; + ctx.info->access.policy = SuPolicy::Deny; } else { int ret = read_int_be(fd); - ctx.info->access.policy = ret < 0 ? DENY : static_cast(ret); + ctx.info->access.policy = ret < 0 ? SuPolicy::Deny : static_cast(ret); close(fd); } } @@ -289,10 +272,10 @@ void su_daemon_handler(int client, const sock_cred *cred) { app_notify(ctx); // Fail fast - if (ctx.info->access.policy == DENY) { + if (ctx.info->access.policy == SuPolicy::Deny) { LOGW("su: request rejected (%u)\n", ctx.info->uid); ctx.info.reset(); - write_int(client, DENY); + write_int(client, +SuPolicy::Deny); close(client); return; }