Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/angr/angr/llms.txt

Use this file to discover all available pages before exploring further.

The filesystem plugin (SimFilesystem) provides a virtual filesystem for angr states. It manages files, directories, and mountpoints, allowing symbolic execution to interact with file paths and contents. It’s accessible via state.fs.

Overview

The filesystem plugin provides:
  • File and directory management
  • Path normalization and resolution
  • Mountpoint support for special filesystems
  • Integration with POSIX file operations
  • Support for concrete and symbolic file access

Core Properties

pathsep
bytes
default:"b'/'"
Path separator character used for this filesystem.
cwd
bytes
Current working directory path.
List of (path, SimFile) tuples for deleted files (for tracking purposes).
# Get current settings
print(f"Path separator: {state.fs.pathsep}")
print(f"Working directory: {state.fs.cwd}")

# Change working directory
state.fs.chdir(b"/home/user")

File Operations

get

get(path)
Retrieve a file from the filesystem.
path
str | bytes
Path to the file (relative or absolute).
return
SimFile | None
The file object, or None if not found.
# Get a file
file = state.fs.get(b"/etc/passwd")
if file:
    content = file.concretize()
    print(content)

# Relative path (uses cwd)
file = state.fs.get(b"config.txt")

insert

insert(path, simfile)
Insert a file into the filesystem.
path
str | bytes
Path where the file should be stored.
simfile
SimFile
The file object to insert.
return
bool
True if successful, False otherwise.
from angr.storage.file import SimFile

# Create and insert a file
file = SimFile(b"myfile", content=b"Hello, World!")
if state.fs.insert(b"/tmp/myfile", file):
    print("File inserted successfully")

# Insert with symbolic content
sym_content = state.solver.BVS('file_content', 64 * 8)
file = SimFile(b"data", content=sym_content, size=64)
state.fs.insert(b"/tmp/data", file)

delete

delete(path)
Delete a file from the filesystem.
path
str | bytes
Path to the file to delete.
return
bool
True if successful, False if file not found.
# Delete a file
if state.fs.delete(b"/tmp/myfile"):
    print("File deleted")
    
    # Deleted files are tracked
    for path, file in state.fs.unlinks:
        print(f"Deleted: {path}")

Directory Operations

chdir

chdir(path)
Change the current working directory.
path
str | bytes
New working directory path.
# Absolute path
state.fs.chdir(b"/home/user")

# Relative path
state.fs.chdir(b"Documents")
print(state.fs.cwd)  # b'/home/user/Documents'

# Parent directory
state.fs.chdir(b"..")
print(state.fs.cwd)  # b'/home/user'

Path Normalization

Paths are automatically normalized:
  • Converts to absolute paths
  • Resolves . (current dir) and .. (parent dir)
  • Removes duplicate separators
  • Removes trailing separators
# These all resolve to b'/home/user/file.txt'
state.fs.get(b"/home/user/./file.txt")
state.fs.get(b"/home/user/subdir/../file.txt")
state.fs.get(b"/home//user///file.txt")

Mountpoints

Mountpoints allow custom filesystem behavior for specific paths.

mount

mount(path, mount)
Mount a filesystem at a specific path.
path
str | bytes
Mount point path.
mount
SimMount
The mount object to attach.
from angr.state_plugins.filesystem import SimHostFilesystem

# Mount host filesystem
host_fs = SimHostFilesystem(host_path='/tmp')
state.fs.mount(b"/mnt/host", host_fs)

# Access files from host
file = state.fs.get(b"/mnt/host/data.txt")

unmount

unmount(path)
Remove a mountpoint.
path
str | bytes
Path to unmount.
state.fs.unmount(b"/mnt/host")

get_mountpoint

get_mountpoint(path)
Find the mountpoint servicing a path.
path
str | bytes
Path to lookup.
return
tuple
(mount, path_elements) where mount is the SimMount and path_elements is the path within the mount.
mount, elements = state.fs.get_mountpoint(b"/mnt/host/subdir/file.txt")
if mount:
    print(f"Mount found, remaining path: {elements}")
    # elements = [b'subdir', b'file.txt']

Built-in Mounts

The POSIX plugin automatically creates special mounts:

/dev (PosixDevFS)

Provides access to standard streams:
# These map to stdin/stdout/stderr
stdin = state.fs.get(b"/dev/stdin")   # FD 0
stdout = state.fs.get(b"/dev/stdout") # FD 1
stderr = state.fs.get(b"/dev/stderr") # FD 2

/proc (PosixProcFS)

Provides process information:
# Read system uptime
uptime = state.fs.get(b"/proc/uptime")
if uptime:
    content = uptime.concretize()
    print(content)  # b'0 0'

Mount Types

SimMount

Base class for creating custom mounts.
from angr.state_plugins.filesystem import SimMount

class MyMount(SimMount):
    def get(self, path_elements):
        # Return SimFile or None
        pass
    
    def insert(self, path_elements, simfile):
        # Return True if successful
        pass
    
    def delete(self, path_elements):
        # Return True if successful
        pass
    
    def lookup(self, sim_file):
        # Return path string or None
        pass

SimHostFilesystem

Mount that provides access to the host filesystem.
from angr.state_plugins.filesystem import SimHostFilesystem

# Mount host /tmp to guest /host_tmp
host_tmp = SimHostFilesystem(host_path='/tmp')
state.fs.mount(b"/host_tmp", host_tmp)

# Read actual files from host
file = state.fs.get(b"/host_tmp/test.txt")
if file:
    print(file.concretize())
host_path
str
Path on the host system to expose.
pathsep
str
default:"os.path.sep"
Host path separator.

SimConcreteFilesystem

Abstract base class for filesystems that lazily load files.
class MyLazyFS(SimConcreteFilesystem):
    def _load_file(self, guest_path):
        # Load file from somewhere
        content = load_from_database(guest_path)
        if content:
            return SimFile(guest_path.encode(), content=content)
        return None

Examples

Creating a Virtual Filesystem

import angr
from angr.storage.file import SimFile

project = angr.Project('/bin/true')
state = project.factory.entry_state()

# Create directory structure
state.fs.insert(b"/etc/passwd", SimFile(
    b"passwd",
    content=b"root:x:0:0:root:/root:/bin/bash\n"
))

state.fs.insert(b"/etc/hosts", SimFile(
    b"hosts",
    content=b"127.0.0.1 localhost\n"
))

state.fs.insert(b"/tmp/data.txt", SimFile(
    b"data",
    content=b"Important data\n"
))

# Access files
passwd = state.fs.get(b"/etc/passwd")
print(passwd.concretize())

Working with Symbolic Files

# Create symbolic file content
file_size = 256
sym_content = state.solver.BVS('config_file', file_size * 8)

file = SimFile(
    b"config",
    content=sym_content,
    size=file_size
)
state.fs.insert(b"/etc/config", file)

# Add constraints on file content
file_bv = state.fs.get(b"/etc/config").content
state.solver.add(file_bv[0:8] == ord('['))  # Must start with '['
state.solver.add(file_bv[8:16] == ord('s'))  # Second char is 's'

# Solve for valid file content
valid_content = state.solver.eval(file_bv, cast_to=bytes)
print(valid_content[:10])

Mounting Host Filesystem

from angr.state_plugins.filesystem import SimHostFilesystem

# Mount host directory
host_fs = SimHostFilesystem(host_path='/etc')
state.fs.mount(b"/host_etc", host_fs)

# Read actual host files
passwd = state.fs.get(b"/host_etc/passwd")
if passwd:
    content = passwd.concretize()
    print("Actual /etc/passwd:")
    print(content.decode())

Tracking File Operations

# Create a file
state.fs.insert(b"/tmp/test", SimFile(b"test", content=b"data"))

# Delete it
state.fs.delete(b"/tmp/test")

# Check deletion history
for path, deleted_file in state.fs.unlinks:
    print(f"Deleted: {path}")
    print(f"Content was: {deleted_file.concretize()}")

Custom Mount Implementation

from angr.state_plugins.filesystem import SimMount
from angr.storage.file import SimFile

class MemoryMount(SimMount):
    """Mount that stores files in a dictionary"""
    
    def __init__(self):
        super().__init__()
        self.files = {}
    
    def get(self, path_elements):
        key = b'/'.join(path_elements)
        return self.files.get(key)
    
    def insert(self, path_elements, simfile):
        key = b'/'.join(path_elements)
        self.files[key] = simfile
        return True
    
    def delete(self, path_elements):
        key = b'/'.join(path_elements)
        return self.files.pop(key, None) is not None
    
    def lookup(self, sim_file):
        for key, file in self.files.items():
            if file == sim_file:
                return key
        return None

# Use the custom mount
mem_fs = MemoryMount()
state.fs.mount(b"/memory", mem_fs)

state.fs.insert(b"/memory/file1", SimFile(b"f1", content=b"data1"))
state.fs.insert(b"/memory/file2", SimFile(b"f2", content=b"data2"))

Integration with POSIX open()

from angr.storage.file import Flags

# Files in filesystem can be opened via POSIX
state.fs.insert(b"/tmp/secret.txt", SimFile(
    b"secret",
    content=b"password123"
))

# Open through POSIX interface
fd = state.posix.open(b"/tmp/secret.txt", Flags.O_RDONLY)
if state.solver.eval(fd) >= 0:
    fd_obj = state.posix.get_fd(state.solver.eval(fd))
    data = fd_obj.read(11)
    print(state.solver.eval(data, cast_to=bytes))  # b'password123'

State Options

Filesystem behavior can be modified with state options:
from angr import sim_options as so

# All file accesses succeed (creates symbolic files on demand)
state.options.add(so.ALL_FILES_EXIST)

# File existence is symbolic (may or may not exist)
state.options.add(so.ANY_FILE_MIGHT_EXIST)

# Neither option: files must exist in filesystem to be opened

See Also