A command-line tool for managing QEMU disk images and virtual machines created through Syzkaller's `create-image.sh`.
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
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
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/config.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:
Initialize syzqemuctl:
syzqemuctl init --images-home /path/to/images
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)
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
Check image/VM status:
syzqemuctl status my-image
Copy files/dir to/from VM:
```bash
syzqemuctl cp local_file my-image:/remote/path # Copy to VM
syzqemuctl cp 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
6. Execute commands in VM:
```bash
syzqemuctl exec my-image "uname -a" # You'd better wrap the command with double quotes
Stop the VM:
syzqemuctl stop my-image
Restart the VM:
syzqemuctl restart my-image
List all images:
syzqemuctl list
Delete the image:
syzqemuctl delete my-image
⭐ 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")
# 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:
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.
License
Apache-2.0
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
syzqemuctl
A command-line tool for managing QEMU disk images and virtual machines created through Syzkaller's `create-image.sh`.
Features
Change Log
Each version without
BUGtag is usable.v0.1.0 ~ v0.1.10
v0.2.0 ~ v0.2.9
set_paramiko_logging()for log controlwait_until_ready()default polling interval to 3s and remove redundantis_ready()checksstop()cleanup (screen session, stale pidfile) and fix return semanticsexcept:clauses instart()andutils.py, remove noisy prints fromis_ready()v0.3.0 ~ progressing
--sizetoinitimage-template-SIZE) for fastercreatewith custom sizes--forcetocreateto bypass cache and create from scratchis_image_ready()API and.image_readyflag for monitoring image creationmy-image--snapshotflag torunfor ephemeral VM sessions (changes discarded on shutdown)verboseparameter toVM,ImageManager, andglobal_conf.initialize()verbose=False); informational prints are suppressed while errors are always preservedverbose=True) to keep existing user experiencenet.ifnames=0to kernel cmdline for stable guest NIC naming (eth0)exec > >(tee)) in boot script so QEMU is a direct child of screenstart()polling to 30s and add failure cleanup (screen + pidfile)banner_timeoutandauth_timeouttois_ready()(5s) andconnect()(10s)timeoutsupport onVM.execute(),VM.copy_to_vm(), andVM.copy_from_vm()timeoutas a total operation limit and keep existing behavior unchanged when omittedstdoutandstderrconcurrently inVM.execute()to avoid dual-stream blocking on large outputconnect()VM.stop()withwaitandforceoptions, and addVM.cleanup_runtime()for strong runtime cleanupTODOs
Installation
Requirements
Configuration
The configuration file is stored in
~/.config/syzqemuctl/config.json. It contains:Concepts
bullseye.img) created bycreate-image.sh. Images are stored as directories underIMAGES_HOME.Usage
⭐ As a command-line tool (CLI)
You can check the usage of
syzqemuctlorsyzqemuctl CMDby adding--help. Here are some common uses:Initialize syzqemuctl:
Create a new disk image:
Run a VM from the image:
Run with snapshot mode (all disk changes discarded on shutdown):
Check image/VM status:
Copy files/dir to/from VM: ```bash syzqemuctl cp local_file my-image:/remote/path # Copy to VM syzqemuctl cp 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
Stop the VM:
Restart the VM:
List all images:
Delete the image:
⭐ As a Python package (API)
License
Apache-2.0
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.