Migrate selinux.cpp to selinux.rs

This commit is contained in:
topjohnwu 2025-04-26 03:56:37 -07:00 committed by John Wu
parent c7d1af9805
commit 73840f8721
19 changed files with 172 additions and 181 deletions

View File

@ -19,7 +19,6 @@ LOCAL_SRC_FILES := \
core/magisk.cpp \ core/magisk.cpp \
core/daemon.cpp \ core/daemon.cpp \
core/scripting.cpp \ core/scripting.cpp \
core/selinux.cpp \
core/sqlite.cpp \ core/sqlite.cpp \
core/module.cpp \ core/module.cpp \
core/thread.cpp \ core/thread.cpp \

View File

@ -85,6 +85,7 @@ pub trait Utf8CStrBuf: Write + AsRef<Utf8CStr> + Deref<Target = Utf8CStr> {
fn capacity(&self) -> usize; fn capacity(&self) -> usize;
fn clear(&mut self); fn clear(&mut self);
fn as_mut_ptr(&mut self) -> *mut c_char; fn as_mut_ptr(&mut self) -> *mut c_char;
fn truncate(&mut self, new_len: usize);
#[inline(always)] #[inline(always)]
fn is_empty(&self) -> bool { fn is_empty(&self) -> bool {
@ -183,6 +184,11 @@ impl Utf8CStrBuf for Utf8CString {
fn as_mut_ptr(&mut self) -> *mut c_char { fn as_mut_ptr(&mut self) -> *mut c_char {
self.0.as_mut_ptr().cast() self.0.as_mut_ptr().cast()
} }
fn truncate(&mut self, new_len: usize) {
self.0.truncate(new_len);
self.0.nul_terminate();
}
} }
impl From<String> for Utf8CString { impl From<String> for Utf8CString {
@ -337,6 +343,12 @@ impl ToOwned for Utf8CStr {
} }
} }
impl AsRef<Utf8CStr> for Utf8CStr {
fn as_ref(&self) -> &Utf8CStr {
self
}
}
// Notice that we only implement ExternType on Utf8CStr *reference* // Notice that we only implement ExternType on Utf8CStr *reference*
unsafe impl ExternType for &Utf8CStr { unsafe impl ExternType for &Utf8CStr {
type Id = type_id!("rust::Utf8CStr"); type Id = type_id!("rust::Utf8CStr");
@ -449,7 +461,7 @@ macro_rules! impl_cstr_misc {
self == other.as_cstr() self == other.as_cstr()
} }
} }
impl<T: AsRef<Utf8CStr>, $($g)*> PartialEq<T> for $t { impl<T: AsRef<Utf8CStr> + ?Sized, $($g)*> PartialEq<T> for $t {
#[inline(always)] #[inline(always)]
fn eq(&self, other: &T) -> bool { fn eq(&self, other: &T) -> bool {
self.as_bytes_with_nul() == other.as_ref().as_bytes_with_nul() self.as_bytes_with_nul() == other.as_ref().as_bytes_with_nul()
@ -521,6 +533,13 @@ macro_rules! impl_cstr_buf {
fn as_mut_ptr(&mut self) -> *mut c_char { fn as_mut_ptr(&mut self) -> *mut c_char {
self.buf.as_mut_ptr().cast() self.buf.as_mut_ptr().cast()
} }
fn truncate(&mut self, new_len: usize) {
if self.used <= new_len {
return;
}
self.buf[new_len] = b'\0';
self.used = new_len;
}
} }
)*} )*}
} }

View File

@ -1,7 +1,6 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <consts.hpp> #include <consts.hpp>
#include <selinux.hpp>
#include <base.hpp> #include <base.hpp>
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {

View File

@ -3,7 +3,6 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <consts.hpp> #include <consts.hpp>
#include <selinux.hpp>
#include <base.hpp> #include <base.hpp>
using namespace std; using namespace std;

View File

@ -8,7 +8,6 @@
#include <consts.hpp> #include <consts.hpp>
#include <base.hpp> #include <base.hpp>
#include <core.hpp> #include <core.hpp>
#include <selinux.hpp>
#include <flags.h> #include <flags.h>
using namespace std; using namespace std;
@ -339,6 +338,16 @@ static void switch_cgroup(const char *cgroup, int pid) {
close(fd); close(fd);
} }
static int setcon(const char *con) {
int fd = open("/proc/self/attr/current", O_WRONLY | O_CLOEXEC);
if (fd < 0)
return fd;
size_t len = strlen(con) + 1;
int rc = write(fd, con, len);
close(fd);
return rc != len;
}
static void daemon_entry() { static void daemon_entry() {
android_logging(); android_logging();
@ -383,8 +392,6 @@ static void daemon_entry() {
set_prop("ro.vendor.mtk_model", "0"); set_prop("ro.vendor.mtk_model", "0");
} }
restore_tmpcon();
// Cleanups // Cleanups
const char *tmp = get_magisk_tmp(); const char *tmp = get_magisk_tmp();
char path[64]; char path[64];

View File

@ -8,6 +8,7 @@ use crate::get_prop;
use crate::logging::{magisk_logging, setup_logfile, start_log_daemon}; use crate::logging::{magisk_logging, setup_logfile, start_log_daemon};
use crate::mount::{clean_mounts, setup_mounts}; use crate::mount::{clean_mounts, setup_mounts};
use crate::package::ManagerInfo; use crate::package::ManagerInfo;
use crate::selinux::restore_tmpcon;
use crate::su::SuInfo; use crate::su::SuInfo;
use base::libc::{O_CLOEXEC, O_RDONLY}; use base::libc::{O_CLOEXEC, O_RDONLY};
use base::{AtomicArc, BufReadExt, FsPathBuilder, ResultExt, Utf8CStr, cstr, error, info, libc}; use base::{AtomicArc, BufReadExt, FsPathBuilder, ResultExt, Utf8CStr, cstr, error, info, libc};
@ -259,6 +260,8 @@ pub fn daemon_entry() {
} }
info!("* Device API level: {}", sdk_int); info!("* Device API level: {}", sdk_int);
restore_tmpcon().log_ok();
let magiskd = MagiskD { let magiskd = MagiskD {
sdk_int, sdk_int,
is_emulator, is_emulator,

View File

@ -10,7 +10,6 @@
#include <base.hpp> #include <base.hpp>
#include <sqlite.hpp> #include <sqlite.hpp>
#include <core.hpp> #include <core.hpp>
#include <selinux.hpp>
#include "deny.hpp" #include "deny.hpp"
@ -109,10 +108,10 @@ static bool proc_name_match(int pid, string_view name) {
bool proc_context_match(int pid, string_view context) { bool proc_context_match(int pid, string_view context) {
char buf[PATH_MAX]; char buf[PATH_MAX];
char con[1024]; char con[1024] = {0};
sprintf(buf, "/proc/%d", pid); sprintf(buf, "/proc/%d", pid);
if (lgetfilecon(buf, { con, sizeof(con) }) >= 0) { if (lgetfilecon(buf, byte_data{ con, sizeof(con) })) {
return str_starts(con, context); return str_starts(con, context);
} }
return false; return false;

View File

@ -1,16 +0,0 @@
#pragma once
#include <base.hpp>
int setcon(const char *con);
int getfilecon(const char *path, byte_data con);
int lgetfilecon(const char *path, byte_data con);
int fgetfilecon(int fd, byte_data con);
int setfilecon(const char *path, const char *con);
int lsetfilecon(const char *path, const char *con);
int fsetfilecon(int fd, const char *con);
int getfilecon_at(int dirfd, const char *name, byte_data con);
void setfilecon_at(int dirfd, const char *name, const char *con);
void restorecon();
void restore_tmpcon();

View File

@ -15,6 +15,7 @@ use derive::Decodable;
use logging::{android_logging, setup_logfile, zygisk_close_logd, zygisk_get_logd, zygisk_logging}; use logging::{android_logging, setup_logfile, zygisk_close_logd, zygisk_get_logd, zygisk_logging};
use mount::{find_preinit_device, revert_unmount}; use mount::{find_preinit_device, revert_unmount};
use resetprop::{persist_delete_prop, persist_get_prop, persist_get_props, persist_set_prop}; use resetprop::{persist_delete_prop, persist_get_prop, persist_get_props, persist_set_prop};
use selinux::{lgetfilecon, lsetfilecon, restorecon, setfilecon};
use socket::{recv_fd, recv_fds, send_fd, send_fds}; use socket::{recv_fd, recv_fds, send_fd, send_fds};
use std::fs::File; use std::fs::File;
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
@ -31,6 +32,7 @@ mod logging;
mod mount; mod mount;
mod package; mod package;
mod resetprop; mod resetprop;
mod selinux;
mod socket; mod socket;
mod su; mod su;
mod zygisk; mod zygisk;
@ -205,13 +207,16 @@ pub mod ffi {
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); unsafe fn write_to_fd(self: &SuRequest, fd: i32);
#[namespace = "rust"]
fn daemon_entry();
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;
fn restorecon();
fn lgetfilecon(path: Utf8CStrRef, con: &mut [u8]) -> bool;
fn setfilecon(path: Utf8CStrRef, con: Utf8CStrRef) -> bool;
fn lsetfilecon(path: Utf8CStrRef, con: Utf8CStrRef) -> bool;
#[namespace = "rust"]
fn daemon_entry();
} }
// Default constructors // Default constructors

View File

@ -4,7 +4,6 @@
#include <base.hpp> #include <base.hpp>
#include <consts.hpp> #include <consts.hpp>
#include <core.hpp> #include <core.hpp>
#include <selinux.hpp>
#include <flags.h> #include <flags.h>
using namespace std; using namespace std;

View File

@ -7,7 +7,6 @@
#include <base.hpp> #include <base.hpp>
#include <consts.hpp> #include <consts.hpp>
#include <core.hpp> #include <core.hpp>
#include <selinux.hpp>
#include "node.hpp" #include "node.hpp"

View File

@ -4,7 +4,6 @@
#include <consts.hpp> #include <consts.hpp>
#include <base.hpp> #include <base.hpp>
#include <selinux.hpp>
#include <core.hpp> #include <core.hpp>
using namespace std; using namespace std;

View File

@ -1,139 +0,0 @@
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/xattr.h>
#include <consts.hpp>
#include <base.hpp>
#include <selinux.hpp>
#include <core.hpp>
#include <flags.h>
using namespace std;
int setcon(const char *con) {
int fd = open("/proc/self/attr/current", O_WRONLY | O_CLOEXEC);
if (fd < 0)
return fd;
size_t len = strlen(con) + 1;
int rc = write(fd, con, len);
close(fd);
return rc != len;
}
int getfilecon(const char *path, byte_data con) {
return syscall(__NR_getxattr, path, XATTR_NAME_SELINUX, con.buf(), con.sz());
}
int lgetfilecon(const char *path, byte_data con) {
return syscall(__NR_lgetxattr, path, XATTR_NAME_SELINUX, con.buf(), con.sz());
}
int fgetfilecon(int fd, byte_data con) {
return syscall(__NR_fgetxattr, fd, XATTR_NAME_SELINUX, con.buf(), con.sz());
}
int setfilecon(const char *path, const char *con) {
return syscall(__NR_setxattr, path, XATTR_NAME_SELINUX, con, strlen(con) + 1, 0);
}
int lsetfilecon(const char *path, const char *con) {
return syscall(__NR_lsetxattr, path, XATTR_NAME_SELINUX, con, strlen(con) + 1, 0);
}
int fsetfilecon(int fd, const char *con) {
return syscall(__NR_fsetxattr, fd, XATTR_NAME_SELINUX, con, strlen(con) + 1, 0);
}
int getfilecon_at(int dirfd, const char *name, byte_data con) {
char path[4096];
fd_pathat(dirfd, name, path, sizeof(path));
return lgetfilecon(path, con);
}
void setfilecon_at(int dirfd, const char *name, const char *con) {
char path[4096];
fd_pathat(dirfd, name, path, sizeof(path));
lsetfilecon(path, con);
}
#define UNLABEL_CON "u:object_r:unlabeled:s0"
#define SYSTEM_CON "u:object_r:system_file:s0"
#define ADB_CON "u:object_r:adb_data_file:s0"
#define ROOT_CON "u:object_r:rootfs:s0"
static void restore_syscon_from_null(int dirfd) {
struct dirent *entry;
char con[1024];
if (fgetfilecon(dirfd, { con, sizeof(con) }) >= 0) {
if (con[0] == '\0' || strcmp(con, UNLABEL_CON) == 0)
fsetfilecon(dirfd, SYSTEM_CON);
}
auto dir = xopen_dir(dirfd);
while ((entry = xreaddir(dir.get()))) {
int fd = openat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
if (entry->d_type == DT_DIR) {
restore_syscon_from_null(fd);
continue;
} else if (entry->d_type == DT_REG) {
if (fgetfilecon(fd, { con, sizeof(con) }) >= 0) {
if (con[0] == '\0' || strcmp(con, UNLABEL_CON) == 0)
fsetfilecon(fd, SYSTEM_CON);
}
} else if (entry->d_type == DT_LNK) {
if (getfilecon_at(dirfd, entry->d_name, { con, sizeof(con) }) >= 0) {
if (con[0] == '\0' || strcmp(con, UNLABEL_CON) == 0)
setfilecon_at(dirfd, entry->d_name, SYSTEM_CON);
}
}
close(fd);
}
}
static void restore_syscon(int dirfd) {
struct dirent *entry;
fsetfilecon(dirfd, SYSTEM_CON);
fchown(dirfd, 0, 0);
auto dir = xopen_dir(dirfd);
while ((entry = xreaddir(dir.get()))) {
int fd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC);
if (entry->d_type == DT_DIR) {
restore_syscon(fd);
continue;
} else if (entry->d_type) {
fsetfilecon(fd, SYSTEM_CON);
fchown(fd, 0, 0);
}
close(fd);
}
}
void restorecon() {
int fd = xopen("/sys/fs/selinux/context", O_WRONLY | O_CLOEXEC);
if (write(fd, ADB_CON, sizeof(ADB_CON)) >= 0)
lsetfilecon(SECURE_DIR, ADB_CON);
close(fd);
lsetfilecon(MODULEROOT, SYSTEM_CON);
restore_syscon_from_null(xopen(MODULEROOT, O_RDONLY | O_CLOEXEC));
restore_syscon(xopen(DATABIN, O_RDONLY | O_CLOEXEC));
}
void restore_tmpcon() {
const char *tmp = get_magisk_tmp();
if (tmp == "/sbin"sv)
setfilecon(tmp, ROOT_CON);
else
chmod(tmp, 0711);
auto dir = xopen_dir(tmp);
int dfd = dirfd(dir.get());
for (dirent *entry; (entry = xreaddir(dir.get()));)
setfilecon_at(dfd, entry->d_name, SYSTEM_CON);
string logd = tmp + "/"s LOG_PIPE;
setfilecon(logd.data(), MAGISK_LOG_CON);
}

108
native/src/core/selinux.rs Normal file
View File

@ -0,0 +1,108 @@
use crate::consts::{DATABIN, LOG_PIPE, MAGISK_LOG_CON, MODULEROOT, SECURE_DIR};
use crate::ffi::get_magisk_tmp;
use base::libc::{O_CLOEXEC, O_WRONLY};
use base::{Directory, FsPathBuilder, LoggedResult, ResultExt, Utf8CStr, Utf8CStrBuf, cstr, libc};
use std::io::Write;
const UNLABEL_CON: &Utf8CStr = cstr!("u:object_r:unlabeled:s0");
const SYSTEM_CON: &Utf8CStr = cstr!("u:object_r:system_file:s0");
const ADB_CON: &Utf8CStr = cstr!("u:object_r:adb_data_file:s0");
const ROOT_CON: &Utf8CStr = cstr!("u:object_r:rootfs:s0");
fn restore_syscon_from_unlabeled(
path: &mut dyn Utf8CStrBuf,
con: &mut dyn Utf8CStrBuf,
) -> LoggedResult<()> {
let dir_path_len = path.len();
if path.get_secontext(con).log().is_ok() && con.as_str() == UNLABEL_CON {
path.set_secontext(SYSTEM_CON)?;
}
let mut dir = Directory::open(path)?;
while let Some(ref e) = dir.read()? {
path.truncate(dir_path_len);
path.append_path(e.name());
if e.is_dir() {
restore_syscon_from_unlabeled(path, con)?;
} else if (e.is_file() || e.is_symlink())
&& path.get_secontext(con).log().is_ok()
&& con.as_str() == UNLABEL_CON
{
path.set_secontext(SYSTEM_CON)?;
}
}
Ok(())
}
fn restore_syscon(path: &mut dyn Utf8CStrBuf) -> LoggedResult<()> {
let dir_path_len = path.len();
path.set_secontext(SYSTEM_CON)?;
unsafe { libc::lchown(path.as_ptr(), 0, 0) };
let mut dir = Directory::open(path)?;
while let Some(ref e) = dir.read()? {
path.truncate(dir_path_len);
path.append_path(e.name());
if e.is_dir() {
restore_syscon(path)?;
} else if e.is_file() || e.is_symlink() {
path.set_secontext(SYSTEM_CON)?;
unsafe { libc::lchown(path.as_ptr(), 0, 0) };
}
}
Ok(())
}
pub(crate) fn restorecon() {
if let Ok(mut file) = cstr!("/sys/fs/selinux/context")
.open(O_WRONLY | O_CLOEXEC)
.log()
{
if file.write_all(ADB_CON.as_bytes_with_nul()).is_ok() {
cstr!(SECURE_DIR).set_secontext(ADB_CON).log_ok();
}
}
let mut path = cstr::buf::default();
let mut con = cstr::buf::new::<1024>();
path.push_str(MODULEROOT);
path.set_secontext(SYSTEM_CON).log_ok();
restore_syscon_from_unlabeled(&mut path, &mut con).log_ok();
path.clear();
path.push_str(DATABIN);
restore_syscon(&mut path).log_ok();
}
pub(crate) fn restore_tmpcon() -> LoggedResult<()> {
let tmp = get_magisk_tmp();
if tmp == "/sbin" {
tmp.set_secontext(ROOT_CON)?;
} else {
unsafe { libc::chmod(tmp.as_ptr(), 0o711) };
}
let mut path = cstr::buf::default();
let mut dir = Directory::open(tmp)?;
while let Some(ref e) = dir.read()? {
e.resolve_path(&mut path)?;
path.set_secontext(SYSTEM_CON)?;
}
path.clear();
path.append_path(tmp).append_path(LOG_PIPE);
path.set_secontext(cstr!(MAGISK_LOG_CON))?;
Ok(())
}
pub(crate) fn lgetfilecon(path: &Utf8CStr, con: &mut [u8]) -> bool {
let mut con = cstr::buf::wrap(con);
path.get_secontext(&mut con).is_ok()
}
pub(crate) fn setfilecon(path: &Utf8CStr, con: &Utf8CStr) -> bool {
path.follow_link().set_secontext(con).is_ok()
}
pub(crate) fn lsetfilecon(path: &Utf8CStr, con: &Utf8CStr) -> bool {
path.set_secontext(con).is_ok()
}

View File

@ -2,7 +2,6 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <base.hpp> #include <base.hpp>
#include <selinux.hpp>
#include <consts.hpp> #include <consts.hpp>
#include <core.hpp> #include <core.hpp>

View File

@ -5,7 +5,6 @@
#include <consts.hpp> #include <consts.hpp>
#include <base.hpp> #include <base.hpp>
#include <core.hpp> #include <core.hpp>
#include <selinux.hpp>
#include "zygisk.hpp" #include "zygisk.hpp"

View File

@ -15,16 +15,25 @@ pub const LOGFILE: &str = "/cache/magisk.log";
// data paths // data paths
pub const SECURE_DIR: &str = "/data/adb"; pub const SECURE_DIR: &str = "/data/adb";
pub const MODULEROOT: &str = concatcp!(SECURE_DIR, "/modules"); pub const MODULEROOT: &str = concatcp!(SECURE_DIR, "/modules");
pub const DATABIN: &str = concatcp!(SECURE_DIR, "/magisk");
// tmpfs paths // tmpfs paths
const INTERNAL_DIR: &str = ".magisk"; const INTERNAL_DIR: &str = ".magisk";
pub const LOG_PIPE: &str = concatcp!(INTERNAL_DIR, "/device/log");
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");
pub const WORKERDIR: &str = concatcp!(INTERNAL_DIR, "/worker"); pub const WORKERDIR: &str = concatcp!(INTERNAL_DIR, "/worker");
pub const DEVICEDIR: &str = concatcp!(INTERNAL_DIR, "/device"); pub const DEVICEDIR: &str = concatcp!(INTERNAL_DIR, "/device");
pub const PREINITDEV: &str = concatcp!(DEVICEDIR, "/preinit"); pub const PREINITDEV: &str = concatcp!(DEVICEDIR, "/preinit");
pub const LOG_PIPE: &str = concatcp!(DEVICEDIR, "/log");
pub const ROOTOVL: &str = concatcp!(INTERNAL_DIR, "/rootdir"); pub const ROOTOVL: &str = concatcp!(INTERNAL_DIR, "/rootdir");
pub const ROOTMNT: &str = concatcp!(ROOTOVL, "/.mount_list"); pub const ROOTMNT: &str = concatcp!(ROOTOVL, "/.mount_list");
pub const SELINUXMOCK: &str = concatcp!(INTERNAL_DIR, "/selinux"); pub const SELINUXMOCK: &str = concatcp!(INTERNAL_DIR, "/selinux");
// Unconstrained domain the daemon and root processes run in
pub const SEPOL_PROC_DOMAIN: &str = "magisk";
// Unconstrained file type that anyone can access
pub const SEPOL_FILE_TYPE: &str = "magisk_file";
// Log pipe that only root and zygote can open
pub const SEPOL_LOG_TYPE: &str = "magisk_log_file";
pub const MAGISK_LOG_CON: &str = concatcp!("u:object_r:", SEPOL_LOG_TYPE, ":s0");

View File

@ -6,6 +6,9 @@ use std::fmt::Write;
use crate::ffi::SePolicy; use crate::ffi::SePolicy;
#[path = "../include/consts.rs"]
mod consts;
#[cfg(feature = "main")] #[cfg(feature = "main")]
mod cli; mod cli;
mod rules; mod rules;

View File

@ -1,3 +1,4 @@
use crate::consts::{SEPOL_FILE_TYPE, SEPOL_LOG_TYPE, SEPOL_PROC_DOMAIN};
use crate::{SePolicy, ffi::Xperm}; use crate::{SePolicy, ffi::Xperm};
use base::{LogLevel, set_log_level_state}; use base::{LogLevel, set_log_level_state};
@ -12,22 +13,22 @@ macro_rules! rules {
vec!["servicemanager", "vndservicemanager", "hwservicemanager"] vec!["servicemanager", "vndservicemanager", "hwservicemanager"]
}; };
(@args [proc]) => { (@args [proc]) => {
vec!["magisk"] vec![SEPOL_PROC_DOMAIN]
}; };
(@args [file]) => { (@args [file]) => {
vec!["magisk_file"] vec![SEPOL_FILE_TYPE]
}; };
(@args [log]) => { (@args [log]) => {
vec!["magisk_log_file"] vec![SEPOL_LOG_TYPE]
}; };
(@args proc) => { (@args proc) => {
"magisk" SEPOL_PROC_DOMAIN
}; };
(@args file) => { (@args file) => {
"magisk_file" SEPOL_FILE_TYPE
}; };
(@args log) => { (@args log) => {
"magisk_log_file" SEPOL_LOG_TYPE
}; };
(@args [$($arg:tt)*]) => { (@args [$($arg:tt)*]) => {
vec![$($arg)*] vec![$($arg)*]