
Building and Testing Linux Kernel Modules Using Multipass & VS Code
Kernel development can feel intimidating when there is a real chance of locking up your machine. Multipass gives you a disposable Ubuntu VM, so you can experiment safely while keeping your host OS clean.
This guide is ordered as a full workflow:
- Create and prepare a Multipass VM
- Connect to it from VS Code
- Install kernel build dependencies
- Write and build a module
- Load, test, unload, and clean up
Create a Multipass VM
Install Multipass on the host:
sudo snap install multipass
Launch a VM named kernel-dev and then enter it:
multipass launch --name kernel-dev
multipass shell kernel-dev
At this point you are inside the Ubuntu VM.
Optional: Bridge Mode Networking
By default, Multipass uses NAT (network address translation), which only allows the VM to reach the host and external networks, but other machines on your network cannot directly access the VM.
If you need the VM to be accessible from other machines on your network, or if you're running on Windows with remote networking, use bridge mode instead:
First, find your network interface name on the host. Run:
ip link show
Look for the interface connected to your network (usually named something like eth0, enp4s0, or wlan0). Skip lo (loopback) and docker interfaces. Example output:
1: lo: <LOOPBACK,UP,LOWER_UP> ...
2: enp4s0: <BROADCAST,MULTICAST,UP,LOWER_UP> ... <- Use this one
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
Then on the host, before creating the VM:
multipass set local.bridged-network=enp4s0
multipass launch --name kernel-dev --bridged
Replace enp4s0 with your actual network interface from the ip link show output.
Why use bridge mode:
- Windows host + remote Linux: If you're running Windows and connecting to a remote Linux machine, bridge mode gives the VM a direct network connection
- Multi-machine access: Other machines on your network can SSH directly to the VM without port forwarding
- Network simulations: Useful if your kernel module testing involves network communication
- Stable remote access: More reliable than NAT when working across network boundaries
The rest of this guide works the same way regardless of which networking mode you chose.
Enable SSH access for VS Code
Still inside the VM, allow password authentication and set a password for user ubuntu.
Edit SSH config:
sudo nano /etc/ssh/sshd_config
Ensure this line is set:
KbdInteractiveAuthentication yes
Restart SSH and set password:
sudo systemctl restart ssh
sudo passwd ubuntu
Get the VM IP address:
hostname -I
Connect from VS Code
Install the VS Code extension pack named Remote Development.
From your host terminal, verify SSH works:
ssh ubuntu@<vm-ip>
Then use VS Code Remote SSH to open that VM as your development environment.
Install kernel module build dependencies
Inside the VM:
sudo apt update
sudo apt install -y build-essential linux-headers-$(uname -r) kmod
What these provide:
- Compiler and build tools
- Headers for your running kernel
- Module management tools such as
insmodandrmmod
Create the module source
Create a working folder:
mkdir -p ~/pyjama
cd ~/pyjama
Create pyjama.c:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/uaccess.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("bibble");
MODULE_DESCRIPTION("Simple /proc example module");
static struct proc_dir_entry *pyjama_entry;
static ssize_t pyjama_read(struct file *file, char __user *buffer, size_t count,
loff_t *offset)
{
char msg[] = "Hello from me\n";
size_t len = strlen(msg);
if (*offset >= len)
return 0;
if (copy_to_user(buffer, msg, len))
return -EFAULT;
*offset += len;
return len;
}
static const struct proc_ops pyjama_ops = {
.proc_read = pyjama_read,
};
static int __init pyjama_init(void)
{
pyjama_entry = proc_create("pyjama", 0444, NULL, &pyjama_ops);
if (!pyjama_entry)
return -ENOMEM;
pr_info("pyjama: loaded\n");
return 0;
}
static void __exit pyjama_exit(void)
{
proc_remove(pyjama_entry);
pr_info("pyjama: unloaded\n");
}
module_init(pyjama_init);
module_exit(pyjama_exit);
Add the Makefile
Create Makefile in the same folder:
obj-m += pyjama.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
Build the module
From ~/pyjama:
make
If successful, you will get pyjama.ko.
Load and test it
Load the module:
sudo insmod pyjama.ko
Check kernel logs:
dmesg | tail -n 20
Read your /proc entry:
cat /proc/pyjama
Expected output:
Hello from me
Unload and clean
Unload:
sudo rmmod pyjama
Confirm unload message:
dmesg | tail -n 20
Clean build artifacts:
make clean
Useful Multipass commands
On the host machine:
multipass list
multipass shell kernel-dev
multipass stop kernel-dev
multipass start kernel-dev
This workflow gives you a repeatable, low-risk setup for kernel module experimentation.



