Skip to content

maxsteeel/Mirage

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

46 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Mirage

Mirage is a stackable virtual filesystem designed specifically for Android environments. Built upon the foundation of WrapFS (originally by Erez Zadok), Mirage has been extensively re-engineered to provide transparent file and directory redirection.

Unlike overlayfs or standard bind mounts, Mirage operates entirely within the VFS (Virtual File System) layer, presenting itself as a native virtual filesystem. This makes it invisible to conventional mount scanners while providing robust support for modern Android kernel architectures (3.x through 5.x+).

Key Features

  • Dynamic File Injection (Magic Mount): Intercepts path resolution (lookup.c) at the VFS layer. Allows mounting a legitimate system directory while silently substituting specific files inside it (e.g., replacing an APK) on-the-fly.
  • Full R/W and Database Support: Fully implements operations like rename, rmdir, mkdir, and symlink. This ensures complex applications and SQLite databases (which rely heavily on atomic renames via journal files) function flawlessly without ENOSYS crashes.
  • SELinux Context Preservation: Implements full extended attributes (xattr) forwarding. System services can read and write SELinux contexts (u:object_r:...) to injected files transparently.
  • Memory Safety: Engineered with strict RCU-safe inode destruction, atomic reference counting, and deep dentry cache synchronization to prevent memory leaks and kernel panics during unmount operations.

Usage Guide

Mirage supports three primary methods of operation, depending on the complexity of the redirection required.

1. Direct File Injection (1-to-1)

This method allows you to mount a modified file directly over an existing system file.

Syntax:

mount -t mirage none <parent_dir> -o source=<source_file>,target=<target_file_to_shadow>

Example:

mount -t mirage none /system/etc -o source=/data/local/tmp/hosts,target=/system/etc/hosts

Note: I recommend to use none as the source device. The source= option specifies the replacement file, and target= specifies which file to shadow. Mirage will transparently substitute the target file with the source file until unmounted.

2. Magic Mount (Directory Injection)

This advanced method mounts a target directory over itself but instructs the kernel to silently intercept and replace a specific file inside that directory. This maintains the structural integrity of the directory while spoofing a single component.

Syntax:

mount -t mirage none <target_directory> -o lowerdir=<target_directory>,inject_name=<file_to_intercept>,inject_path=<source_file>

Example:

mount -t mirage none /system/app/YouTube -o lowerdir=/system/app/YouTube,inject_name=base.apk,inject_path=/data/local/tmp/modded_youtube.apk

In this scenario, if a user or system process lists the directory (ls /system/app/YouTube), it appears normal. However, if a process attempts to open() or mmap() the file base.apk, Mirage will transparently serve the file located at /data/local/tmp/modded_youtube.apk.

3. Union/Overlay Mount (Directory Merging)

This method acts similarly to overlayfs and unionfs. It allows you to merge multiple lower directories (separated by colons) and an optional upper directory, presenting their unified contents at the mount point.

Syntax:

mount -t mirage none <mount_point> -o [upperdir=<upper_path>,]lowerdir=<lower_path1>:<lower_path2>...

Example:

mount -t mirage none /mnt/merged -o upperdir=/data/upper,lowerdir=/data/lower1:/data/lower2

In this scenario:

  • A file created or modified in /mnt/merged will actually be modified in the upperdir (/data/upper).
  • If a user lists (ls /mnt/merged), they will see a deduplicated list of files present in /data/upper, /data/lower1, and /data/lower2.
  • If a file exists in multiple layers with the same name, the file from the highest layer (e.g. upperdir, or the first lowerdir in the list) shadows the ones below it.
  • A maximum of 5 branches are supported at once.

Unmounting

To safely remove the injection and restore the original file visibility without rebooting:

umount <target_file_or_directory>

Architecture & Development

Mirage acts as a proxy layer between the VFS and the lower underlying filesystem (e.g., ext4, f2fs).

Core Components

  • super.c: Handles mount argument parsing, superblock allocation, and lifecycle management. It initializes the lower filesystem bindings and manages reference counters (s_active) to prevent lower filesystem unmounting while Mirage is active.
  • lookup.c: The core of the "Magic Mount" capability. It utilizes iget5_locked for safe, race-free inode caching and implements the VFS interception logic to route specific qstr lookups to alternative physical paths.
  • inode.c: Handles metadata and structural modifications. Forwarding functions (mirage_vfs_create, mirage_vfs_rename, mirage_vfs_setxattr) ensure that upper-layer metadata requests accurately reflect and modify the lower filesystem.
  • file.c & mmap.c: Manages data I/O. Uses localized VMA structure cloning during fault and page_mkwrite operations to guarantee stability when heavily multi-threaded Android applications map files into memory.
  • compat.h: A robust compatibility layer containing preprocessor macros to bridge API changes across different Linux kernel versions (from legacy 3.x mechanisms to modern 5.4+ i_version atomics and iterate_shared paradigms).

Compilation

Mirage is designed to be integrated directly into your Android kernel source tree. You can do this automatically (recommended) or manually.

1. Automatic Integration (Recommended)

The fastest way to integrate Mirage into your kernel tree is using our setup script. Run this command from the root of your kernel source:

curl -LSs "https://raw.githubusercontent.com/maxsteeel/Mirage/master/setup.sh" | bash -

This script will:

  • Clone the repository.
  • Create a symbolic link in fs/mirage.
  • Automatically configure fs/Kconfig and fs/Makefile.

2. Manual Integration

If you prefer to do it yourself:

  1. Clone this repository into your kernel source as fs/mirage/.
  2. Add the following line to fs/Kconfig before the last endmenu:
source "fs/mirage/Kconfig"

  1. Add the following line to fs/Makefile:
obj-$(CONFIG_MIRAGE) += mirage/

3. Building

Once integrated, you can build it in two ways:

As a loadable module (.ko):

make -C <path_to_kernel_source> M=fs/mirage modules

Built-in: Enable the driver in your defconfig or via menuconfig:

  • File systems ---> Mirage VFS support Set CONFIG_MIRAGE=y.

Credits and Acknowledgements

  • Erez Zadok & File Systems and Storage Lab (Stony Brook University): For the original research and development of WrapFS, which provided the foundational boilerplate for stackable filesystems in Linux.

License

This project is licensed under the GNU General Public License v3.0 (GPL-3.0). See the source files for detailed copyright notices.

About

A transparent stackable virtual filesystem for Android content redirection. Based on WrapFS.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors