Skip to content
KernelSU Modules

NoMount

Metamodule Immutable release Synced

A kernel-level VFS path redirection metamodule for KernelSU and APatch.

Description

NoMount

WARNING: This project operates directly at the kernel VFS layer and is intended for research and development. Proceed with caution.

NoMount is a VFS (Virtual File System) path redirection framework for Android kernels.

Unlike traditional mount solutions like Magic Mount or OverlayFS that rely on modifying the mount table and polluting /proc/mounts, NoMount operates purely in RAM. Instead of making a real mount, it intercepts path resolution and directory iteration dynamically, making file injections completely transparent to the Android system and userspace apps without generating any mounts.

View Screenshots
Home Status Modules List
Home Status Modules List
Exclusions Empty Exclusions Active
Exclusions Empty Exclusions Active
App Selector Manual UID Entry
App Selector Manual Entry
Options Installation
Options Installation

How it Works

When you set up a redirection, you provide two paths: the original file the system expects to find (e.g., /vendor/etc/audio.conf), and your modified file located elsewhere (e.g., /data/local/tmp/mod.conf).

Instead of applying global hooks in-kernel that affect the whole system, NoMount specifically modifies the directory operations of the target path directly in the RAM cache. When an application requests the original file, NoMount intercepts the call and creates a fake file representation in RAM. Once the application opens this file, NoMount internally opens your real modified file in the background and links them together. From that exact moment, any read, memory mapping (mmap), or data operation performed by the application is forwarded to your real file. The application reads the modified content naturally, completely unaware of the redirection.

NoMount also takes control of directory iteration. This allows you to inject entirely new files into existing system directories or completely hide existing ones (known as whiteouts). When an app or a terminal command like ls tries to list the contents of a directory, NoMount dynamically injects the new entries or omits the hidden ones, reflecting the changes in file lists and system calls. Also NoMount includes a dedicated UID filter. Before any path interception occurs, NoMount checks the process ID of the application making the request. If the app's UID is flagged (such as a banking app or an root detector), NoMount simply steps aside and lets the kernel resolve the path normally. The isolated app will see the stock, untouched filesystem.

This approach makes NoMount highly compatible with both read-only partitions (like erofs) and read-write partitions (like ext4), because the underlying partition is never modified. Furthermore, all communication between the userspace tool and the kernel is handled via the Linux keyring subsystem (add_key), completely bypassing the complications of traditional /dev nodes and IOCTL commands.

How to Use It (Metamodule)

NoMount is distributed as a Metamodule for KernelSU (and forks) and APatch (and forks). This means it acts as a master module that dynamically intercepts and manages the mounting process of other standard modules in your system.

The NoMount module includes a built-in WebUI that allows you to easily control the kernel subsystem without touching the terminal:

  • Hot Load/Unload: Enable or disable modules on the fly without rebooting.
  • App Exclusion (UID Isolation): Select specific apps (like banking apps or anti-cheats) from a list. The WebUI extracts their UID and isolates them, ensuring they only see the stock, untouched filesystem.
  • Global Flush: Instantly clear all redirection rules.

Do I need a custom kernel?

Since NoMount operates at the VFS layer, it requires kernel-level integration. However, how you get this integration depends on your device:

  • Standard GKI Kernels (5.10+): You DO NOT need to modify your kernel. The NoMount release ZIP includes pre-compiled LKMs (Loadable Kernel Modules) that will inject the VFS subsystem automatically upon flashing.
  • Legacy Kernels (< 5.10) and Strict Kernels: If you are on an older kernel (e.g., 4.14, 4.19) or a strictly locked kernel (e.g., Sultan kernels with CONFIG_INTEGRATED_MODULES=y), the pre-compiled LKMs will not load. You will need to integrate NoMount directly into your kernel source or compile a specific LKM for your device.

For detailed instructions on how to patch your kernel source or compile a custom LKM, please read kernel/README.md.

How to Install the NoMount Metamodule

If your kernel already has NoMount integrated, or if you plan to use the included / compiled LKM, simply download the latest module from Releases or the Nightly builds (dev branch). Flash it via KernelSU/APatch and reboot your device.

After rebooting, just install your favorite modules (like audio mods or system tweaks) in KernelSU/APatch exactly as you normally would. NoMount's Metamodule will automatically intercept them at boot and use VFS injection instead of traditional mounts.

How to Use It (Binary)

The subsystem is controlled via the nm binary. The CLI uses a simple command structure.

Command Description
nm rule add <virtual> <real> Inject real file at virtual path.
nm rule add --whiteout <virtual> Hide the file/directory at virtual path.
nm rule del <virtual> Remove a specific injection rule.
nm uid add <uid> Isolate UID. The app will see the stock filesystem.
nm uid del <uid> Remove isolation for UID.
nm rule list Show currently active injection rules.
nm rule list --json Show currently active injection rules in JSON format.
nm uid list Show currently isolated UIDs.
nm clear all Flush all rules and UID blocks immediately.
nm version Show the kernel subsystem version.

Examples

Inject a custom library:

# The system thinks libfoo.so is in /vendor, but it loads from /data
nm rule add /vendor/lib64/soundfx/libfoo.so /data/local/tmp/my_lib.so

Hide a file completely (Whiteout):

# Make the system think this configuration file does not exist
nm rule add --whiteout /system/etc/hidden_config.xml

Hide modifications from a specific app:

# App with UID 10256 will see the untouched filesystem, bypassing detection
nm uid add 10256

Note: Because NoMount operates entirely in RAM, manual rules or modifications created via the CLI are lost upon reboot. The metamodule handles the persistent injection of your installed modules automatically during the boot process.

Special Thanks

  • Kasumi: Inspiration for this project.
  • ZQZCC: WebUI MD3E-style design.
  • backslashxx: Code optimization.
  • KernelSU: Root solution.
  • All testers and contributors: Thanks for testing this project and helping to make it stable.

License

  • Files under kernel directory are GPL-2
  • All other parts except kernel directory are GPL-3

Disclaimer

NoMount is a kernel modification tool intended for research and development. Modifying kernel behavior carries inherent risks. The developers are not responsible for bricked devices, data loss, or thermonuclear war.

Releases

v2.2.0 (605)

Latest NoMount v2.2.0

Version code 605 v2.2.0

Download

NoMount v2.2.0 is here!🎉

This release brings UID-scoped rules, opaque directory redirection, .remove support, and the biggest hot-path optimization pass we've ever shipped. The kernel driver and the metamodule must be updated together.

Commit count hit 605 on this release. Driver protocol is now v22. Thanks to everyone who kept reporting, bisecting and testing through the rough week 💙

Small Changelog:

  • kernel/:

    • Wire protocol v22. nm_rule_hdr grew from 16 to 24 bytes and nm_del_hdr from 10 to 18 to fit the new UID range fields. A v22 CLI cannot talk to a v21 driver (and vice versa); the installer aborts if the running driver is older than v22.
    • UID-scoped rules with ranges: --uid-range 1000-5000 and --uid-range all. A single rule now covers a whole range without enumerating every UID.
    • UID deny sub-ranges: --uid-excluded 3000-4000. Combine it with --uid-range for [1000,5000] except [3000,4000], or use it alone as "default except this range". Rules with the same target range but different denies are rejected with -EEXIST; overlap between ranges is rejected too.
    • Opaque directories: --opaque. A directory rule can hide the underlying filesystem entirely and only expose the module's leaves. This is what .replace with content actually meant: previously it whiteouted the whole directory and bootlooped when the hidden dir was a system app the framework needed.
    • Pseudo filesystems (proc, sysfs, devpts, debugfs, tracefs, selinuxfs, cgroup, bpf) are no longer hijacked at the dentry level.
    • Skip d_op installation on dentries that have no rule for their name. This is the biggest change in the release: it removes the d_revalidate tax on every non-rule lookup under a hijacked directory, which is most of them.
    • Skip d_op installation on dentries in pseudo filesystems, and skip the shrink_dcache_parent pass when invalidating a single injected name. The nm_hijack_dentry_ops publication now uses smp_store_release and a single d_flags write.
    • Hot-path micro-optimizations, reorder nm_dir_ops so the hot fields fit in one cache line, avoid current_fsuid() when the leaf is NULL, skip nm_is_uid_blocked() and nm_find_leaf_in_dir() when there is no leaf or no children, short-circuit nm_dir_lookup and nm_d_revalidate_common on directories without rules.
    • nm_d_revalidate_common no longer reads dentry->d_op or inode->i_op when it does not need them, and chains to the original d_revalidate when the underlying filesystem has one.
    • On unload, walk i_dentry to clear d_op before freeing module memory. Fixes the panic on rmmod with files open on virtual paths.
    • iget5_locked hits no longer allocate an nm_inode_info; the probe uses a stack struct and kmalloc only happens for I_NEW. d_add instead of d_splice_alias for fresh file inodes.
    • Probe xattr_handler->__get via header grep instead of LINUX_VERSION_CODE, so kernel trees that never backported the member compile again.
    • inode_state_read_once for I_NEW checks (mainline >=6.19 compatibility).
    • Deferred reclaim of rules and leaves moved fully to process context. nm clear rules no longer blocks on synchronize_rcu.
    • Internal naming unified to the nm_ prefix.
  • userspace/:

    • --uid-range <a>-<b>, --uid-range all, --uid-excluded <c>-<d>, and --opaque flags.
    • nm rule list prints [UID: a-b excl c-d] and emits "opaque": true in the JSON output.
    • Streamlined absolute path handling, chunked output for large rule lists.
  • module/:

    • common.sh holds the boot pipeline: bootloop detection keyed on /proc/sys/kernel/random/boot_id, LKM loading, module disable. post-fs-data.sh and metamount.sh are thin wrappers over it.
    • Boot order is now correct on both KernelSU and APatch. The previous flow silently lost rules on APatch (and sometimes in KernelSU with specific setups) because metamount.sh ran before the LKM was loaded.
    • Bootloop detection no longer relies on .booting existence; a successful boot clears the file, a failed boot keeps the boot_id and the next boot disables the module.
    • .remove support: Magisk's .remove marker is recognized alongside .replace (.replace with content → opaque rule, .replace alone → whiteout, .remove → whiteout). rule-paths.sh gains path, pair, opaque and del kinds, and both metamount.sh and the WebUI's hot load/unload use the same flow. Hot unload now deletes opaque rules too.
    • x86_64 build support: new CI matrix entry, lkmloader-x86_64, nm-x86_64, and ARCH_BIN normalization for KernelSU's x64 label.
    • Installer aborts if the running driver is below v22, and falls back to the previous LKM if a v22 KO is staged for the next boot. Reboot is required to activate the new driver in LKM mode.
  • webui/:

    • Skip / Unskip button on each module card (creates or deletes skip_mount).
    • Persist the "Show system apps" toggle across reloads.
    • Back gesture closes the right dialog in every navigation state (fixed double back navigation).
    • AMOLED palette adjustments and clear button corner fix.

and a lot of other misc changes :)

Thanks to everyone who kept testing, contributing and reporting through the rough bits: @ZQZCC, @nleloc, @sohan-f, and the testers on the Telegram group 🫂

Full Changelog: https://github.com/maxsteeel/nomount/compare/v2.1.1...v2.2.0

Assets 1

NoMount-v2.2.0-release-605.zip 457.8 KiB

SHA-256 d40277cb8f495b78711fb72e5f19a79ab2627eba2f0eb2aec60b5fc8019fae83 · Attestations

Transparency

Repository
maxsteeel/nomount
Tag
v2.2.0 Immutable release
Tag commit
bf1847f98fed
Content commit
bf1847f98fed
SHA-256
d40277cb8f495b78711fb72e5f19a79ab2627eba2f0eb2aec60b5fc8019fae83
Last change synced

Verify it yourself

KernelSU Modules does not sign or audit modules. The SHA-256 only proves the download matches this index. Verify the release yourself with the GitHub CLI:

gh release verify v2.2.0 -R maxsteeel/nomount
gh release verify-asset v2.2.0 NoMount-v2.2.0-release-605.zip -R maxsteeel/nomount