UML (User Mode Linux) is a nice way for Linux virtualization. Somewhere between containers and full or paravirtualization. But without actually using a visualizer / hypervisor.
Unfortunately UML not so well documented. So I dumped some of my notes here.
ATTENTION: These are just my notes!
I didn’t spend time to check if they can be easily used or MAY EVEN BE DANGEROUS OR HARMFUL TO YOUR COMPUTER!
POSSIBLE SECURITY PROBLEM:
https://web.archive.org/web/20210222080616/https://www.securityfocus.com/bid/3973/discuss
UML does not correctly protect kernel address space from user
programs within the UML environment. It may be possible to execute
arbitrary code within the kernel and gain root access. Additionally,
it may be possible to use this vulnerability to escape the UML
environment, leading to local access on the hosting system.
boot message:
This architecture does not have kernel memory protection.
Debian 12 ROOT: # Alternatively to using root you may have a look at this: # https://libguestfs.org/virt-builder.1.html # https://linux.die.net/man/1/guestfish # https://wiki.debian.org/FakeRoot # https://wiki.debian.org/fakechroot apt install user-mode-linux debootstrap slirp truncate --size=1G disk.ext4 mkfs.ext4 disk.ext4 mount -o loop disk.ext4 /mnt/ debootstrap --include=user-mode-linux bookworm /mnt/ umount /mnt/ chown USER: disk.img USER SHELL 1: # MAYBE ADDITIONAL (HOST:ubd0 -> GUEST:ubda): root=/dev/ubda linux.uml mem=1G ubd0=disk.ext4 init=/bin/ash# WITH INITRD: # init= is interpreted by the init script, which usually loads /dev/ first! # rdinit= directly sets another init script in the kernel. (rdinit = ram-disk-init) # WITHOUT INITRD: # init= sets the init script directly in the kernel. linux.uml mem=1G ubd0=disk.ext4 rdinit=/bin/ash # /dev/ populating (root=98:0 console=tty0 -> else this gets automatically attached at the end) linux.uml mem=1G ubd0=disk.ext4 root=98:0 console=tty0 rdinit=/bin/ash -- -c \ '"mount /run; mkdir -p /run/lock; mount /proc; mount /sys; /lib/debian-installer/start-udev; exec ash"' # With open shell by systemd linux.uml mem=1G ubd0=disk.ext4 rw con9=fd:0,fd:1 con=null console=tty9 systemd.debug-shell=1 # Alternatively if no login password is set: linux.uml mem=1G ubd0=disk.ext4 rw con2=fd:0,fd:1 con=null console=tty2 USER SHELL 2: ss -xlnp | grep linux uml_mconsole ~/.uml/*/mconsole config ubd1=/path/to/disk2.raw RUNNING UML AS ROOT WITH HOSTFS: linux.uml mem=1G rootfstype=hostfs hostfs=/mnt/ ro con9=fd:0,fd:1 con=null console=tty9 systemd.debug-shell=1 # Replacing "ro" with "rw" may be DANGEROUS!!! # IT MAY CHANGE YOUR HOSTS FILESYSTEM IN UNWANTED WAYS!!! MINIMAL SYSTEM: wget https://deb.debian.org/debian/dists/bullseye/main/installer-amd64/current/images/hd-media/initrd.gz linux.uml mem=1G initrd=initrd.gz init=/bin/sh hostfs=/ mount -t hostfs hostfs /mnt mount --bind /mnt/usr/lib/uml/modules/ /lib/modules/ halt -f MINIMAL WITH READONLY HOSTFS (Debian-12) #### Minimal without network (hostfs=/ is default): # linux.uml mem=1G rootfstype=hostfs ro init=/bin/bash #### With network via "slirp": linux.uml mem=1G rootfstype=hostfs ro init=/bin/bash \ eth0='slirp,,slirp,host_addr_10.0.2.2,redir_50022_10.0.2.15:22' # mount overlay mount -t tmpfs -o size=256M tmpfs /mnt mkdir /mnt/up /mnt/work /mnt/merged insmod /usr/lib/uml/modules/"$(uname -r)"/kernel/fs/overlayfs/overlay.ko mount -t overlay -o lowerdir=/,upperdir=/mnt/up,workdir=/mnt/work overlay /mnt/merged mount -t devtmpfs devtmpfs /mnt/merged/dev mount -t proc proc /mnt/merged/proc mount -t sysfs sysfs /mnt/merged/sys chroot /mnt/merged /bin/bash ip link set eth0 up ip -4 addr add 10.0.2.15/24 dev eth0 ip -4 r add default via 10.0.2.2 echo 'nameserver 10.0.2.3' >> /etc/resolv.conf COMPILING A USER MODE LINUX KERNEL: # Download and extract kernel sources from https://kernel.org/ make defconfig ARCH=um make menuconfig ARCH=um # interesting options (Linux-6.1) CONFIG_BLK_DEV_INITRD=y CONFIG_VIRTIO_UML=y CONFIG_PM_AUTOSLEEP=y CONFIG_BLK_WBT=y CONFIG_PARTITION_ADVANCED=y CONFIG_CMDLINE_PARTITION=y CONFIG_BLK_MQ_PCI=y CONFIG_BLK_MQ_VIRTIO=y CONFIG_BLK_DEV_LOOP=y CONFIG_VIRTIO=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y CONFIG_BTRFS_FS=y CONFIG_BTRFS_FS_POSIX_ACL=y CONFIG_FS_POSIX_ACL=y CONFIG_FS_ENCRYPTION=y CONFIG_FS_ENCRYPTION_ALGS=y CONFIG_NETFS_SUPPORT=y CONFIG_ISO9660_FS=y CONFIG_FAT_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_EXFAT_FS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_TMPFS_XATTR=y CONFIG_CRAMFS=y CONFIG_SQUASHFS=y CONFIG_SQUASHFS_XATTR=y CONFIG_SQUASHFS_ZLIB=y CONFIG_SQUASHFS_LZ4=y CONFIG_SQUASHFS_LZO=y CONFIG_SQUASHFS_XZ=y CONFIG_SQUASHFS_ZSTD=y CONFIG_NFS_FS=y CONFIG_NFS_V2=y CONFIG_NFS_V3=y CONFIG_NFSD=m CONFIG_NFSD_V2_ACL=y CONFIG_NFSD_V3_ACL=y CONFIG_NFSD_V4=y CONFIG_NFS_ACL_SUPPORT=m CONFIG_CIFS=y CONFIG_AFS_FS=y # Build mkdir tmp TMPDIR="$(pwd)"/tmp LANGUAGE='' LANG=C.UTF-8 nice ionice -c3 eatmydata \ sh -c 'make ARCH=um linux modules modules_install INSTALL_MOD_PATH="${HOME}"/opt/user-mode-linux-uml/default' # Output (you may rename it to "linux.uml") linux SLIRP (NAT network without root permissions on host) COMPILING SLIRP: mkdir ~/opt/slirp/{bin,build,man/man1} cd ~/opt/slirp/build wget 'https://deb.debian.org/debian/pool/main/s/slirp/slirp_1.0.17.orig.tar.gz' tar xf slirp_1.0.17.orig.tar.gz wget 'https://deb.debian.org/debian/pool/main/s/slirp/slirp_1.0.17-11.debian.tar.xz' tar xf slirp_1.0.17-11.debian.tar.xz cd slirp-1.0.17 for i in ../slirp_1.0.17-11.debian/patches/0*; do patch -p1 < "${i}"; done cd src/ ./configure --prefix="${HOME}"/opt/slirp CFLAGS='-I. -DUSE_PPP -DUSE_MS_DNS -fno-strict-aliasing -Wno-unused -std=gnu89'; \ make "${CFLAGS} -DFULL_BOLT" PPPCFLAGS="${CFLAGS}" install linux.uml mem=1G initrd=initrd.gz init=/bin/sh \ eth0=slirp,,"${HOME}"/opt/user-mode-linux-uml/slirp/bin/slirp" ip link set eth0 up ip -4 addr add 10.0.2.15/24 dev eth0 ip -4 r add default via 10.0.2.2 echo 'nameserver 10.0.2.3' >> /etc/resolv.conf SLIRP WITH PORT-FORWARDING: linux.uml mem=1G initrd=initrd.gz init=/bin/sh \ eth0='slirp,,slirp,host_addr_10.0.2.2,redir_50022_10.0.2.15:22' linux.uml mem=1G initrd=initrd.gz \ eth0='slirp,,slirp,host_addr_10.0.2.2,redir_50022_10.0.2.15:22' \ console=tty0 rdinit=/bin/ash -- -c \ "\"mount /run; mkdir -p /run/lock; mount /proc; mount /sys; /lib/debian-installer/start-udev; ip link set eth0 up; ip -4 addr add 10.0.2.15/24 dev eth0; ip -4 r add default via 10.0.2.2; echo 'nameserver 10.0.2.3' >> /etc/resolv.conf; exec ash\"" sh -c 'sleep 10; kill "$(pidof nc)"' & nc -l -p 22 ########## mount -t hostfs -o ro hostfs /mnt mount --bind /dev /mnt/dev; mount --bind /proc /mnt/proc; mount --bind /sys /mnt/sys mount -t tmpfs -o size=32M,mode=0700 tmpfs /mnt/run chroot /mnt # Without mode=0700 sshd refuses to read AuthorizedKeysFile ########## echo 'PUBKEY' >> /run/a_pubk ssh-keygen -t rsa -b 4096 -f /run/ssh_rsa -P '' /usr/sbin/sshd -f /dev/null -h /run/ssh_rsa -o AuthorizedKeysFile=/run/a_pubk
See also:
https://www.kernel.org/doc/html/v6.1/virt/uml/user_mode_linux_howto_v2.html
https://www.kernel.org/doc/html/v5.9/virt/uml/user_mode_linux.html
https://en.wikipedia.org/wiki/User-mode_Linux