How Magisk Injects Binaries into the System PATH: The magiskinit Mount Strategy

Magisk creates a temporary tmpfs mount at /magisk, populates it with symlinks to its core binaries (su, resetprop, magiskpolicy), and prepends this directory to the global $PATH during early init, ensuring all system processes resolve these commands to the Magisk versions before reaching stock ROM binaries.

Magisk achieves privileged binary interception without modifying the read-only /system partition by manipulating the process environment before Android fully boots. According to the topjohnwu/Magisk source code, the injection mechanism relies on magiskinit to establish a writable temporary filesystem, extract the necessary binaries from the Magisk APK, and export a modified PATH variable that prioritizes Magisk's utilities.

Creating the MAGISKTMP Mount Point in magiskinit

During the earliest phase of device initialization, magiskinit establishes a dedicated staging area for Magisk's binaries. This occurs before the main Android init process begins, ensuring the environment is prepared for all subsequent processes.

Mounting the tmpfs Filesystem

In native/src/init/mount.cpp, the initialization code creates a writable tmpfs filesystem at the fixed location /magisk. This provides a volatile, executable directory that persists only for the current boot session:

// native/src/init/mount.cpp
mount("tmpfs", "/magisk", "tmpfs", 0, "mode=0755");
setenv("MAGISKTMP", "/magisk", 1);

The mount() call establishes the directory with 0755 permissions, making it executable and accessible to the processes that need to resolve binaries from this location. The setenv() call immediately exports the MAGISKTMP environment variable, making the mount point path available to helper scripts and subsequent binary installation steps.

Populating the Temporary Directory with Magisk Binaries

Once the mount point exists, Magisk must place its privileged binaries inside $MAGISKTMP. This extraction and linking process is handled by scripts/live_setup.sh, which runs during the pre-init phase.

Extracting Binaries from the APK

The live setup script extracts the native libraries from the Magisk APK and restructures them as executable commands. Rather than copying multiple files, Magisk creates symbolic links that point various command names to the core magisk binary or its specialized tools:


# scripts/live_setup.sh

# Extract binaries from the APK for the target ABI

unzip -oj magisk.apk "lib/$ABI/*" -x "lib/$ABI/libbusybox.so"

# Create symlinks for the main utilities

ln -s ./magisk $MAGISKTMP/su
ln -s ./magisk $MAGISKTMP/resetprop
ln -s ./magiskpolicy $MAGISKTMP/supolicy

Here, su and resetprop are symlinked to the main magisk binary, which acts as a multi-call binary (similar to BusyBox) and changes behavior based on argv[0]. The magiskpolicy tool is linked separately as supolicy to maintain compatibility with legacy scripts while providing SELinux policy manipulation capabilities.

Injecting the Mount Point into the Global PATH

With the binaries in place, the final step ensures that shell sessions and spawned processes find the Magisk versions before any stock implementations in /system/bin or /vendor/bin.

Prepending MAGISKTMP to PATH

Immediately after creating the mount, native/src/init/mount.cpp modifies the global PATH environment variable by prepending $MAGISKTMP to the existing value:

// native/src/init/mount.cpp – after mounting /magisk
char *old_path = getenv("PATH");
char *new_path;
asprintf(&new_path, "%s:%s", getenv("MAGISKTMP"), old_path ? old_path : "/system/bin");
setenv("PATH", new_path, 1);

This operation uses asprintf to construct a new string with the format /magisk:<original_path>, then calls setenv() with the overwrite flag set to 1. Consequently, any process spawned from this environment—including app_process, shell sessions, and system services—inherits a PATH that resolves su, resetprop, and magiskpolicy to /magisk/ first.

System-Wide Binary Resolution

The PATH modification happens early enough in the boot sequence that the Android runtime itself inherits these variables. When an application or script calls su, the shell searches directories in the order specified by PATH, finding /magisk/su before /system/bin/su. This mechanism allows Magisk to provide root access and property manipulation without altering the immutable system partition or triggering SafetyNet flags related to system modifications.

Summary

  • Magisk creates a temporary tmpfs at /magisk during early init via magiskinit, exporting the path as MAGISKTMP in native/src/init/mount.cpp.
  • Binaries are extracted and linked by scripts/live_setup.sh, which creates symlinks for su, resetprop, and magiskpolicy pointing to the core Magisk binary or its policy tool.
  • PATH manipulation occurs in native code by prepending $MAGISKTMP to the existing PATH variable, ensuring all child processes prioritize Magisk binaries over stock alternatives.
  • No system partition modification is required, as the entire injection relies on runtime environment variables and a volatile mount point that disappears on reboot.

Frequently Asked Questions

Why does Magisk use a tmpfs mount instead of directly modifying /system?

Magisk avoids modifying the /system partition to maintain a "systemless" approach that does not alter the cryptographic hash of the read-only filesystem. By using a tmpfs mount at /magisk and modifying the PATH variable, Magisk intercepts binary calls without changing the underlying system image, allowing it to pass SafetyNet and similar integrity checks while still providing root access.

How does the PATH modification persist across different process forks?

The setenv("PATH", new_path, 1) call in native/src/init/mount.cpp executes in the context of magiskinit, which becomes the ancestor of the main Android init process. Because environment variables are inherited by child processes through fork() and exec(), the modified PATH propagates automatically to the Zygote, system server, and all application processes without requiring additional injection code in each process.

magiskpolicy is the dedicated binary for manipulating SELinux policies. In scripts/live_setup.sh, the line ln -s ./magiskpolicy $MAGISKTMP/supolicy creates a symlink named supolicy that points to the magiskpolicy executable. This maintains compatibility with legacy SuperSU scripts and modules that expect a supolicy command while using Magisk's modern policy implementation.

Can the MAGISKTMP location be changed from /magisk?

While the current implementation in native/src/init/mount.cpp hardcodes /magisk as the mount point and exports it via MAGISKTMP, changing this would require recompiling magiskinit with a modified path string. The location is fixed at compile time to ensure that live_setup.sh and other components can reliably locate the binary staging area during the pre-init boot phase.

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 →