Skip to main content

syzqemuctl

A command-line tool and Python API for managing QEMU disk images and virtual machines created through Syzkaller's `create-image.sh`.

PyPI - Version PyPI - Downloads GitHub License Codacy grade

Documentation

The repository also ships a portable syzqemuctl Agent Skill for Codex, Claude Code, OpenCode, and other Agent Skills-compatible tools under skills/syzqemuctl.

Features

  • Easy VM creation and management
  • Automated template image creation using syzkaller's create-image.sh
  • SSH and file transfer support
  • Command execution in VMs
  • Guest-side syzkaller temporary artifact cleanup
  • Screen session management for VM console access

See details in Usage section :)

Change Log

Each version without BUG tag is usable.

v0.1.0 ~ v0.1.10
  • 0.1.0: 2025-01-16
    • Initial release (BUG: entry_point is wrong)
  • 0.1.1: 2025-01-16
    • Update README.md (BUG: entry_point is wrong)
  • 0.1.2: 2025-01-17
    • Fix bug of entry point (CLI USABLE NOW!)
  • 0.1.3: 2025-01-17
    • Add badges
  • 0.1.4: 2025-01-20
    • Fix the inconsistencies of README and code (API USABLE NOW!)
  • 0.1.5: 2025-01-21
    • Complete vm.wait_until_ready and update README
  • 0.1.6: 2025-01-21
    • Update version info and try to solve the installation dependency problem
  • 0.1.7: 2025-01-21
    • Fix the installation dependency problem
  • 0.1.8: 2025-01-22
    • Add smart option --version and move some functions to utils.py
  • 0.1.9: 2025-01-22
    • Add safe_decode in execute in vm.py
  • 0.1.10: 2025-01-22
    • Use the kernel in last vm config to start vm by default
v0.2.0 ~ v0.2.9
  • 0.2.0: 2025-04-25
    • Add user friendly instruction for running image and update email
  • 0.2.1: 2025-04-26
    • Add documentation for copy dirs from local to vm
  • 0.2.2: 2025-04-27
    • Add restart for vm and update README
  • 0.2.3: 2025-04-27
    • Set default image size of image-template to 5GB and support --size for creating vm (BUG: size it doesn't work)
  • 0.2.4: 2025-04-27
    • Fix a missing file in creating vm with specified size and optimize printing
  • 0.2.5: 2025-05-01
    • Add security check for command injection
  • 0.2.6: 2025-05-12
    • Add blocking mode for init command
  • 0.2.7: 2025-05-14
    • Improve API usage
  • 0.2.8: 2026-05-05
    • Fix a vm booting bug caused by the cpu inconsistency by adding params in boot_script
  • 0.2.9: 2026-05-11
    • Suppress paramiko SSH noise and expose set_paramiko_logging() for log control
    • Reduce wait_until_ready() default polling interval to 3s and remove redundant is_ready() checks
    • Improve stop() cleanup (screen session, stale pidfile) and fix return semantics
    • Fix bare except: clauses in start() and utils.py, remove noisy prints from is_ready()
v0.3.0 ~ progressing
  • 0.3.0: 2026-05-12
    • Reduce default template size from 5120MB to 3072MB and add --size to init
    • Add template-size cache (image-template-SIZE) for faster create with custom sizes
    • Add --force to create to bypass cache and create from scratch
    • Add is_image_ready() API and .image_ready flag for monitoring image creation
    • Distinguish image vs VM concepts in README and unify examples to my-image
  • 0.3.1: 2026-05-13
    • Add --snapshot flag to run for ephemeral VM sessions (changes discarded on shutdown)
    • Snapshot flag is not inherited from previous boots; specify it explicitly when needed
  • 0.3.2: 2026-05-16
    • Add verbose parameter to VM, ImageManager, and global_conf.initialize()
    • API mode defaults to quiet (verbose=False); informational prints are suppressed while errors are always preserved
    • CLI mode remains verbose (verbose=True) to keep existing user experience
  • 0.3.3: 2026-05-18
    • Add net.ifnames=0 to kernel cmdline for stable guest NIC naming (eth0)
    • Use process substitution (exec > >(tee)) in boot script so QEMU is a direct child of screen
    • Extend start() polling to 30s and add failure cleanup (screen + pidfile)
    • Add explicit banner_timeout and auth_timeout to is_ready() (5s) and connect() (10s)
  • 0.3.4: 2026-05-25
    • Expose public timeout support on VM.execute(), VM.copy_to_vm(), and VM.copy_from_vm()
    • Treat timeout as a total operation limit and keep existing behavior unchanged when omitted
    • Drain stdout and stderr concurrently in VM.execute() to avoid dual-stream blocking on large output
    • Abort the current SSH/SCP connection on timeout so callers can recover with a fresh connect()
    • Extend VM.stop() with wait and force options, and add VM.cleanup_runtime() for strong runtime cleanup
  • 0.3.5: 2026-08-16
    • Add configurable guest kernel command lines through kernel_args and extra_kernel_args in both API and CLI modes
    • Safely quote generated QEMU arguments and stop interpolating dynamic paths into image-creation shell commands
    • Add path-specific screen names, per-image operation locking, exact QEMU/PID ownership checks, startup pre-cleanup, and deletion protection for running images
    • Replace the netstat port scan with socket binding and remove the duplicate SSH handshake from connect()
    • Expose timeout and strong-cleanup controls in the CLI, with non-zero exit status on operation failures
    • Restore tracked unit tests and retain Python 3.8 compatibility
  • 0.3.6: 2026-08-18
    • Add the read-only VM.runtime_diagnostics() API with structured screen, QEMU, pidfile, port, log, and runtime-cleanliness state
    • Bound external runtime checks by a caller-provided timeout and report unavailable state through nullable fields and errors
    • Add RuntimeDiagnostics.to_dict() and summary() for machine-readable records and concise logs
    • Add syzqemuctl diagnose with optional --json and --no-check-port output controls
  • 0.3.7: 2026-08-18
    • Add official MkDocs Material documentation and Read the Docs build configuration
    • Add a portable syzqemuctl Agent Skill with lifecycle and failure-handling guidance
    • Validate documentation and Agent Skill structure in CI
  • 0.3.8: 2026-08-19
    • Adopt PEP 517 package builds while retaining setuptools and Python 3.8 compatibility
    • Document Agent Skill installation for Codex, Claude Code, and OpenCode
    • Add complete English and Simplified Chinese documentation with separate Read the Docs builds
    • Validate wheel, source distribution, and both documentation languages in CI
  • 0.3.9: 2026-09-18
    • Add VM.cleanup_guest_artifacts() for bounded cleanup of common syzkaller and reproducer temporary files inside a connected guest
    • Add syzqemuctl cleanup-guest NAME --timeout 20 for the same operation from the CLI
    • Keep guest filesystem cleanup separate from host-side VM stop, runtime cleanup, and diagnostics
TODOs
  • Merge global_conf into ImageManager

Installation

pip install syzqemuctl

Requirements

python3.8+ qemu screen ssh  

Configuration

The configuration file is stored in ~/.config/syzqemuctl/settings.json. It contains:

  • Images home directory path
  • Default VM settings

Concepts

  • Image: A QEMU disk image (e.g., bullseye.img) created by create-image.sh. Images are stored as directories under IMAGES_HOME.
  • VM: A running QEMU virtual machine booted from an image with a specified kernel. A VM shares the same name as its underlying image directory.

Usage

⭐ As a command-line tool (CLI)

You can check the usage of syzqemuctl or syzqemuctl CMD by adding --help. Here are some common uses:

  1. Initialize syzqemuctl:
syzqemuctl init --images-home /path/to/images
  1. Create a new disk image:
syzqemuctl create my-image [--size 3072]   # --size INT for specifying a custom disk size in MB (copies from default template if omitted)
  1. Run a VM from the image:
syzqemuctl run my-image --kernel /path/to/kernel

Run with snapshot mode (all disk changes discarded on shutdown):

syzqemuctl run my-image --kernel /path/to/kernel --snapshot

Append case-specific arguments to the saved command line, or to the default command line on first boot:

syzqemuctl run my-image --kernel /path/to/kernel \
  --extra-kernel-args "systemd.unified_cgroup_hierarchy=0"

Use --kernel-args "..." instead to replace the complete guest kernel command line. Explicit kernel arguments are stored in boot.sh and reused by later starts unless new arguments are supplied.

  1. Check image/VM status:
syzqemuctl status my-image
  1. Copy files/dir to/from VM:
syzqemuctl cp --timeout 600 local_file my-image:/remote/path  # Copy to VM
syzqemuctl cp --timeout 600 my-image:/remote/file local_path  # Copy from VM

syzqemuctl cp local_dir my-image:/remote/       # Copy local_dir to VM
syzqemuctl cp local_dir/ my-image:/remote/      # Copy local_dir/* to VM
  1. Execute commands in VM:
syzqemuctl exec --timeout 30 my-image "uname -a" # You'd better wrap the command with double quotes
  1. Remove common temporary artifacts left by an earlier syzkaller reproducer:
syzqemuctl cleanup-guest my-image --timeout 20

This command requires a running, SSH-ready VM. It does not stop the VM or clean host-side runtime resources.

  1. Stop the VM:
syzqemuctl stop my-image
syzqemuctl stop my-image --wait --force --timeout 20
  1. Restart the VM:
syzqemuctl restart my-image
  1. Diagnose VM runtime resources without changing them:
syzqemuctl diagnose my-image
syzqemuctl diagnose my-image --timeout 5 --json
  1. List all images:
syzqemuctl list
  1. Delete the image:
syzqemuctl delete my-image

A running image must be stopped before it can be deleted.

⭐ As a Python package (API)

from syzqemuctl import global_conf, ImageManager, VM

images_home = "/path/to/images_home"
# API defaults to quiet (verbose=False); pass verbose=True to see informational prints
global_conf.initialize(images_home, force=False)
manager = ImageManager(images_home)
manager.initialize(force=False)
manager.create("my-image")

# Or just direct specify a created image and run a VM from it
# Use verbose=True if you want to see boot script and screen session tips
vm = VM("/path/to/images_home/my-image")
vm.start(
    kernel="/path/to/kernel",
    extra_kernel_args="systemd.unified_cgroup_hierarchy=0",
)

# Use kernel_args="..." to replace the complete guest kernel command line.
# start() cleans stale runtime belonging to this image before launching QEMU.

# Wait several minutes for the VM to be ready, or you can check by:
if vm.is_ready():
    pass

# Or use this API to wait:
if vm.wait_until_ready(timeout=180):
    pass

# You need to use this context manager to auto-connect/disconnect
with vm:
    # Run after the previous workload has stopped and before uploading a new PoC.
    vm.cleanup_guest_artifacts(timeout=20)
    vm.copy_to_vm("/path/to/local/file", "/path/to/vm/remote/file", timeout=600)
    stdout, stderr = vm.execute("uname -a", timeout=30)
    print(f"stdout: {stdout}\nstderr: {stderr}")

# timeout is optional and defaults to None.
# It limits the total duration of a single execute/copy operation.
# After a timeout, reconnect before issuing the next SSH/SCP request.

# Use wait=True and force=True when you need runtime cleanup to fully converge.
vm.stop(wait=True, force=True, timeout=20)
vm.cleanup_runtime(timeout=20)

# force=True is useful after a failed start.
# wait=True is useful before reusing an image.

# Collect a read-only runtime snapshot after start or cleanup failures.
diagnostics = vm.runtime_diagnostics(timeout=5, check_port=True)
print(diagnostics.summary())
record = diagnostics.to_dict()  # JSON/CSV-friendly structured fields

License

Apache-2.0

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Metadata

Release files for syzqemuctl 0.3.9

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for syzqemuctl 0.3.9
File Size Uploaded
syzqemuctl-0.3.9.tar.gz 80.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for syzqemuctl 0.3.9
File Interpreter ABI Platform
syzqemuctl-0.3.9-py3-none-any.whl Python 3 none any Details

Total release size: 112.8 kB

Release files / syzqemuctl-0.3.9.tar.gz

Download URL syzqemuctl-0.3.9.tar.gz
Size 80.5 kB
Tags Source
SHA-256 checksum
How to use checksums
db3ea62f5a3a902f7bfdaea164e206771cbbd6b3cd56e3fcc969ca911e0802da
BLAKE2b-256 checksum
How to use checksums
95cea151fab3476f1a8a723e441aa531a32b44d7564f85a37c4807799e1a74ff
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.8

Release files / syzqemuctl-0.3.9-py3-none-any.whl

Download URL syzqemuctl-0.3.9-py3-none-any.whl
Size 32.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
703dfd29dc3e07aebda453fe525c4f6d0a7222d3585347b7390874d46d71ff60
BLAKE2b-256 checksum
How to use checksums
1ef1768f5023d452ffdc85b44a04406c19f42228aea41082eb8d7ce4227d6333
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.8

Release history Release notifications | RSS feed

0.4.0

2 release files

This release

0.3.9 This release

2 release files

0.3.8

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

1 release file

0.3.3

1 release file

0.3.2

1 release file

0.3.1

1 release file

0.3.0

1 release file

0.2.9

1 release file

0.2.8

1 release file

0.2.7

1 release file

0.2.6

1 release file

0.2.5

1 release file

0.2.4

1 release file

0.2.3

1 release file

0.2.2

1 release file

0.2.1

1 release file

0.2.0

1 release file

0.1.10

1 release file

0.1.9

1 release file

0.1.8

1 release file

0.1.7

1 release file

0.1.6

1 release file

0.1.5

1 release file

0.1.4

1 release file

0.1.3

1 release file

0.1.2

1 release file

0.1.1

1 release file

0.1.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page