This document describes how to setup a working UML completely from scratch
(no preloaded filesystems) without needing root access. Anywhere.
Why on earth would you want to do that?
Because it can be done.
Who are you?
Stephen Oberholtzer, aka Stevie-O.
Wait, that's not the way you should do X!
You're probably right. Especially if X is a config setting when
building the kernel. I wasn't going for perfect. I was going for something that
This all seems like a lot of work that involves several unnecessary steps.
That's correct. Some of these steps could be avoided (for example, I could
provide prebuilt binaries of the UML kernel.) But where's the fun in that?
You could also probably speed up the kernel compilation by NOT building in
support for every filesystem ever created, ever.
What you'll need
You'll need several things in order to make this work.
If you have all of that covered, we may begin.
- Access to least one shell on a Linux machine, that's running at least a
2.4 kernel (preferably at least 2.6), where your home directory (or any
directory you can write to) is NOT mounted
-o noexec, you are able
to allocate at least 500MB-1GB, and you have direct access to the internet.
- On that shell, you will need access to:
perl (version 5.8),
and some sort of editor (such as
- It is (hypothetically) possible to get away without needing
patch, as one could manually edit/recreate the patched files
with an editor. Making this work is left as an exercise to reader who is
even more insane than I am.
- Similarly, it is (hypothetically) possible to make this work across
multiple shells, for example, if one shell has unrestricted access to the
internet, while another has gcc, you could download the files via the first
shell, transfer them to the gcc shell (somehow), compile things, then transfer
them back to the net-enabled shell (somehow). I have not tested this; making
it work is left as an exercise to another insane reader.
- This might involve building a cross-compiler if the two hosts are of
different architectures. Making this work is left as an exercise to a
reader whose mind is completely and utterly warped.
- While not strictly necessary, you will find life to be far easier if the
screen. It's also much nicer if your shell has what you
need to compile against ncurses (on Debian, the package libncurses5-dev should
be installed). You also may wish to use a shell where you can listen on a port
that is publically accessible from the internet.
- The means to retrieve files from websites.
wget is perfect.
- My test shell didn't have locale stuff enabled, which is bad, because for this
stuff to work right, you need to be using a UTF-8 character encoding.
The locales package was installed, and localedef was there (it's part of the
libc6 package in Debian), but no locales had been built.
dpkg -x locales_2.3.2.ds1-22_all.deb mylocales
# after some tweaking I learned that locale-gen tries to run the following
# localedef -i en_US -c -f UTF-8 -A /etc/locale.alias en_US.UTF-8
# after some more fiddling and googling I found that localedef doesn't play
# nicely unless you do certain tricks. The trailing slash at the end of the
# following command line is crucial:
I18NPATH=~/mylocales/usr/share/i18n/ localedef -i en_US -c -f UTF-8 -A /etc/locale.alias ~/mylocales/en_US.UTF-8/
# see http://gentoo-wiki.com/Talk:HOWTO_localedef
I then put the following into my
Then I logged out and logged back in.
I had to do two more things to really make it all work:
- Decide how big you want your virtual drive to be. I suggest 512MB-1024MB.
Partman has trouble autopartitioning 512MB drives, so if you want to auto
partition, use 1024.
- Create the virtual drive. (Replace 1024 with the number of MB you want your drive to be.)
dd if=/dev/zero of=uml-drive bs=1M count=1024
This will probably take a while; don't worry unless you don't get
something back that looks like:
1024+0 records in
1024+0 records out
Except that instead of 1024, it will say whatever you put for the 'count=' value.
- Download the files you're going to need.
- Nightly netinst cd (this might also take a while): [http://www.debian.org/devel/debian-installer/]
- Perl stuff that I wrote for extracting files from ISO images
For perl version >= 5.8:
For perl version >= 5.5.3 but < 5.8:
- Slirp 1.0.16 and the patch to make it 1.0.17 [http://sourceforge.net/project/showfiles.php?group_id=4677]
- The linux kernel source. Another one that might take a very, very long time. [http://www.kernel.org/] [http://www.kernel.org/pub/linux/kernel/v2.6/]
Note: At this time, 2.6.16 is the newest kernel, but the UML patches haven't been
updated for it yet. The patches will apply -- mostly -- but you'll get a kernel
that won't build.
- The latest UML utilities
- The latest UML guest patches [http://www.user-mode-linux.org/~blaisorblade/]
- libncurses5-dev: The host I used to verify this had libncurses5 installed, but not libncurses5-dev.
Needless to say, this upset me.
I went to http://packages.debian.org/unstable/libdevel/libncurses5-dev
and then did:
dpkg -x libncurses5-dev_5.5-1_i386.deb ncurses-dev
export HOSTCFLAGS="-I$PWD/ncurses-dev/usr/include -L$PWD/ncurses-dev/usr/lib"
# for 2.6.16, the stuff for menuconfig is broken, and you also need to do this
export HOSTLDFLAGS="-L$PWD/ncurses-dev/usr/lib -lncurses"
Note: The export has to be done before you start building the kernel!
- Extract the ISO helper.
tar jxf iso-perl-stuff.tar.bz2
# or iso-perl-stuff-5.5.tar.bz2 if you have an older perl
- Extract the initrd from the CD image.
perl -Iiso-perl-stuff iso-perl-stuff/isocat.pl debian-testing-i386-netinst.iso /install/2.6/initrd.gz > uml-initrd.gz
- Extract the Linux kernel source and the UML patch.
tar jxf linux-18.104.22.168.tar.bz2
- Optionally get worried when you see a message saying
tar: pax_global_header: Unknown file type 'g', extracted as normal file
- Start building your kernel.
- Enter the directory.
- Patch the kernel to add TLS support.
patch -p1 < ../uml-2.6.15-bs3-tls.patch
- Make sure it knows you're doing UML.
- Now it's time to tweak things.
- UML-specific options: (if you don't see this, you
forgot to do
- Y to CONFIG_BINFMT_MISC ("Kernel support for MISC binaries")
- Y to CONFIG_HOSTFS ("Host filesystem")
- Y to CONFIG_MCONSOLE_EXEC ("Management console 'exec' support')
- Y to CONFIG_MAGIC_SYSQR ("Magic SysRq key")
- Under Host processor type, make sure you choose Pentium-Pro (assuming
your shell is on an x86 system)
- General Setup:
- N to "BSD Process Accounting version 3"
- N to "Configure standard kernel features"
- N to "Optimize for size"
- Y to everything else here.
- Loadable Module Support
- N to "Enable loadable module support".
- Block Devices
- Y to Networking Support
- Y to EVERYTHING under Networking Options, except:
- N to ARP Daemon support
- N to the various options for debugging (watch out for the Simple
Example in the QoS section)
- N to Asynchronous Transfer Mode (ATM)
- N to DECnet
- N to IPX
- N to Appletalk
- N to CCITT X.25
- N to LAPB Data Link Driver
- N to Acorn
- N to WAN Router
- Be absolutely certain you specify N to the Network Testing/Packet Generator option
- N to Amateur Radio support
- N to IRDA support
- N to Bluetooth support
- N to Generic IEEE 802.11 support
- Character Devices
- N to Legacy (BSD) PTY support
- N to Sound support
- N to Disable Watchdog Shutdown on Close
- N to iomem emulation driver
- Y to everything else here
- Default main console initialization: "fd:0,fd:1"
- Default console channel initialization: "pts"
- Default serial line channel initialization: "pty"
- Block Devices
- N to ATA over Ethernet support
- Y to everything else here, especially "Virtual block device"
- UML Network Devices
- N to pcap device!
Note: You can actually choose Y here, but your kernel
won't compile unless the pcap headers are installed. Furthermore, you'd
need root in order to attach to an interface, in which case (a) why
are you reading this document?, and (b) the tun/tap interface is easier
- Y to everything else in here, especially SLiRP
- Network Device Support
- Don't turn on WAN Interface support
- Turn on all the PPP crap
- Turn on TUN/TAP
- N to ext2 execute in place support
- N to XFS Realtime support
- N to all those debugging options (including Stats in proc/fs/reiserfs)
- N to NTFS write support as well, unless you really want it
- N to Allow direct I/O on NFS files
- N to Use a default NLS (on SMB file system support)
- N to CIFS Experimental Features
- N to NCP file system support (unless you're planning to mount some NetWare drive images)
- N to 96-bit Coda identifiers
- No point in saying Y to Advanced partition selection until the
eloop driver (which supports partition tables on loopback mounts) goes
- Leave Native Language Support alone.
- Y to everything else
- Security Options
- N to both of these unless you want to try out SELinux or something :)
- Cryptographic options
- I don't think you need to turn any of these on, but it should be safe to do so
- Library routines
- Multi-device support (RAID and LVM)
- N to Multipath I/O support
- N to Faulty test module
- N to Multipath Target
- Y to everything else
- Kernel hacking
- N to command-line arguments in TT mode
- Finally, save your configuration.
- Build the kernel:
- Go get a pizza (or compile eggdrop.)
- Return to the place from whence you came.
ln linux ..
- Setup uml_mconsole.
tar jxf uml_utilities_20060216.tar.bz2
Of course, this didn't work on my system. It needed some encouragement.
(Back in the main dir)
dpkg -x libreadline5-dev_5.1-6_i386.deb readline-dev
export CFLAGS="-I$PWD/readline/usr/include -L$PWD/readline-dev/usr/lib"
ln uml_mconsole ../..
- Setup SLiRP.
- Unpack SLiRP (heretofore referred to as 'slirp' because its' capitalization is annoying as hell).
tar zxf slirp-1.0.16.tar.gz
tar zxf ../slirp_1_0_17_patch.tar.gz
- Patch it.
patch -p1 < ../fix17.patch
- Configure it.
# (still in the src directory)
- Fix it.
Depending on your GCC version, you might need to turn off optimizations.
SLiRP plays fast and loose with the TCP memory structures to make handling
the 'pseudoheader' checksum as efficient as possible, and some versions of
GCC reorder access to what appear to be different variables (but are actually
the same memory location). The upshot to all this is that if you have an
unfriendly GCC version, and you compile SLiRP with -O2, you get a binary
that rejects all TCP packets.
Versions of GCC known to cause problems:
- gcc (GCC) 3.3.6 (Debian 1:3.3.6-10)
Versions of GCC known to work OK:
- gcc (GCC) 4.0.3 20060212 (prerelease) (Debian 4.0.2-9)
If you experience problems with connectivity, try editing the Makefile
-O2 out of CFLAGS and PPPCFLAGS.
- Build it.
# again -- still in the src directory
- Return to the main directory.
ln slirp ../..
- If you're interested in enabling ssh connections into your UML,
you'll want to do something like this:
echo 'redir tcp 15022 22' > ~/.slirprc
15022 is the port on the host that will be redirected to 22 on the UML.
- Start installing Debian!
./linux mem=64M ubd0=uml-drive ubd2r=debian-testing-i386-netinst.iso eth0=slirp,,./slirp root=/dev/ram rw ramdisk=10240 initrd=uml-initrd.gz netcfg/disable_dhcp=true hw-detect/start_pmcia=false debian-installer/probe/usb=false
Be sure to put your terminal program into UTF-8 mode.
Also, if you're running under screen, you'll want screen to know you're
really in a UTF-8 locale (
This will be pretty straightforward, except at the beginning. Pay attention!
LANG=en_US.UTF8). Furthermore, older
versions of screen are just totally hopeless and will always screw up the first
few lines of output. Live with it.
Here is how to configure the network:
- d-i (Debian Installer) won't find your CD-ROM drive, because you don't have one.
When it asks you if you want to load drivers from a floppy, say NO.
- It will then ask you if you want to manually select a CD-ROM module and device.
- Choose 'none' from the module list.
- It will prompt you for a device (likely defaulting to /dev/cdrom). Change
this to /dev/ubdc (NOT /dev/udbc!) and hit enter to Continue.
- It will then tell you it couldn't load the kernel modules, and ask if
you want to proceed with the installation anyway. Say YES.
Partitioning: ubda is your virtual drive. Use that.
- You'll get a zillion network options. Which you won't be able to read
at first, because SLiRP writes directly to stderr. It would be interesting
to patch UML so that it stole stderr from SLiRP and piped the information
directly into the kernel ring buffer.
Nothing serious, however; just hit Control-L to see:
Anyway, pick eth0. (It should be first on the list.)
- IP Address:
- Name server address:
- Hostname: You're on your own here. I suggest reading RFC 2100.
Or leave the default 'debian'. See if I care.
- Domain name: leave blank
Once that stuff is done, you should be good to go for a while. (A long while.
For example, now would probably be a good time to take a nap.
(This will be especially slow because if you're reading this document, you're
almost certainly running under skas0 mode, which is a lot less efficient than
Update: jdike has informed me that sysemu was mainlined as of 2.6.14.
When the time comes, it will ask you if you want to install GRUB to the master
boot record. Choose to Go Back. You will find yourself back at the main
menu; choose "Continue without boot loader".
When you get to the prompt warning you that it's time to reboot, you need to
pay close attention.
When the UML reboots and says "UML running in (SKAS0|SKAS3|TT) mode", hit
Control-C to stop it.
- Boot your new system!
./linux mem=64M ubd0=uml-drive eth0=slirp,,./slirp root=/dev/ubda1 ro
It will run for a while and then you'll get a pile of messages that look
[42949410.210000] Virtual console 3 assigned device '/dev/pts/282'
[42949410.270000] Virtual console 4 assigned device '/dev/pts/283'
[42949410.270000] Virtual console 5 assigned device '/dev/pts/284'
[42949410.270000] Virtual console 6 assigned device '/dev/pts/285'
[42949410.320000] Virtual console 1 assigned device '/dev/pts/286'
[42949410.320000] Virtual console 2 assigned device '/dev/pts/287'
Find the one that says 'Virtual console 1' and then run
and hit Enter.