A Rust implementation of magiskpolicy for manipulating SELinux policies.
This library requires libsepol for proper policy binary parsing.
The SELinux policy binary format is complex and requires libsepol to properly parse. Without libsepol:
from_file()andfrom_data()will not properly parse policy filesprint_rules()will only show rules added via the API, not from loaded policiesto_file()will not work properly for creating valid policy files
- Android NDK installed
- libsepol sources (included in Magisk project)
# Build with libsepol (requires libsepol to be built first)
cargo ndk -t arm64-v8a build --releaseThe Magisk project includes libsepol sources at:
native/src/external/selinux/libsepol/
Build libsepol first:
cd Magisk/native/src/external
# Build libsepol using the Android.mk or build scriptsap_policy/
├── Cargo.toml # Workspace configuration
├── crates/
│ ├── policy/ # Core SELinux policy library
│ │ ├── Cargo.toml
│ │ ├── src/
│ │ │ ├── lib.rs # Main library with SePolicy struct
│ │ │ ├── statement.rs # Policy statement parser
│ │ │ └── rules.rs # Magisk-specific rules
│ │ └── README.md
│ └── magiskpolicy/ # CLI binary
│ ├── Cargo.toml
│ ├── src/
│ │ └── main.rs # Command-line interface
│ └── README.md
└── README.md # This file
Add to your Cargo.toml:
[dependencies]
policy = { path = "path/to/crates/policy" }Example:
use policy::{SePolicy, Xperm};
fn main() -> std::io::Result<()> {
// Load policy from a file (requires libsepol for proper parsing)
let mut policy = SePolicy::from_file("/sys/fs/selinux/policy")?;
// Apply Magisk rules
policy.magisk_rules();
// Add custom rules
policy.allow(
&["domain"],
&["magisk_file"],
&["file"],
&["read", "write"]
);
// Add extended permissions
policy.allowxperm(
&["magisk"],
&["dev_type"],
&["chr_file"],
&[Xperm::range(0x8910, 0x8926)]
);
// Load rules from a string
policy.load_rules("allow domain magisk_file file { read write }");
// Save modified policy (requires libsepol for proper serialization)
policy.to_file("modified_policy")?;
Ok(())
}Build:
cargo build --releaseFor Android (requires NDK):
cargo ndk -t arm64-v8a build --releaseRun:
./magiskpolicy --help
./magiskpolicy --magisk --save modified_policy
./magiskpolicy --load policy --apply rules.txt --save outputUsage: magiskpolicy [--options...] [policy statements...]
Options:
--help show help message for policy statements
--load FILE load monolithic sepolicy from FILE
--load-split load from precompiled sepolicy or compile split cil policies
--compile-split compile split cil policies
--save FILE dump monolithic sepolicy to FILE
--live immediately load sepolicy into the kernel
--magisk apply built-in Magisk sepolicy rules
--apply FILE apply rules from FILE, read line by line as policy statements
--print-rules print all rules in the loaded sepolicy
The library supports the following SELinux policy statements:
allow *source_type *target_type *class *perm_setdeny *source_type *target_type *class *perm_setauditallow *source_type *target_type *class *perm_setdontaudit *source_type *target_type *class *perm_setallowxperm *source_type *target_type *class ioctl xperm_setauditallowxperm *source_type *target_type *class ioctl xperm_setdontauditxperm *source_type *target_type *class ioctl xperm_setpermissive *typeenforce *typetypeattribute ^type ^attributetype type_name ^(attribute)attribute attribute_nametype_transition source_type target_type class default_type (object_name)type_change source_type target_type class default_typetype_member source_type target_type class default_typegenfscon fs_name partial_path fs_context
Arguments labeled with (^) can accept one or more entries in braces {}.
Arguments labeled with (*) additionally support the match-all operator *.
Main structure for manipulating SELinux policies.
from_file(path)- Load policy from a filefrom_data(data)- Load policy from binary datafrom_split()- Load from split CIL policiescompile_split()- Compile split CIL policiesto_file(path)- Save policy to a file
allow(src, tgt, cls, perm)- Add allow ruledeny(src, tgt, cls, perm)- Add deny ruleauditallow(src, tgt, cls, perm)- Add auditallow ruledontaudit(src, tgt, cls, perm)- Add dontaudit ruleallowxperm(src, tgt, cls, xperms)- Add extended permissionsauditallowxperm(src, tgt, cls, xperms)- Add audit extended permissionsdontauditxperm(src, tgt, cls, xperms)- Add dontaudit extended permissions
permissive(types)- Make types permissiveenforce(types)- Make types enforcingtypeattribute(types, attrs)- Add attributes to typestype_(name, attrs)- Create new typeattribute(name)- Create new attribute
type_transition(src, tgt, cls, def, obj)- Add type transition ruletype_change(src, tgt, cls, def)- Add type change ruletype_member(src, tgt, cls, def)- Add type member rule
genfscon(fs, path, ctx)- Add genfscon rulemagisk_rules()- Apply built-in Magisk rulesload_rules(rules)- Load and parse rules from stringload_rule_file(filename)- Load rules from fileprint_rules()- Print all rules
Extended permission structure for ioctl operations.
// Single ioctl command
Xperm::single(0x8910)
// Range of ioctl commands
Xperm::range(0x8910, 0x8926)
// Complement (all except range)
Xperm::complement(0x8910, 0x8926)
// All ioctl commands
Xperm::all()- Policy binary parsing requires libsepol - This is the key limitation
- CIL parsing is not implemented
- Policy binary serialization requires libsepol
print_rules()only shows in-memory rules, not loaded policy content without libsepol
To properly parse and manipulate real SELinux policies, you need to integrate libsepol. See the Magisk project's implementation for reference:
- libsepol sources:
Magisk/native/src/external/selinux/libsepol/ - C++ wrapper:
Magisk/native/src/sepolicy/sepolicy.cpp - Rust FFI:
Magisk/native/src/sepolicy/lib.rs
Apache-2.0