After reading this article you will be able to start a Debian-Linux (including Kernel) from any (unprivileged) Linux shell.
User Mode Linux (UML) is a modified Linux Kernel that the user starts just like any other Linux program. The UML-Kernel then "boots" a 'Guest Debian Linux' to which the user can log in as root.
This is a great way to play around on a root-shell on an isolated Linux.
Think of UML as something between Docker and a VM:
All processes are visible on the host but 'kind of' isolated.
All processes run at near host speed (~15% slower).
All capabilities and privileges are available within the Guest OS.
Host and Guest OS must be of the same architecture (e.g. both x86_64).
Does not require access to
/dev/kvm
.
Alternatively, read Starting a VM as an unprivileged Linux User for using a full VM instead (which will run slower but better isolated).
The instructions have been tested on Segfault's Disposable Root Servers.
A. Configuration
Set up UML and the directory structure:
[[ ! -f ~/.ssh/id_ed25519 ]] && ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_ed25519
mkdir uml
cd uml
wget https://deb.debian.org/debian/pool/main/u/user-mode-linux/user-mode-linux_5.10um3+b1_amd64.deb
ar x user-mode-linux_5.10um3+b1_amd64.deb
rm user-mode-linux_5.10um3+b1_amd64.deb control.tar.xz debian-binary
tar -xf data.tar.xz
rm data.tar.xz
mv usr/bin/linux.uml .
mv usr/lib/uml/modules .
rm -r usr
[[ ! -f ~/.slirprc ]] && echo "redir tcp 2222 22" >~/.slirprc
Download Debian OS and resize the image:
wget -O debian.img https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-nocloud-amd64.raw
truncate -s 8G debian.img
Start Debian OS using the UML-Linux Kernel:
export TMPDIR=/tmp
./linux.uml \
mem=1024M \
root=/dev/ubda1 rw \
ubd0=debian.img \
systemd.unit=emergency.target
Configure the System
Press Enter
when prompted to configure the system:
sed '/boot\/efi/d' -i /etc/fstab
echo "none /lib/modules/$(uname -r) hostfs /sec/root/uml/modules/$(uname -r) 0 2" >>/etc/fstab
mkdir -p /lib/modules/$(uname -r)
# Mount the host's /sec inside the guest OS:
echo "none /mnt/host-fs hostfs / 0 2" >>/etc/fstab
mkdir -p /mnt/host-fs
ln -s /mnt/host-fs/sec /sec # segfault.net specific
systemctl mask systemd-binfmt.service
systemctl disable getty@tty1
systemctl enable getty@tty0
ssh-keygen -A
cat > /etc/netplan/90-default.yaml <<-'EOF'
network:
version: 2
renderer: networkd
ethernets:
eth0:
dhcp4: no
addresses: [10.0.2.15/24]
routes:
- to: default
via: 10.0.2.2
on-link: true
nameservers:
addresses: [10.0.2.3]
EOF
growpart /dev/ubda 1
resize2fs /dev/ubda1
# Add an SSH Key
systemctl daemon-reload
mount /mnt/host-fs
cp /mnt/host-fs/root/.ssh/id_ed25519.pub ~/.ssh/authorized_keys
poweroff
Create a Shortcut for launching
cat >launch.sh <<-'EOF'
#! /bin/sh
cd "$(dirname "$0")" || exit
export TMPDIR=/tmp
exec ./linux.uml mem=1024M root=/dev/ubda1 ubd0=debian.img eth0=slirp,52:54:00:00:01,/usr/bin/slirp-fullbolt
EOF
chmod +x launch.sh
B. Starting the UML-Linux Debian OS
Start the Debian OS UML-Linux
./launch.sh
Log in using root
without a password or use ssh -p2222 root@0
.
Example: Install & start docker:
# UML Kernel does not come with all netfilter modules.
# Use iptables in "legacy"-mode instead:
update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
# Install docker
apt update
apt install docker.io
# Start 'Alpine/Linux' inside Docker, inside UML.
docker run --rm -it alpine
C. Advanced tricks
- Using the Slirp-Console to forward ports from the host to the UML guest:
# On the UML guest:
apt install telnet
# Make Linux less stupid (10.0.2.0 is indeed a valid IP):
iptables -t nat -I OUTPUT -p tcp -d 10.0.2.1 -j DNAT --to-destination 10.0.2.0
# Access the Slirp console
telnet 10.0.2.1
Shoutz to Matthew (๐ซต๐ง ๐).