Overlapped filesystem
This tutorial has been prepared to show what can be done with another umview service module, umfuse. Although it was designed to allow the user to mount its own filesystem images without administrative privileges it can be also used to build interesting configurations.
Contents |
A brief introduction
Since any modification to a process' environment running within umview is only visible from the process itself there are no constrains on what can be done. In the following example we are going to use umfuse as a facility to superimpose a new filesystem over current root filesystem. The figure below gives a little overview of what we need to set up the situation just described.
Overview
- Although it is not actually possible to login to the UMview environment due to the lack of a pseudo-terminal device interface virtualization, what can be done now is some kind of authenticated and secure remote execution of small simple applications inside the virtual environment.
- SVG source available here
In such a chroot-like environment there are some restrictions: for now there is no way to bind hosting machine pseudo-filesystems to the new superimposed root. Therefore it is not possible to access pseudo-filesystem like /proc
and /dev/pts
. This implies that access to certain special device is not available. In the UMview hacks subsection we'll see how to bypass part of these limitations.
UMview hacks
From the beginning we wanted to get some kind of secure and authenticated network access to the UMview environment in order to be able to execute something from the superimposed filesystem and get results via a secure network channel. The idea behind this strange but interesting mechanism is to use a lightweight ssh server daemon, Dropbear.
Like every application that use cryptography Dropbear needs a source of entropy to work correctly. Dropbear by default tries to use the linux special device called /dev/urandom
as the source of entropy for its internals. As said previously inside our chroot-like environment made of umview and a superimosed root filesystem devices are not consistent and so unusable.
Here is where a little hack in umview joins the game. Taking a look into the source code of umdev service module and in its testmodules there are some examples that show how to mount a virtual device to the current filesystem. This patch adds to umdev service module the ability to mount an urandom
device within the chroot-like umview environment.
The working principle of this module is to open a new file descriptor from hosting machine's /dev/urandom
before the new root filesystem is superimposed to the real root filesystem. Then via the mount system call this open file descriptor is mapped to the desired place within the new environment.
Applying the patch
Once the patch has been downloaded it can be applied to the umview source tree with the patch
utility. Here is a brief example on how to proceed. Suppose that umview-0.4a
is the root of the source tree.
$ bzcat umdevurandom_20070307.patch.bz2 | patch -p1 -d umview-0.4a patching file umview-0.4a/umdev/umdev.c patching file umview-0.4a/umdev_testmodules/Makefile.am patching file umview-0.4a/umdev_testmodules/umdevurandom.c
Since a new module has been added to the source tree we need to rebuild configuration files generated by autotools.
$ cd umview-0.4a $ autoreconf
Now umview can be compiled in the usual way with ./configure && make
and installed with make install
. For further details about compiling and installing UMview from source code take a look here.
Setup procedure
Preparing the virtual network
First of all to be able to reach umview process tcp/ip stack the easiest way is to connect a tap interface to the virtual network. Before doing that a new persistent tap interface must be created and made accessible to the user named username for the example.
# tunctl -u username
Once created the interface must be brought up and configured as usual with a private network address.
# ifconfig tap0 192.168.0.100 netmask 255.255.255.0
Now the user can start a new vde_switch in daemon mode, specifying the data socket, optionally a management socket and the tap interface name to connect the switch to.
$ vde_switch -d -s /tmp/vde -M /tmp/mgmt -t tap0
The virtual network is ready for incoming connections from other virtual networking pluggable devices, so we can start a new instance of bash tunning within umview.
$ umview bash umview bash This kernel supports: PTRACE_MULTI PTRACE_SYSVM ppoll UMView will use: PTRACE_MULTI PTRACE_SYSVM ppoll pure_libc library found: module nesting allowed $
To provide a new abstract network connectivity within umview we have to load the Light Weight IPv6 service module, specifying that a new virtual network interface must be created and connected to the vde_switch data socket.
Then we bring up the new virtual network interface vd0 and we give it an address in the same subnet of address assigned to tap0.
$ um_add_service lwipv6.so,vd0=/tmp/vde $ ip link set vd0 up $ ip addr add 192.168.0.101/24 dev vd0
Now every aspect of the virtual network is ready. In the following section we are going to explain how to operate a "filesystem substitution" within umview environment.
Preparing the filesystem image
Since we want to mount a new root filesystem over the current root the easiest way to get a filesystem image is by creating it and bootstrapping it from scratch with debootstrap.
First of all we need to create a new empty file big enough to contain a debian base system and some other tools like iproute for Light Weight IPv6 configuration, netcat and dropbear for networking experiments and Virtual Square toolkit (vde, umview, lwipv6, umfuse).
$ dd if=/dev/zero of=debian.fs bs=1024 bc=512000 512000+0 records in 512000+0 records out 524288000 bytes (524 MB) copied, 16.1429 seconds, 32.5 MB/s
Once the new empty file has been created we have to make a new filesystem on it. We choose ext2 filesystem since it is the native GNU/Linux filesystem supported by umfuse. Note that obviously debian.fs is not a block special device but it can be formatted anyway so answer yes when mkfs.ext2 asks if you want to proceed.
$ mkfs.ext2 debian.fs mke2fs 1.39 (29-May-2006) debian.fs is not a block special device. Proceed anyway? (y,n) y Filesystem label= OS type: Linux Block size=1024 (log=0) Fragment size=1024 (log=0) 128016 inodes, 512000 blocks 25600 blocks (5.00%) reserved for the super user First data block=1 Maximum filesystem blocks=67633152 63 block groups 8192 blocks per group, 8192 fragments per group 2032 inodes per group Superblock backups stored on blocks: 8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409 Writing inode tables: done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 29 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override.
Now it is possible to mount the filesystem just created. debootstrap can be used to create a Debian base system from scratch, without requiring the availability of dpkg or apt. It does this by downloading .deb files from a mirror site, and carefully unpacking them into a directory which can be chrooted into.
# mount -o loop debian.fs /mountpoint # debootstrap etch /mountpoint http://ftp.it.debian.org/debian I: Retrieving Release I: Retrieving Packages I: Validating Packages I: Resolving dependencies of required packages... I: Resolving dependencies of base packages... ... #
To install additional tools we will use chroot to change the current root filesystem to the new environment.
# chroot /mountpoint /bin/bash
Once ch-rooted apt and dpkg of the new root filesystem become available and can be used to install packages from regular debian repositories via the host machine network. Moreover, to be able to execute commands from a remote host a password for root has to be set with passwd
Mounting the new filesystem
In order to be able to mount a filesystem image we need to load the umview service module called umfuse. As usual it can be loaded with um_add_service. UMfuse is the implementation of File System in User Space within umview: it is not only possible for a user to create its own filesystem without writing kernel code, but the user can also mount and use it inside umview partial virtualization.
In umview each filesystem implementation is a shared library that is loaded every time the user tries to mount a filesystem named with the umfuse prefix.
What we are goint to do is to mount an ext2 filesystem image containing a minimal debian GNU/Linux root filesystem over the current root inside umview. Before mounting the filesystem over current root you need to add another umview service module, umdev that provides support for virtual user-mode /dev/urandom
support.
It is important to load this service module 'before' mounting the filesystem with umfuse because umdev initialization opens /dev/urandom
and after mount operation such special device won't be reachable.
$ um_add_service umfuse $ um_add_service umdev
Now it is possible to proceed and mount the debian.fs filesystem on root.
$ mount -t umfuseext2 debian.fs / $ cd / $ ls bin DEBIAN_FS etc initrd lost+found mnt proc sbin sys usr boot dev home lib media opt root srv tmp var $ mount /root/debian.fs on / type umfuseext2 (rw)
The new root filesystem is now mounted over the hosting root. A quick listing of root directory shows that we are inside the filesystem just mounted and the output of mount shows that now the only filesystem mounted is debian.fs image. Let's see if the network works correctly.
$ ip addr show 1: lo0: <LOOPBACK,UP> mtu 0 link/loopback inet6 ::1/128 scope host inet 127.0.0.1/8 scope host 2: vd0: <BROADCAST,UP> mtu 1500 link/ether 02:02:28:9a:8e:06 brd ff:ff:ff:ff:ff:ff inet6 fe80::2:28ff:fe9a:8e06/64 scope link inet 192.168.0.101/24 scope global $ ping 192.168.0.100 WARNING: setsockopt(ICMP_FILTER): Protocol not available Do you have CONFIG_SOCKET in your kernel?WARNING: your kernel is veeery old. No problems. PING 192.168.0.1 (192.168.0.100) 56(84) bytes of data. Warning: no SO_TIMESTAMP support, falling back to SIOCGSTAMP 64 bytes from 192.168.0.100: icmp_seq=1 ttl=64 time=1.35 ms 64 bytes from 192.168.0.100: icmp_seq=2 ttl=64 time=1.07 ms --- 192.168.0.100 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1003ms rtt min/avg/max/mdev = 1.078/1.217/1.356/0.139 ms
Via iproute commands it is possible to see interfaces configuration that is the same as before mounting debian.fs. Hosting machine address replies to ICMP requests so everything seems to be fine.
Mounting /dev/urandom
The next step is to provide access to /dev/urandom
to the environment. This can be done via umdev hack by mounting an umdevurandom device to actual /dev/urandom
. As is shown below before mounting /dev/urandom
the device act as /dev/null
and it doesn't give any kind of output.
$ dd if=/dev/urandom bs=128 count=1 2>/dev/null | hexdump $ $ mount -t umdevurandom none /dev/urandom
Once /dev/urandom has been mounted to current /dev/urandom
mountpoint it begins to work correctly. In the following shell snapshot we tried to get 128 bytes of pure entropy the from the device just added.
$ dd if=/dev/urandom bs=128 count=1 2>/dev/null | hexdump -C 00000000 c2 a2 37 fb f7 65 7c 6d 3a f6 78 8e 03 79 99 ee |..7..e|m:.x..y..| 00000010 58 ee 0d 1c 11 86 54 c5 6a e9 1b e9 4a 08 e9 b2 |X.....T.j...J...| 00000020 8a 43 7f cf 7d 16 47 9f f3 c2 39 99 b2 5e 3c 4b |.C..}.G...9..^<K| 00000030 54 88 68 fe 54 0d c6 95 2c 61 67 f5 3f 33 95 75 |T.h.T...,ag.?3.u| 00000040 db a8 3d 73 42 f7 ab 84 3f 3d 4e 11 10 bd f1 e8 |..=sB...?=N.....| 00000050 65 01 88 84 32 ff ec 94 ba fb af ad d4 eb c9 a6 |e...2...........| 00000060 e1 67 4f d2 99 59 5e f8 bc f9 40 c1 b1 26 e4 32 |.gO..Y^...@..&.2| 00000070 6f 9a 5e 40 e5 ea cb d9 dc 51 0a e4 5b bd 4c 8d |o.^@.....Q..[.L.| 00000080
Testing the configuration
Now that everything is ready we can try to start a netcat instance to trigger dropbear execution for incoming connections.
$ nc -vv -l -n -p 10000 -c '/usr/sbin/dropbear -i' listening on [any] 10000 ...
When the address of umview virtual network interface receives a connection on port 10000 it starts dropbear in inetd-like mode (that is what the -i flag means). So netcat behaves like a network-triggered bi-directional pipe with dropbear standard input and output. From the hosting machine we try to execute a command via a network authenticated and secure connection with ssh.
$ ssh -p 10000 root@192.168.0.101 cat /root/foo.c root@192.168.0.101's password: #include<stdio.h> int main() { printf("hello umworld\n"); return 0; }
That's it.