Create custom cxx binding to Utf8CStr

This commit is contained in:
topjohnwu 2023-12-26 23:08:06 +08:00
parent 062e498bdd
commit 65207f96c8
18 changed files with 142 additions and 68 deletions

View File

@ -6,10 +6,12 @@ use std::path::Path;
use std::str::{Utf8Chunks, Utf8Error}; use std::str::{Utf8Chunks, Utf8Error};
use std::{fmt, mem, slice, str}; use std::{fmt, mem, slice, str};
use crate::slice_from_ptr_mut; use cxx::{type_id, ExternType};
use libc::c_char; use libc::c_char;
use thiserror::Error; use thiserror::Error;
use crate::slice_from_ptr_mut;
// Utf8CStr types are UTF-8 validated and null terminated strings. // Utf8CStr types are UTF-8 validated and null terminated strings.
// //
// Several Utf8CStr types: // Several Utf8CStr types:
@ -380,6 +382,22 @@ impl DerefMut for Utf8CStr {
} }
} }
// Notice that we only implement ExternType on Utf8CStr *reference*
unsafe impl ExternType for &Utf8CStr {
type Id = type_id!("rust::Utf8CStr");
type Kind = cxx::kind::Trivial;
}
macro_rules! const_assert_eq {
($left:expr, $right:expr $(,)?) => {
const _: [(); $left] = [(); $right];
};
}
// Assert ABI layout
const_assert_eq!(mem::size_of::<&Utf8CStr>(), mem::size_of::<[usize; 2]>());
const_assert_eq!(mem::align_of::<&Utf8CStr>(), mem::align_of::<[usize; 2]>());
// File system path extensions types // File system path extensions types
#[repr(transparent)] #[repr(transparent)]

View File

@ -10,7 +10,8 @@ use libc::mode_t;
use crate::logging::CxxResultExt; use crate::logging::CxxResultExt;
pub(crate) use crate::xwrap::*; pub(crate) use crate::xwrap::*;
use crate::{ use crate::{
clone_attr, fclone_attr, fd_path, map_fd, map_file, Directory, FsPath, Utf8CStr, Utf8CStrBufRef, clone_attr, cstr, fclone_attr, fd_path, map_fd, map_file, slice_from_ptr, Directory, FsPath,
Utf8CStr, Utf8CStrBufRef,
}; };
pub(crate) fn fd_path_for_cxx(fd: RawFd, buf: &mut [u8]) -> isize { pub(crate) fn fd_path_for_cxx(fd: RawFd, buf: &mut [u8]) -> isize {
@ -57,12 +58,8 @@ unsafe extern "C" fn frm_rf(fd: OwnedFd) -> bool {
inner(fd).is_ok() inner(fd).is_ok()
} }
pub(crate) fn map_file_for_cxx(path: &[u8], rw: bool) -> &'static mut [u8] { pub(crate) fn map_file_for_cxx(path: &Utf8CStr, rw: bool) -> &'static mut [u8] {
unsafe { map_file(path, rw).log_cxx().unwrap_or(&mut [])
map_file(Utf8CStr::from_bytes_unchecked(path), rw)
.log_cxx()
.unwrap_or(&mut [])
}
} }
pub(crate) fn map_fd_for_cxx(fd: RawFd, sz: usize, rw: bool) -> &'static mut [u8] { pub(crate) fn map_fd_for_cxx(fd: RawFd, sz: usize, rw: bool) -> &'static mut [u8] {
@ -171,3 +168,18 @@ unsafe extern "C" fn fclone_attr_for_cxx(a: RawFd, b: RawFd) -> bool {
.log_cxx_with_msg(|w| w.write_str("fclone_attr failed")) .log_cxx_with_msg(|w| w.write_str("fclone_attr failed"))
.is_ok() .is_ok()
} }
#[export_name = "cxx$utf8str$new"]
unsafe extern "C" fn str_new(this: &mut &Utf8CStr, s: *const u8, len: usize) {
*this = Utf8CStr::from_bytes(slice_from_ptr(s, len)).unwrap_or(cstr!(""));
}
#[export_name = "cxx$utf8str$ptr"]
unsafe extern "C" fn str_ptr(this: &&Utf8CStr) -> *const u8 {
this.as_ptr().cast()
}
#[export_name = "cxx$utf8str$len"]
unsafe extern "C" fn str_len(this: &&Utf8CStr) -> usize {
this.len()
}

View File

@ -189,7 +189,7 @@ sFILE make_file(FILE *fp) {
} }
mmap_data::mmap_data(const char *name, bool rw) { mmap_data::mmap_data(const char *name, bool rw) {
auto slice = rust::map_file(byte_view(name), rw); auto slice = rust::map_file(name, rw);
if (!slice.empty()) { if (!slice.empty()) {
_buf = slice.data(); _buf = slice.data();
_sz = slice.size(); _sz = slice.size();

View File

@ -34,12 +34,17 @@ pub mod ffi {
unsafe extern "C++" { unsafe extern "C++" {
include!("misc.hpp"); include!("misc.hpp");
#[namespace = "rust"]
#[cxx_name = "Utf8CStr"]
type Utf8CStrRef<'a> = &'a crate::cstr::Utf8CStr;
fn mut_u8_patch(buf: &mut [u8], from: &[u8], to: &[u8]) -> Vec<usize>; fn mut_u8_patch(buf: &mut [u8], from: &[u8], to: &[u8]) -> Vec<usize>;
} }
extern "Rust" { extern "Rust" {
#[cxx_name = "log_with_rs"] #[cxx_name = "log_with_rs"]
fn log_from_cxx(level: LogLevelCxx, msg: &[u8]); fn log_from_cxx(level: LogLevelCxx, msg: Utf8CStrRef);
#[cxx_name = "set_log_level_state"] #[cxx_name = "set_log_level_state"]
fn set_log_level_state_cxx(level: LogLevelCxx, enabled: bool); fn set_log_level_state_cxx(level: LogLevelCxx, enabled: bool);
fn exit_on_error(b: bool); fn exit_on_error(b: bool);
@ -53,7 +58,7 @@ pub mod ffi {
#[cxx_name = "fd_path"] #[cxx_name = "fd_path"]
fn fd_path_for_cxx(fd: i32, buf: &mut [u8]) -> isize; fn fd_path_for_cxx(fd: i32, buf: &mut [u8]) -> isize;
#[cxx_name = "map_file"] #[cxx_name = "map_file"]
fn map_file_for_cxx(path: &[u8], rw: bool) -> &'static mut [u8]; fn map_file_for_cxx(path: Utf8CStrRef, rw: bool) -> &'static mut [u8];
#[cxx_name = "map_fd"] #[cxx_name = "map_fd"]
fn map_fd_for_cxx(fd: i32, sz: usize, rw: bool) -> &'static mut [u8]; fn map_fd_for_cxx(fd: i32, sz: usize, rw: bool) -> &'static mut [u8];
} }

View File

@ -15,7 +15,7 @@ static int fmt_and_log_with_rs(LogLevel level, const char *fmt, va_list ap) {
buf[0] = '\0'; buf[0] = '\0';
// Fortify logs when a fatal error occurs. Do not run through fortify again // Fortify logs when a fatal error occurs. Do not run through fortify again
int len = std::min(__call_bypassing_fortify(vsnprintf)(buf, sz, fmt, ap), sz - 1); int len = std::min(__call_bypassing_fortify(vsnprintf)(buf, sz, fmt, ap), sz - 1);
log_with_rs(level, byte_view(buf, len + 1)); log_with_rs(level, rust::Utf8CStr(buf, len + 1));
return len; return len;
} }

View File

@ -101,10 +101,8 @@ fn log_with_writer<F: FnOnce(LogWriter)>(level: LogLevel, f: F) {
} }
} }
pub fn log_from_cxx(level: LogLevelCxx, msg: &[u8]) { pub fn log_from_cxx(level: LogLevelCxx, msg: &Utf8CStr) {
if let Some(level) = LogLevel::from_i32(level.repr) { if let Some(level) = LogLevel::from_i32(level.repr) {
// SAFETY: The null termination is handled on the C++ side
let msg = unsafe { Utf8CStr::from_bytes_unchecked(msg) };
log_with_writer(level, |write| write(level, msg)); log_with_writer(level, |write| write(level, msg));
} }
} }

View File

@ -274,3 +274,19 @@ int ssprintf(char *dest, size_t size, const char *fmt, ...) {
size_t strscpy(char *dest, const char *src, size_t size) { size_t strscpy(char *dest, const char *src, size_t size) {
return std::min(strlcpy(dest, src, size), size - 1); return std::min(strlcpy(dest, src, size), size - 1);
} }
extern "C" void cxx$utf8str$new(rust::Utf8CStr *self, const void *s, size_t len);
extern "C" const char *cxx$utf8str$ptr(const rust::Utf8CStr *self);
extern "C" size_t cxx$utf8str$len(const rust::Utf8CStr *self);
rust::Utf8CStr::Utf8CStr(const char *s, size_t len) {
cxx$utf8str$new(this, s, len);
}
const char *rust::Utf8CStr::data() const {
return cxx$utf8str$ptr(this);
}
size_t rust::Utf8CStr::length() const {
return cxx$utf8str$len(this);
}

View File

@ -331,3 +331,30 @@ constexpr auto operator+(T e) noexcept ->
std::enable_if_t<std::is_enum<T>::value, std::underlying_type_t<T>> { std::enable_if_t<std::is_enum<T>::value, std::underlying_type_t<T>> {
return static_cast<std::underlying_type_t<T>>(e); return static_cast<std::underlying_type_t<T>>(e);
} }
namespace rust {
struct Utf8CStr {
const char *data() const;
size_t length() const;
Utf8CStr(const char *s, size_t len);
Utf8CStr() : Utf8CStr("", 1) {};
Utf8CStr(const Utf8CStr &o) = default;
Utf8CStr(Utf8CStr &&o) = default;
Utf8CStr(const char *s) : Utf8CStr(s, strlen(s) + 1) {};
Utf8CStr(std::string_view s) : Utf8CStr(s.data(), s.length() + 1) {};
Utf8CStr(std::string s) : Utf8CStr(s.data(), s.length() + 1) {};
const char *c_str() const { return this->data(); }
size_t size() const { return this->length(); }
bool empty() const { return this->length() == 0 ; }
operator std::string_view() { return {data(), length()}; }
private:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-private-field"
std::array<std::uintptr_t, 2> repr;
#pragma clang diagnostic pop
};
} // namespace rust

View File

@ -9,7 +9,7 @@ use base::{
Utf8CStrBufArr, Utf8CStrBufRef, WalkResult, Utf8CStrBufArr, Utf8CStrBufRef, WalkResult,
}; };
use crate::ffi::{CxxMagiskD, RequestCode}; use crate::ffi::{get_magisk_tmp, CxxMagiskD, RequestCode};
use crate::logging::magisk_logging; use crate::logging::magisk_logging;
use crate::{get_prop, MAIN_CONFIG}; use crate::{get_prop, MAIN_CONFIG};
@ -97,10 +97,6 @@ impl MagiskD {
} }
} }
pub fn get_magisk_tmp() -> &'static Utf8CStr {
unsafe { Utf8CStr::from_ptr(super::ffi::get_magisk_tmp()).unwrap_unchecked() }
}
pub fn daemon_entry() { pub fn daemon_entry() {
let mut qemu = get_prop(cstr!("ro.kernel.qemu"), false); let mut qemu = get_prop(cstr!("ro.kernel.qemu"), false);
if qemu.is_empty() { if qemu.is_empty() {
@ -170,13 +166,9 @@ pub fn get_magiskd() -> &'static MagiskD {
unsafe { MAGISKD.get().unwrap_unchecked() } unsafe { MAGISKD.get().unwrap_unchecked() }
} }
pub fn find_apk_path(pkg: &[u8], data: &mut [u8]) -> usize { pub fn find_apk_path(pkg: &Utf8CStr, data: &mut [u8]) -> usize {
use WalkResult::*; use WalkResult::*;
fn inner(pkg: &[u8], buf: &mut dyn Utf8CStrBuf) -> io::Result<usize> { fn inner(pkg: &Utf8CStr, buf: &mut dyn Utf8CStrBuf) -> io::Result<usize> {
let pkg = match Utf8CStr::from_bytes(pkg) {
Ok(pkg) => pkg,
Err(e) => return Err(io::Error::new(io::ErrorKind::Other, e)),
};
Directory::open(cstr!("/data/app"))?.pre_order_walk(|e| { Directory::open(cstr!("/data/app"))?.pre_order_walk(|e| {
if !e.is_dir() { if !e.is_dir() {
return Ok(Skip); return Ok(Skip);

View File

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <base.hpp>
namespace rust { namespace rust {
struct MagiskD; struct MagiskD;
} }
@ -24,3 +26,4 @@ private:
}; };
const char *get_magisk_tmp(); const char *get_magisk_tmp();
static inline rust::Utf8CStr get_magisk_tmp_rs() { return get_magisk_tmp(); }

View File

@ -58,9 +58,14 @@ pub mod ffi {
} }
unsafe extern "C++" { unsafe extern "C++" {
#[namespace = "rust"]
#[cxx_name = "Utf8CStr"]
type Utf8CStrRef<'a> = base::ffi::Utf8CStrRef<'a>;
include!("include/daemon.hpp"); include!("include/daemon.hpp");
fn get_magisk_tmp() -> *const c_char; #[cxx_name = "get_magisk_tmp_rs"]
fn get_magisk_tmp() -> Utf8CStrRef<'static>;
#[cxx_name = "MagiskD"] #[cxx_name = "MagiskD"]
type CxxMagiskD; type CxxMagiskD;
@ -76,12 +81,12 @@ pub mod ffi {
fn zygisk_logging(); fn zygisk_logging();
fn zygisk_close_logd(); fn zygisk_close_logd();
fn zygisk_get_logd() -> i32; fn zygisk_get_logd() -> i32;
fn find_apk_path(pkg: &[u8], data: &mut [u8]) -> usize; fn find_apk_path(pkg: Utf8CStrRef, data: &mut [u8]) -> usize;
fn read_certificate(fd: i32, version: i32) -> Vec<u8>; fn read_certificate(fd: i32, version: i32) -> Vec<u8>;
unsafe fn persist_get_prop(name: *const c_char, prop_cb: Pin<&mut PropCb>); unsafe fn persist_get_prop(name: Utf8CStrRef, prop_cb: Pin<&mut PropCb>);
unsafe fn persist_get_props(prop_cb: Pin<&mut PropCb>); unsafe fn persist_get_props(prop_cb: Pin<&mut PropCb>);
unsafe fn persist_delete_prop(name: *const c_char) -> bool; unsafe fn persist_delete_prop(name: Utf8CStrRef) -> bool;
unsafe fn persist_set_prop(name: *const c_char, value: *const c_char) -> bool; unsafe fn persist_set_prop(name: Utf8CStrRef, value: Utf8CStrRef) -> bool;
} }
#[namespace = "rust"] #[namespace = "rust"]

View File

@ -19,7 +19,8 @@ use base::libc::{
}; };
use base::*; use base::*;
use crate::daemon::{get_magisk_tmp, MagiskD, MAGISKD}; use crate::daemon::{MagiskD, MAGISKD};
use crate::ffi::get_magisk_tmp;
use crate::logging::LogFile::{Actual, Buffer}; use crate::logging::LogFile::{Actual, Buffer};
use crate::{LOGFILE, LOG_PIPE}; use crate::{LOGFILE, LOG_PIPE};

View File

@ -176,7 +176,7 @@ int get_manager(int user_id, string *pkg, bool install) {
int app_id = to_app_id(st.st_uid); int app_id = to_app_id(st.st_uid);
byte_array<PATH_MAX> apk; byte_array<PATH_MAX> apk;
find_apk_path(byte_view(str[SU_MANAGER]), apk); find_apk_path(str[SU_MANAGER], apk);
int fd = xopen((const char *) apk.buf(), O_RDONLY | O_CLOEXEC); int fd = xopen((const char *) apk.buf(), O_RDONLY | O_CLOEXEC);
auto cert = read_certificate(fd, -1); auto cert = read_certificate(fd, -1);
close(fd); close(fd);
@ -230,7 +230,7 @@ int get_manager(int user_id, string *pkg, bool install) {
if (stat(app_path, &st) == 0) { if (stat(app_path, &st) == 0) {
#if ENFORCE_SIGNATURE #if ENFORCE_SIGNATURE
byte_array<PATH_MAX> apk; byte_array<PATH_MAX> apk;
find_apk_path(byte_view(JAVA_PACKAGE_NAME), apk); find_apk_path(JAVA_PACKAGE_NAME, apk);
int fd = xopen((const char *) apk.buf(), O_RDONLY | O_CLOEXEC); int fd = xopen((const char *) apk.buf(), O_RDONLY | O_CLOEXEC);
auto cert = read_certificate(fd, MAGISK_VER_CODE); auto cert = read_certificate(fd, MAGISK_VER_CODE);
close(fd); close(fd);

View File

@ -1,4 +1,3 @@
use core::ffi::c_char;
use std::io::Read; use std::io::Read;
use std::{ use std::{
fs::File, fs::File,
@ -142,9 +141,8 @@ fn proto_write_props(props: &PersistentProperties) -> LoggedResult<()> {
Ok(()) Ok(())
} }
pub unsafe fn persist_get_prop(name: *const c_char, prop_cb: Pin<&mut PropCb>) { pub unsafe fn persist_get_prop(name: &Utf8CStr, prop_cb: Pin<&mut PropCb>) {
fn inner(name: *const c_char, mut prop_cb: Pin<&mut PropCb>) -> LoggedResult<()> { fn inner(name: &Utf8CStr, mut prop_cb: Pin<&mut PropCb>) -> LoggedResult<()> {
let name = unsafe { Utf8CStr::from_ptr(name)? };
if check_proto() { if check_proto() {
let mut props = proto_read_props()?; let mut props = proto_read_props()?;
let prop = props.find(name)?; let prop = props.find(name)?;
@ -197,9 +195,8 @@ pub unsafe fn persist_get_props(prop_cb: Pin<&mut PropCb>) {
inner(prop_cb).ok(); inner(prop_cb).ok();
} }
pub unsafe fn persist_delete_prop(name: *const c_char) -> bool { pub unsafe fn persist_delete_prop(name: &Utf8CStr) -> bool {
fn inner(name: *const c_char) -> LoggedResult<()> { fn inner(name: &Utf8CStr) -> LoggedResult<()> {
let name = unsafe { Utf8CStr::from_ptr(name)? };
if check_proto() { if check_proto() {
let mut props = proto_read_props()?; let mut props = proto_read_props()?;
let idx = props.find_index(name).no_log()?; let idx = props.find_index(name).no_log()?;
@ -212,10 +209,8 @@ pub unsafe fn persist_delete_prop(name: *const c_char) -> bool {
inner(name).is_ok() inner(name).is_ok()
} }
pub unsafe fn persist_set_prop(name: *const c_char, value: *const c_char) -> bool { pub unsafe fn persist_set_prop(name: &Utf8CStr, value: &Utf8CStr) -> bool {
unsafe fn inner(name: *const c_char, value: *const c_char) -> LoggedResult<()> { unsafe fn inner(name: &Utf8CStr, value: &Utf8CStr) -> LoggedResult<()> {
let name = Utf8CStr::from_ptr(name)?;
let value = Utf8CStr::from_ptr(value)?;
if check_proto() { if check_proto() {
let mut props = proto_read_props()?; let mut props = proto_read_props()?;
match props.find_index(name) { match props.find_index(name) {

View File

@ -105,7 +105,7 @@ bool sepolicy::exists(const char *type) {
} }
void sepolicy::load_rule_file(const char *file) { void sepolicy::load_rule_file(const char *file) {
rust::load_rule_file(*this, byte_view(file, false)); rust::load_rule_file(*this, file);
} }
void sepolicy::load_rules(const std::string &rules) { void sepolicy::load_rules(const std::string &rules) {

View File

@ -3,6 +3,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <string> #include <string>
#include <base.hpp>
// sepolicy paths // sepolicy paths
#define PLAT_POLICY_DIR "/system/etc/selinux/" #define PLAT_POLICY_DIR "/system/etc/selinux/"
#define VEND_POLICY_DIR "/vendor/etc/selinux/" #define VEND_POLICY_DIR "/vendor/etc/selinux/"
@ -38,8 +40,7 @@ struct sepolicy {
// External APIs // External APIs
bool to_file(c_str file); bool to_file(c_str file);
void parse_statement(c_str stmt, int len); void parse_statement(rust::Str stmt);
void parse_statement(c_str stmt) { parse_statement(stmt, strlen(stmt)); }
void load_rules(const std::string &rules); void load_rules(const std::string &rules);
void load_rule_file(c_str file); void load_rule_file(c_str file);
void print_rules(); void print_rules();

View File

@ -1,33 +1,37 @@
use io::Cursor; use io::Cursor;
use std::fs::File; use std::io;
use std::io::{BufRead, BufReader}; use std::io::{BufRead, BufReader};
use std::pin::Pin; use std::pin::Pin;
use std::{io, str};
pub use base; pub use base;
use base::*; use base::libc::{O_CLOEXEC, O_RDONLY};
use base::{BufReadExt, FsPath, LoggedResult, Utf8CStr};
use crate::ffi::sepolicy; use crate::ffi::sepolicy;
#[cxx::bridge] #[cxx::bridge]
mod ffi { mod ffi {
unsafe extern "C++" { unsafe extern "C++" {
#[namespace = "rust"]
#[cxx_name = "Utf8CStr"]
type Utf8CStrRef<'a> = base::ffi::Utf8CStrRef<'a>;
include!("include/sepolicy.hpp"); include!("include/sepolicy.hpp");
type sepolicy; type sepolicy;
unsafe fn parse_statement(self: Pin<&mut sepolicy>, stmt: *const c_char, len: i32); fn parse_statement(self: Pin<&mut sepolicy>, stmt: &str);
} }
#[namespace = "rust"] #[namespace = "rust"]
extern "Rust" { extern "Rust" {
fn load_rules(sepol: Pin<&mut sepolicy>, rules: &[u8]); fn load_rules(sepol: Pin<&mut sepolicy>, rules: &[u8]);
fn load_rule_file(sepol: Pin<&mut sepolicy>, filename: &[u8]); fn load_rule_file(sepol: Pin<&mut sepolicy>, filename: Utf8CStrRef);
} }
} }
trait SepolicyExt { trait SepolicyExt {
fn load_rules(self: Pin<&mut Self>, rules: &[u8]); fn load_rules(self: Pin<&mut Self>, rules: &[u8]);
fn load_rule_file(self: Pin<&mut Self>, filename: &[u8]); fn load_rule_file(self: Pin<&mut Self>, filename: &Utf8CStr);
fn load_rules_from_reader<T: BufRead>(self: Pin<&mut Self>, reader: &mut T); fn load_rules_from_reader<T: BufRead>(self: Pin<&mut Self>, reader: &mut T);
} }
@ -37,10 +41,10 @@ impl SepolicyExt for sepolicy {
self.load_rules_from_reader(&mut cursor); self.load_rules_from_reader(&mut cursor);
} }
fn load_rule_file(self: Pin<&mut sepolicy>, filename: &[u8]) { fn load_rule_file(self: Pin<&mut sepolicy>, filename: &Utf8CStr) {
fn inner(sepol: Pin<&mut sepolicy>, filename: &[u8]) -> LoggedResult<()> { fn inner(sepol: Pin<&mut sepolicy>, filename: &Utf8CStr) -> LoggedResult<()> {
let filename = str::from_utf8(filename)?; let file = FsPath::from(filename).open(O_RDONLY | O_CLOEXEC)?;
let mut reader = BufReader::new(File::open(filename)?); let mut reader = BufReader::new(file);
sepol.load_rules_from_reader(&mut reader); sepol.load_rules_from_reader(&mut reader);
Ok(()) Ok(())
} }
@ -49,17 +53,14 @@ impl SepolicyExt for sepolicy {
fn load_rules_from_reader<T: BufRead>(mut self: Pin<&mut sepolicy>, reader: &mut T) { fn load_rules_from_reader<T: BufRead>(mut self: Pin<&mut sepolicy>, reader: &mut T) {
reader.foreach_lines(|line| { reader.foreach_lines(|line| {
let bytes = line.trim().as_bytes(); let line = line.trim();
unsafe { self.as_mut().parse_statement(line);
self.as_mut()
.parse_statement(bytes.as_ptr().cast(), bytes.len() as i32);
}
true true
}); });
} }
} }
pub fn load_rule_file(sepol: Pin<&mut sepolicy>, filename: &[u8]) { pub fn load_rule_file(sepol: Pin<&mut sepolicy>, filename: &Utf8CStr) {
sepol.load_rule_file(filename); sepol.load_rule_file(filename);
} }

View File

@ -417,19 +417,19 @@ static bool parse_pattern_9(const Func &fn, const char *action, char *stmt) {
else if (strcmp(name, action) == 0) { \ else if (strcmp(name, action) == 0) { \
auto __fn = [&](auto && ...args){ return (fn)(args...); }; \ auto __fn = [&](auto && ...args){ return (fn)(args...); }; \
if (!parse_pattern_##type(__fn, name, remain)) \ if (!parse_pattern_##type(__fn, name, remain)) \
LOGW("Syntax error in '%.*s'\n\n%s\n", len, stmt, type_msg_##type); \ LOGW("Syntax error in '%.*s'\n\n%s\n", (int) stmt.length(), stmt.data(), type_msg_##type); \
} }
#define add_action(act, type) add_action_func(#act, type, act) #define add_action(act, type) add_action_func(#act, type, act)
void sepolicy::parse_statement(const char *stmt, int len) { void sepolicy::parse_statement(rust::Str stmt) {
// strtok modify strings, create a copy // strtok modify strings, create a copy
string cpy(stmt, len); string cpy(stmt.data(), stmt.length());
char *remain; char *remain;
char *action = strtok_r(cpy.data(), " ", &remain); char *action = strtok_r(cpy.data(), " ", &remain);
if (remain == nullptr) { if (remain == nullptr) {
LOGW("Syntax error in '%.*s'\n\n", len, stmt); LOGW("Syntax error in '%.*s'\n\n", (int) stmt.length(), stmt.data());
return; return;
} }