Overlapped filesystem

From Virtualsquare
Jump to: navigation, search

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.


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.



Overlap fs.png
  • 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 netmask

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 

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 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 
    inet6 ::1/128 scope host 
    inet 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 scope global

$ ping
WARNING: setsockopt(ICMP_FILTER): Protocol not available
Do you have CONFIG_SOCKET in your kernel?WARNING: your kernel is veeery old. No problems.
PING ( 56(84) bytes of data.
Warning: no SO_TIMESTAMP support, falling back to SIOCGSTAMP
64 bytes from icmp_seq=1 ttl=64 time=1.35 ms
64 bytes from icmp_seq=2 ttl=64 time=1.07 ms

--- 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.|

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@ cat /root/foo.c
root@'s password: 

int main()
        printf("hello umworld\n");
        return 0;

That's it.

Personal tools