Migrate prune_su_access to Rust

This commit is contained in:
topjohnwu 2025-01-10 09:04:56 +08:00 committed by John Wu
parent 5637a258fc
commit 4d4195c02d
12 changed files with 104 additions and 88 deletions

View File

@ -20,7 +20,6 @@ LOCAL_SRC_FILES := \
core/daemon.cpp \
core/bootstages.cpp \
core/socket.cpp \
core/package.cpp \
core/scripting.cpp \
core/selinux.cpp \
core/sqlite.cpp \

16
native/src/Cargo.lock generated
View File

@ -70,6 +70,21 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bit-set"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
[[package]]
name = "block-buffer"
version = "0.11.0-rc.3"
@ -442,6 +457,7 @@ name = "magisk"
version = "0.0.0"
dependencies = [
"base",
"bit-set",
"bytemuck",
"cxx",
"cxx-gen",

View File

@ -25,6 +25,7 @@ der = "0.8.0-rc.1"
bytemuck = "1.16"
fdt = "0.1"
const_format = "0.2"
bit-set = "0.8"
[workspace.dependencies.argh]
git = "https://github.com/google/argh.git"

View File

@ -23,3 +23,4 @@ num-derive = { workspace = true }
quick-protobuf = { workspace = true }
bytemuck = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
bit-set = { workspace = true }

View File

@ -144,7 +144,7 @@ static void handle_request_async(int client, int code, const sock_cred &cred) {
break;
case +RequestCode::ZYGOTE_RESTART:
LOGI("** zygote restarted\n");
prune_su_access();
MagiskD().prune_su_access();
scan_deny_apps();
reset_zygisk(false);
close(client);

View File

@ -5,7 +5,11 @@ use crate::get_prop;
use crate::logging::{magisk_logging, start_log_daemon};
use crate::package::ManagerInfo;
use base::libc::{O_CLOEXEC, O_RDONLY};
use base::{cstr, info, libc, open_fd, BufReadExt, FsPath, FsPathBuf, ReadExt, Utf8CStrBufArr};
use base::{
cstr, info, libc, open_fd, BufReadExt, DirEntry, Directory, FsPath, FsPathBuf, LoggedResult,
ReadExt, Utf8CStr, Utf8CStrBufArr,
};
use bit_set::BitSet;
use bytemuck::bytes_of;
use std::fs::File;
use std::io;
@ -37,6 +41,8 @@ impl BootStateFlags {
}
}
pub const AID_APP_START: i32 = 10000;
pub const AID_APP_END: i32 = 19999;
pub const AID_USER_OFFSET: i32 = 100000;
pub const fn to_app_id(uid: i32) -> i32 {
@ -62,14 +68,48 @@ impl MagiskD {
self.sdk_int
}
pub fn app_data_dir(&self) -> &'static str {
pub fn app_data_dir(&self) -> &'static Utf8CStr {
if self.sdk_int >= 24 {
"/data/user_de"
cstr!("/data/user_de")
} else {
"/data/user"
cstr!("/data/user")
}
}
// app_id = app_no + AID_APP_START
// app_no range: [0, 9999]
pub fn get_app_no_list(&self) -> BitSet {
let mut list = BitSet::new();
let _: LoggedResult<()> = try {
let mut dir = Directory::open(self.app_data_dir())?;
// For each user
loop {
let entry: DirEntry;
match dir.read()? {
None => break,
Some(e) => entry = e,
}
if let Ok(mut dir) = entry.open_as_dir() {
// For each package
loop {
match dir.read()? {
None => break,
Some(e) => {
let attr = e.get_attr()?;
let app_id = to_app_id(attr.st.st_uid as i32);
if app_id >= AID_APP_START && app_id <= AID_APP_END {
let app_no = app_id - AID_APP_START;
list.insert(app_no as usize);
}
}
}
}
}
}
};
list
}
pub fn boot_stage_handler(&self, client: i32, code: i32) {
// Make sure boot stage execution is always serialized
let mut state = self.boot_stage_lock.lock().unwrap();

View File

@ -213,7 +213,7 @@ impl MagiskD {
)
}
fn db_exec(&self, sql: &str, args: &[DbArg]) -> i32 {
pub fn db_exec(&self, sql: &str, args: &[DbArg]) -> i32 {
self.db_exec_impl(sql, args, None, ptr::null_mut())
}
@ -308,10 +308,6 @@ impl MagiskD {
self.set_db_setting(key, value).log().is_ok()
}
pub fn rm_db_string_for_cxx(&self, key: DbEntryKey) -> bool {
self.rm_db_string(key).log().is_ok()
}
pub fn db_exec_for_cxx(&self, client_fd: RawFd) {
// Take ownership
let fd = unsafe { OwnedFd::from_raw_fd(client_fd) };

View File

@ -12,8 +12,6 @@
#define AID_ROOT 0
#define AID_SHELL 2000
#define AID_APP_START 10000
#define AID_APP_END 19999
#define AID_USER_OFFSET 100000
#define to_app_id(uid) (uid % AID_USER_OFFSET)
@ -60,10 +58,6 @@ void denylist_handler(int client, const sock_cred *cred);
void su_daemon_handler(int client, const sock_cred *cred);
void zygisk_handler(int client, const sock_cred *cred);
// Package
std::vector<bool> get_app_no_list();
void prune_su_access();
// Module stuffs
void handle_modules();
void load_modules();

View File

@ -181,6 +181,7 @@ pub mod ffi {
fn sdk_int(&self) -> i32;
fn boot_stage_handler(&self, client: i32, code: i32);
fn preserve_stub_apk(&self);
fn prune_su_access(&self);
#[cxx_name = "get_manager"]
unsafe fn get_manager_for_cxx(&self, user: i32, ptr: *mut CxxString, install: bool) -> i32;
@ -189,9 +190,6 @@ pub mod ffi {
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;
fn get_db_string(&self, key: DbEntryKey) -> String;
#[cxx_name = "rm_db_string"]
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"]

View File

@ -1,39 +0,0 @@
#include <base.hpp>
#include <consts.hpp>
#include <core.hpp>
#include <sqlite.hpp>
#include <flags.h>
using namespace std;
// app_id = app_no + AID_APP_START
// app_no range: [0, 9999]
vector<bool> get_app_no_list() {
vector<bool> list;
auto data_dir = xopen_dir(APP_DATA_DIR);
if (!data_dir)
return list;
dirent *entry;
while ((entry = xreaddir(data_dir.get()))) {
// For each user
int dfd = xopenat(dirfd(data_dir.get()), entry->d_name, O_RDONLY);
if (auto dir = xopen_dir(dfd)) {
while ((entry = xreaddir(dir.get()))) {
// For each package
struct stat st{};
xfstatat(dfd, entry->d_name, &st, 0);
int app_id = to_app_id(st.st_uid);
if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
int app_no = app_id - AID_APP_START;
if (list.size() <= app_no) {
list.resize(app_no + 1);
}
list[app_no] = true;
}
}
} else {
close(dfd);
}
}
return list;
}

View File

@ -1,4 +1,4 @@
use crate::daemon::MagiskD;
use crate::daemon::{to_app_id, MagiskD, AID_APP_END, AID_APP_START};
use crate::db::DbArg::Integer;
use crate::db::{SqlTable, SqliteResult, SqliteReturn};
use crate::ffi::{DbValues, RootSettings, SuPolicy};
@ -35,6 +35,14 @@ impl SqlTable for RootSettings {
}
}
struct UidList(Vec<i32>);
impl SqlTable for UidList {
fn on_row(&mut self, _: &[String], values: &DbValues) {
self.0.push(values.get_int(0));
}
}
impl MagiskD {
fn get_root_settings(&self, uid: i32, settings: &mut RootSettings) -> SqliteResult {
self.db_exec_with_rows(
@ -49,6 +57,36 @@ impl MagiskD {
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 prune_su_access(&self) {
let mut list = UidList(Vec::new());
if self
.db_exec_with_rows("SELECT uid FROM policies", &[], &mut list)
.sql_result()
.log()
.is_err()
{
return;
}
let app_list = self.get_app_no_list();
let mut rm_uids = Vec::new();
for uid in list.0 {
let app_id = to_app_id(uid);
if app_id >= AID_APP_START && app_id <= AID_APP_END {
let app_no = app_id - AID_APP_START;
if !app_list.contains(app_no as usize) {
// The app_id is no longer installed
rm_uids.push(uid);
}
}
}
for uid in rm_uids {
self.db_exec("DELETE FROM policies WHERE uid=?", &[Integer(uid as i64)]);
}
}
}
pub fn get_default_root_settings() -> RootSettings {

View File

@ -116,34 +116,6 @@ bool uid_granted_root(int uid) {
return granted;
}
struct policy_uid_list : public vector<int> {
void operator()(StringSlice, const DbValues &values) {
push_back(values.get_int(0));
}
};
void prune_su_access() {
cached.reset();
policy_uid_list uids;
if (!db_exec("SELECT uid FROM policies", {}, uids))
return;
vector<bool> app_no_list = get_app_no_list();
vector<int> rm_uids;
for (int uid : uids) {
int app_id = to_app_id(uid);
if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
int app_no = app_id - AID_APP_START;
if (app_no >= app_no_list.size() || !app_no_list[app_no]) {
// The app_id is no longer installed
rm_uids.push_back(uid);
}
}
}
for (int uid : rm_uids) {
db_exec("DELETE FROM policies WHERE uid=?", { uid });
}
}
static shared_ptr<su_info> get_su_info(unsigned uid) {
if (uid == AID_ROOT) {
auto info = make_shared<su_info>(uid);