QEMU MT7622 Emulation

December 21, 2025 ยท View on GitHub

overview

This repo provides a minimal setup for running the MediaTek MT7622 wifi kernel driver in an x86_64 QEMU VM. It includes a custom build of QEMU which implements a PCI device emulating the MT7622 wifi chip, kernel images for Linux 4.4.198, and a copy of the MT7622 kernel driver compiled for x86_64 (version 5.1.0.0).

This project was developed primarily for security research purposes (to reproduce bugs in the driver with a viable debug environment) during my time evaluating the MT7622/MT7915 chipset. As such, the implementation is still very minimal and incomplete. I've only developed QEMU devices a few times in the past and each time is pretty "experimental" so there may be better/more accurate ways to implement things but this was enough to load the kernel module and interact with the majority of the ioctl handlers in the driver.

WARNING: there are a number of handlers in the driver which will crash if interacted with (e.g. trying to access hardware, etc). I don't have a mapping of what works and what doesn't but if you run into unexpected kernel crashes this is the most likely cause.

You can use this environment to reproduce and further explore the bugs described in my recent blog post covering this work.

files

  • files/mt7622_mt_wifi.tar.gz: compressed archive containing the mt7622 kernel module binary
  • files/rootfs-wifi/wifi-files.tar.gz: archive of related firmware and configs for the driver

build custom QEMU

NOTE: the instructions below make use of a nix-shell for compiling QEMU. If you're not using NixOS or the nix package manager you'll need to install dependencies from your distro's package repo.

To build the custom QEMU with the MT7622 device:

cd mt7622-qemu
nix-shell
make qemu-bin

build a rootfs

Booting the VM requires a root filesystem so you'll need to create one before doing anything else.

You can build a compatible rootfs for use with the VM with debootstrap. I've created a docker container and wrapper script to simplify this process (built on top of the create-image.sh script used by syzkaller). Use the steps below to create a minimal rootfs based on Debian Bullseye.

NOTE: requires docker.

git clone https://github.com/mellow-hype/kernel-utils utils/.
make -C util/kernel-utils/debootstrapper init_docker
make -C util/kernel-utils/debootstrapper bullseye_amd64 odir=$PWD/rootfs

# optional: delete the unpacked rootfs files; you can mount the .img locally with a loopback device
# if you need local access to the files in the image.
sudo rm -rf rootfs/bullseye_amd64/bullseye

The rootfs image will be at rootfs/bullseye_amd64/bullseye.img.

init the rootfs with required driver files

There are a few files which are used by the driver that need to be copied over into the filesystem before trying to run it.

After building the rootfs using the steps above, the files that were used to generate the image will be at rootfs/bullseye_amd64/bullseye. You can use the script util/init_wifi_files.sh to copy the files over to the correct locations in the filesystem. You'll then need to rebuild/recreate the rootfs image from this new directory.

If you want to skip the step of having to recreate the image, you can also mount the rootfs image directly on your host and copy the files into the mount location. The following commands can be used to go this route:

mkdir rootfs/mnt
sudo mount -o loop rootfs/bullseye_amd64/bullseye.img rootfs/mnt

# unpack the compressed wifi files first
tar xvzf files/rootfs-wifi/wifi-files.tar.gz -C files/rootfs-wifi/.
# then use this helper script to copy the files into the mounted rootfs
./util/init_wifi_files.sh ./rootfs/mnt

Finally, copy over the kernel driver:

tar xvf files/mt7622_mt_wifi.tar.gz -C files/.
sudo cp files/mt7622_mt_wifi.ko rootfs/mnt/root/.
sudo umount rootfs/mnt

Then modify the permissions of the rootfs.img file to change it's ownership from root to your local user to avoid having to run qemu as root.

sudo chown user:user rootfs/bullseye_amd64/bullseye.*

boot the VM and finish setup

Assuming the rootfs has been set up with the required files as described above, you can now boot the VM using the provided kernel image. The script qemu-mt7622-run.sh should be used to ensure all required flags are passed to QEMU.

./qemu-mt7622-run.sh files/kernel/4.4.198-bzImage.nokasan rootfs/bullseye_amd64/bullseye.img

Once the VM boots you'll be able to log in to the local console as root without a password. You can also use the SSH key generated as part of the creation of the rootfs to connect remotely, like so:

ssh -i rootfs/bullseye_amd64/bullseye.id_rsa -p 10021 root@127.0.0.1

You might want to install a couple of tools inside the VM like iwpriv (provided by wireless-tools package in Debian).

apt update && apt install wireless-tools vim curl

test loading the driver

Once everything above is complete you can verify that the kernel driver successfully loads by using the following command:

insmod /root/mt7622_mt_wifi.ko

This will create a new network interface named ra0. You can then run iwpriv ra0 get_driverinfo to confirm everything is working as expected.