diff --git a/native/src/Android.mk b/native/src/Android.mk index e165ca99c..3736e1874 100644 --- a/native/src/Android.mk +++ b/native/src/Android.mk @@ -176,7 +176,8 @@ LOCAL_SRC_FILES := \ sepolicy/sepolicy.cpp \ sepolicy/rules.cpp \ sepolicy/policydb.cpp \ - sepolicy/statement.cpp + sepolicy/statement.cpp \ + sepolicy/policy-rs.cpp include $(BUILD_STATIC_LIBRARY) include src/Android-rs.mk diff --git a/native/src/Cargo.lock b/native/src/Cargo.lock index bbb045280..8350f9769 100644 --- a/native/src/Cargo.lock +++ b/native/src/Cargo.lock @@ -83,7 +83,7 @@ dependencies = [ "codespan-reporting", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -96,7 +96,7 @@ version = "1.0.94" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] @@ -168,9 +168,9 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi", "libc", @@ -179,15 +179,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.142" +version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "linux-raw-sys" -version = "0.3.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64f40e5e03e0d54f03845c8197d0291253cdbedfb1cb46b13c2c117554a9f4c" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "log" @@ -228,13 +228,17 @@ dependencies = [ "base", "cxx", "cxx-gen", + "magiskpolicy", ] [[package]] name = "magiskpolicy" version = "0.0.0" dependencies = [ + "anyhow", "base", + "cxx", + "cxx-gen", ] [[package]] @@ -331,9 +335,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" dependencies = [ "proc-macro2", ] @@ -349,9 +353,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +checksum = "d1a59b5d8e97dee33696bf13c5ba8ab85341c002922fba050069326b9c498974" dependencies = [ "aho-corasick", "memchr", @@ -360,15 +364,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "rustix" -version = "0.37.18" +version = "0.37.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bbfc1d1c7c40c01715f47d71444744a81669ca84e8b63e25a55e169b1f86433" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" dependencies = [ "bitflags", "errno", @@ -391,9 +395,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.15" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" dependencies = [ "proc-macro2", "quote", @@ -439,14 +443,14 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.16", ] [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "unicode-width" diff --git a/native/src/Cargo.toml b/native/src/Cargo.toml index 82a2c6f1b..5c513fce0 100644 --- a/native/src/Cargo.toml +++ b/native/src/Cargo.toml @@ -2,19 +2,23 @@ exclude = ["external"] members = ["base", "boot", "core", "init", "sepolicy"] +[workspace.dependencies] +cxx = { path = "external/cxx-rs" } +cxx-gen = { path = "external/cxx-rs/gen/lib" } +libc = "0.2" +cfg-if = "1.0" +anyhow = "1.0" +num-traits = "0.2" +num-derive = "0.3" + [profile.dev] opt-level = "z" lto = true codegen-units = 1 panic = "abort" -strip = true [profile.release] opt-level = "z" lto = true codegen-units = 1 panic = "abort" -strip = true - -[patch.crates-io] -cxx = { path = "external/cxx-rs" } diff --git a/native/src/base/Cargo.toml b/native/src/base/Cargo.toml index a966c0ae7..d2cfb353e 100644 --- a/native/src/base/Cargo.toml +++ b/native/src/base/Cargo.toml @@ -7,9 +7,9 @@ edition = "2021" path = "lib.rs" [build-dependencies] -cxx-gen = { path = "../external/cxx-rs/gen/lib" } +cxx-gen = { workspace = true } [dependencies] -cxx = { path = "../external/cxx-rs" } -libc = "0.2" -cfg-if = "1.0" +cxx = { workspace = true } +libc = { workspace = true } +cfg-if = { workspace = true } diff --git a/native/src/base/files.rs b/native/src/base/files.rs index 859306781..9308bec80 100644 --- a/native/src/base/files.rs +++ b/native/src/base/files.rs @@ -1,14 +1,12 @@ use std::cmp::min; use std::ffi::CStr; -use std::fs::File; use std::io; use std::io::{BufRead, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, OwnedFd, RawFd}; -use std::path::Path; use libc::{c_char, c_uint, mode_t, EEXIST, ENOENT, O_CLOEXEC, O_PATH}; -use crate::{bfmt_cstr, errno, xopen}; +use crate::{bfmt_cstr, errno, error, xopen}; pub mod unsafe_impl { use std::ffi::CStr; @@ -137,9 +135,43 @@ pub extern "C" fn mkdirs(path: *const c_char, mode: mode_t) -> i32 { } } -pub fn read_lines>(path: P) -> io::Result>> { - let file = File::open(path)?; - Ok(io::BufReader::new(file).lines()) +pub trait BufReadExt { + fn foreach_lines bool>(&mut self, f: F); + fn foreach_props bool>(&mut self, f: F); +} + +impl BufReadExt for T { + fn foreach_lines bool>(&mut self, mut f: F) { + let mut buf = String::new(); + loop { + match self.read_line(&mut buf) { + Ok(0) => break, + Ok(_) => { + if !f(&mut buf) { + break; + } + } + Err(e) => { + error!("{}", e); + break; + } + }; + buf.clear(); + } + } + + fn foreach_props bool>(&mut self, mut f: F) { + self.foreach_lines(|line| { + let line = line.trim(); + if line.starts_with('#') { + return true; + } + if let Some((key, value)) = line.split_once('=') { + return f(key, value); + } + return true; + }); + } } pub trait WriteExt { diff --git a/native/src/boot/Cargo.toml b/native/src/boot/Cargo.toml index bb1b270f7..95140bcc6 100644 --- a/native/src/boot/Cargo.toml +++ b/native/src/boot/Cargo.toml @@ -9,7 +9,7 @@ path = "lib.rs" [build-dependencies] protobuf-codegen = "3.2.0" -cxx-gen = { path = "../external/cxx-rs/gen/lib" } +cxx-gen = { workspace = true } [dependencies] base = { path = "../base" } diff --git a/native/src/core/Cargo.toml b/native/src/core/Cargo.toml index a59f55eb8..f2e2b2fec 100644 --- a/native/src/core/Cargo.toml +++ b/native/src/core/Cargo.toml @@ -8,10 +8,10 @@ crate-type = ["staticlib"] path = "lib.rs" [build-dependencies] -cxx-gen = { path = "../external/cxx-rs/gen/lib" } +cxx-gen = { workspace = true } [dependencies] base = { path = "../base" } -cxx = { path = "../external/cxx-rs" } -num-traits = "0.2" -num-derive = "0.3" +cxx = { workspace = true } +num-traits = { workspace = true } +num-derive = { workspace = true } diff --git a/native/src/init/Cargo.toml b/native/src/init/Cargo.toml index 43282596a..c1b541faa 100644 --- a/native/src/init/Cargo.toml +++ b/native/src/init/Cargo.toml @@ -8,8 +8,9 @@ crate-type = ["staticlib"] path = "lib.rs" [build-dependencies] -cxx-gen = { path = "../external/cxx-rs/gen/lib" } +cxx-gen = { workspace = true } [dependencies] base = { path = "../base" } -cxx = { path = "../external/cxx-rs" } +magiskpolicy = { path = "../sepolicy" } +cxx = { workspace = true } diff --git a/native/src/init/lib.rs b/native/src/init/lib.rs index 6fd10a72c..0e761bc3f 100644 --- a/native/src/init/lib.rs +++ b/native/src/init/lib.rs @@ -1,4 +1,6 @@ pub use logging::*; +// Has to be pub so all symbols in that crate is included +pub use magiskpolicy; mod logging; diff --git a/native/src/sepolicy/Cargo.toml b/native/src/sepolicy/Cargo.toml index e07df6d49..92c20b115 100644 --- a/native/src/sepolicy/Cargo.toml +++ b/native/src/sepolicy/Cargo.toml @@ -7,5 +7,10 @@ edition = "2021" crate-type = ["staticlib", "rlib"] path = "lib.rs" +[build-dependencies] +cxx-gen = { workspace = true } + [dependencies] base = { path = "../base" } +cxx = { workspace = true } +anyhow = { workspace = true } diff --git a/native/src/sepolicy/api.cpp b/native/src/sepolicy/api.cpp index ac44c9922..acaaee053 100644 --- a/native/src/sepolicy/api.cpp +++ b/native/src/sepolicy/api.cpp @@ -103,3 +103,13 @@ bool sepolicy::genfscon(const char *fs_name, const char *path, const char *ctx) bool sepolicy::exists(const char *type) { return hashtab_search(impl->db->p_types.table, type) != nullptr; } + +void sepolicy::load_rule_file(const char *file) { + rust::load_rule_file(*this, rust::Slice( + reinterpret_cast(file), strlen(file))); +} + +void sepolicy::load_rules(const std::string &rules) { + rust::load_rules(*this, rust::Slice( + reinterpret_cast(rules.data()), rules.length())); +} diff --git a/native/src/sepolicy/build.rs b/native/src/sepolicy/build.rs new file mode 100644 index 000000000..34e1f6b12 --- /dev/null +++ b/native/src/sepolicy/build.rs @@ -0,0 +1,8 @@ +use crate::gen::gen_cxx_binding; + +#[path = "../include/gen.rs"] +mod gen; + +fn main() { + gen_cxx_binding("policy-rs"); +} diff --git a/native/src/sepolicy/include/sepolicy.hpp b/native/src/sepolicy/include/sepolicy.hpp index 46c86735a..d0e1b7e4a 100644 --- a/native/src/sepolicy/include/sepolicy.hpp +++ b/native/src/sepolicy/include/sepolicy.hpp @@ -1,9 +1,10 @@ #pragma once #include -#include #include +#include + #define ALL nullptr struct sepolicy { @@ -17,7 +18,8 @@ struct sepolicy { // External APIs bool to_file(c_str file); - void parse_statement(c_str stmt); + void parse_statement(c_str stmt, int len); + void parse_statement(c_str stmt) { parse_statement(stmt, strlen(stmt)); } void load_rules(const std::string &rules); void load_rule_file(c_str file); diff --git a/native/src/sepolicy/lib.rs b/native/src/sepolicy/lib.rs index 8411b1d59..8ac6deaf1 100644 --- a/native/src/sepolicy/lib.rs +++ b/native/src/sepolicy/lib.rs @@ -1 +1,53 @@ +use io::Cursor; +use std::fs::File; +use std::io::{BufRead, BufReader}; +use std::pin::Pin; +use std::{io, str}; + pub use base; +use base::*; + +use crate::ffi::sepolicy; + +#[cxx::bridge] +mod ffi { + unsafe extern "C++" { + include!("include/sepolicy.hpp"); + + type sepolicy; + unsafe fn parse_statement(self: Pin<&mut sepolicy>, stmt: *const c_char, len: i32); + } + + #[namespace = "rust"] + extern "Rust" { + fn load_rules(sepol: Pin<&mut sepolicy>, rules: &[u8]); + fn load_rule_file(sepol: Pin<&mut sepolicy>, filename: &[u8]); + } +} + +fn load_rules_from_reader(mut sepol: Pin<&mut sepolicy>, reader: &mut T) { + reader.foreach_lines(|line| { + let bytes = line.trim().as_bytes(); + unsafe { + sepol + .as_mut() + .parse_statement(bytes.as_ptr().cast(), bytes.len() as i32); + } + true + }); +} + +pub fn load_rule_file(sepol: Pin<&mut sepolicy>, filename: &[u8]) { + fn inner(sepol: Pin<&mut sepolicy>, filename: &[u8]) -> anyhow::Result<()> { + let filename = str::from_utf8(filename)?; + let mut reader = BufReader::new(File::open(filename)?); + load_rules_from_reader(sepol, &mut reader); + Ok(()) + } + inner(sepol, filename).ok_or_log(); +} + +pub fn load_rules(sepol: Pin<&mut sepolicy>, rules: &[u8]) { + let mut cursor = Cursor::new(rules); + load_rules_from_reader(sepol, &mut cursor); +} diff --git a/native/src/sepolicy/policy.hpp b/native/src/sepolicy/policy.hpp index e5836c845..8b9572ed9 100644 --- a/native/src/sepolicy/policy.hpp +++ b/native/src/sepolicy/policy.hpp @@ -5,6 +5,8 @@ #include #include +#include "policy-rs.hpp" + struct sepol_impl : public sepolicy { avtab_ptr_t get_avtab_node(avtab_key_t *key, avtab_extended_perms_t *xperms); bool add_rule(const char *s, const char *t, const char *c, const char *p, int effect, bool invert); diff --git a/native/src/sepolicy/statement.cpp b/native/src/sepolicy/statement.cpp index 4f7e8adab..da035f918 100644 --- a/native/src/sepolicy/statement.cpp +++ b/native/src/sepolicy/statement.cpp @@ -266,22 +266,22 @@ static bool parse_pattern_9(const Func &fn, const char *action, char *stmt) { } #define add_action_func(name, type, fn) \ -else if (strcmp(name, action) == 0) { \ - auto __fn = [=](auto && ...args){ return (fn)(args...); };\ - if (!parse_pattern_##type(__fn, name, remain)) \ - LOGW("Syntax error in '%s'\n\n%s\n", stmt, type_msg_##type); \ +else if (strcmp(name, action) == 0) { \ + auto __fn = [&](auto && ...args){ return (fn)(args...); }; \ + if (!parse_pattern_##type(__fn, name, remain)) \ + LOGW("Syntax error in '%.*s'\n\n%s\n", len, stmt, type_msg_##type); \ } #define add_action(act, type) add_action_func(#act, type, act) -void sepolicy::parse_statement(const char *stmt) { +void sepolicy::parse_statement(const char *stmt, int len) { // strtok modify strings, create a copy - string cpy(stmt); + string cpy(stmt, len); char *remain; char *action = strtok_r(cpy.data(), " ", &remain); if (remain == nullptr) { - LOGW("Syntax error in '%s'\n\n", stmt); + LOGW("Syntax error in '%.*s'\n\n", len, stmt); return; } @@ -310,43 +310,3 @@ void sepolicy::parse_statement(const char *stmt) { else { LOGW("Unknown action: '%s'\n\n", action); } } - -void sepolicy::load_rule_file(const char *file) { - file_readline(true, file, [&](string_view line) -> bool { - if (line.empty() || line[0] == '#') - return true; - parse_statement(line.data()); - return true; - }); -} - -void sepolicy::load_rules(const string &rules) { - struct cookie { - const string &s; - size_t pos; - }; - cookie c{rules, 0}; - FILE *fp = funopen(&c, /* read */ [](void *v, char *buf, int sz) -> int { - auto c = reinterpret_cast(v); - if (c->pos == c->s.length()) - return 0; - size_t end = std::min(c->pos + sz, c->s.length()); - int len = end - c->pos; - memcpy(buf, c->s.data() + c->pos, len); - c->pos = end; - return len; - }, /* write */ [](auto, auto, auto) -> int { - return 0; - }, /* seek */ [](auto, auto, auto) -> fpos_t { - return 0; - }, /* close */ [](auto) -> int { - return 0; - }); - - file_readline(true, fp, [&](string_view line) -> bool { - if (line.empty() || line[0] == '#') - return true; - parse_statement(line.data()); - return true; - }); -}