How Magisk Handles SELinux Policies with magiskpolicy

Magisk handles SELinux policies through the standalone magiskpolicy Rust binary, which patches the kernel's security policy at boot by loading the stock configuration, injecting built-in Magisk rules, and merging module-specific statements before writing the result directly to /sys/fs/selinux/policy.

The topjohnwu/Magisk repository implements a comprehensive SELinux management system centered on the magiskpolicy utility. This tool allows the framework to modify mandatory access controls without recompiling entire policy binaries, enabling root functionality while maintaining Android's security model.

What Is magiskpolicy and Where It Lives

The magiskpolicy binary is a Rust-based utility that serves as the primary interface for SELinux policy manipulation in Magisk.

Source Code Location

The implementation resides in the native Rust codebase:

Build System Integration

The binary is compiled through the Android NDK build system as defined in native/src/Android.mk, which packages magiskpolicy alongside other Magisk native components. During the build process, the Rust crate is compiled into a static binary suitable for Android's execution environment.

Legacy Compatibility

For backward compatibility with legacy SuperSU scripts, scripts/live_setup.sh creates a symbolic link exposing magiskpolicy as supolicy:

ln -s ./magiskpolicy $MAGISKTMP/supolicy

This alias ensures existing modules and scripts referencing the older supolicy command continue to function correctly.

Loading and Applying Policies at Boot

During the live-boot stage, Magisk orchestrates policy patching through scripts/live_setup.sh to establish the necessary security context for daemon operation.

The Boot-Time Orchestration

The setup script invokes magiskpolicy with specific flags to load the device's stock policy and inject Magisk-specific rules:

./magiskpolicy --load /vendor/etc/selinux/precompiled_sepolicy --live --magisk $RULESCMD
./magiskpolicy --load /sepolicy --live --magisk $RULESCMD
./magiskpolicy --live --magisk $RULESCMD

These commands attempt to load the precompiled vendor policy first, falling back to the root /sepolicy file if unavailable, and finally operating on the current live policy if neither file exists.

Command-Line Flags Explained

Each flag serves a distinct function in the policy pipeline:

  • --load <file> – Reads a monolithic policy binary from the specified path (e.g., /vendor/etc/selinux/precompiled_sepolicy).
  • --live – Sends the modified policy directly to the kernel via the /sys/fs/selinux/policy interface, applying changes immediately without reboot.
  • --magisk – Automatically injects the built-in Magisk rule set, effectively executing allow magisk * * * to permit the Magisk domain universal access.

The $RULESCMD variable contains additional policy statements supplied by the user or modules, passed internally using the --apply mechanism.

Policy Syntax and Capabilities

The magiskpolicy parser, implemented in native/src/sepolicy/cli.rs, supports a statement format mirroring classic SELinux .te (Type Enforcement) syntax supplied via command-line arguments.

Supported Statement Types

According to the documentation in docs/tools.md, the utility recognizes several policy statement types:

  • allow *source_type *target_type *class *perm_set – Standard access control rules allowing a source domain to perform actions on target objects.
  • allowxperm … – Extended permission rules (X-perm) for ioctl controls, introduced for Android O compatibility.
  • permissive ^type – Switches a specific domain to permissive mode for debugging.
  • enforce ^type – Re-enables enforcing mode for a specified domain.

Arguments may be specified as wildcards (*), lists (e.g., { s1 s2 }), or specific identifiers, providing flexibility in rule definition.

Extending Policies via Magisk Modules

Magisk modules can ship custom SELinux rules without modifying the core policy binary, leveraging the --apply interface for safe, isolated extensions.

Module Policy Files

Modules typically include a sepolicy.rules file within their directory structure (/data/adb/modules/<module>/sepolicy.rules). When Magisk initializes modules during boot, it invokes:

./magiskpolicy --live --magisk --apply /data/adb/modules/<module>/sepolicy.rules

Runtime Merging Process

The merging logic concatenates parsed statements from the module's rule file into the in-memory policy representation before committing the final policy to the kernel. This approach allows modules to declare necessary permissions (e.g., accessing hardware nodes or system properties) without conflicting with the stock SELinux configuration or other modules.

Runtime Usage and Developer Workflows

Beyond boot-time automation, magiskpolicy functions as a standalone developer tool for debugging and policy analysis.

Direct Shell Invocation

Developers can invoke the binary directly from an ADB shell or terminal emulator to inspect or modify the current security policy:


# Display all active rules in the running policy

magiskpolicy --print-rules

# Inject a temporary rule for testing

magiskpolicy --live "allow my_app file file { read write }"

Advanced Policy Operations

The CLI supports additional workflows for policy manipulation:

  • --save <file> – Exports the current live policy to a binary file for offline analysis.
  • --load-split – Handles split policy configurations common in newer Android versions, loading from /vendor/etc/selinux/precompiled_sepolicy and associated split contexts.

These capabilities enable developers to extract stock policies, modify them using external tools, and re-inject the modified versions for testing.

Summary

  • magiskpolicy is a Rust binary located in native/src/sepolicy/ that serves as Magisk's sole interface for SELinux manipulation.
  • At boot, scripts/live_setup.sh invokes the tool with --load, --live, and --magisk flags to patch the kernel policy and establish the magisk domain.
  • Modules extend policies by placing rules in sepolicy.rules files, processed via the --apply flag during module loading.
  • The tool supports standard SELinux syntax including allow, allowxperm, and permissive statements with wildcard and list expansion.
  • Runtime usage via --print-rules and --save enables debugging and policy analysis without requiring a full rebuild cycle.

Frequently Asked Questions

What is the difference between magiskpolicy and supolicy?

magiskpolicy is the current binary name for Magisk's SELinux policy tool, while supolicy is a legacy alias maintained for backward compatibility. During initialization, scripts/live_setup.sh creates a symbolic link from magiskpolicy to supolicy, ensuring older modules and scripts referencing the SuperSU-era command continue to function without modification.

How do I add custom SELinux rules to a Magisk module?

Create a file named sepolicy.rules in your module's root directory (/data/adb/modules/<your-module>/). Place valid SELinux statements inside using standard Type Enforcement syntax (e.g., allow my_daemon property_type property_service { set }). Magisk automatically passes this file to magiskpolicy --apply during the boot sequence, merging your rules into the live kernel policy.

Can I use magiskpolicy to modify policies on a running device?

Yes. The --live flag enables runtime policy modification without rebooting. You can execute commands like magiskpolicy --live "allow my_app device chr_file { read write }" from a root shell to temporarily extend permissions. However, these changes persist only until the next reboot unless incorporated into a module's sepolicy.rules file.

Where does magiskpolicy store the modified policy?

The tool does not store policies in persistent storage by default. When using --live, it writes directly to /sys/fs/selinux/policy, modifying the kernel's in-memory policy representation. To save a policy binary for offline editing, use the --save <filename> flag, which exports the current live policy to the specified file path.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →