/ Security

Sandboxing and program isolation in linux using many approaches (Part 1)

Securing your system is a big priority for every desktop user or in production environment whether you are system admin or a software developer. The best way of secure your operating system from doubtful programs or process is by sandboxing (also termed as jailing).Sandboxing means providing a safe environment for a program or software so you can play around it without hurting your system. It actually made your program isolated from rest of the system by different features avaliable in linux kernel. Sandboxing can be useful for system adminstration if they want to test their task without any damage to system and also for developer for testing their piece of code, even it can help you to create a different environment then your base operating system.It comes in trend due to its extreme use by Paas and Saas providers.
The idea of jailing is not new since it is available in unix based BSD as bsd jails and solarise as zones from years. But in linux it was started with chroot and is available due to namespaces present in linux kernel.

Namespaces

Namespaces are features avaliable in linux to isolate process in different system resource aspects.There are 6 type of namespaces avaliable till kernel 4.0, more can be added in future

mnt (mount points,filesystems)
pid (processes)
net (network stack)
ipc (System V IPC)
uts (hostname)
user (UIDs)

Linux namespace is not new,first one is added in linux in 2008 (linux kernel 2.6) but become useable more recently in linux kernel 3.6 when the work of most complex namespace user namespace has completed.Linux kernel use clone(),unshare() and setns() system call to create and control namespaces.Creation of new namespace is done by clone() system call which also use to start a process.setns() system call adds a running process to the existing namespace.unshare() call work on process inside namespace and make the caller member of namespace.Its main purpose is also to isolate namespace without having to create a new process or thread (as is done by clone()).You can directly use some services to get the feature of these namespaces.The CLONE_NEW* identifiers is use with these system call to indentify the type of namespace.these three system calls make use of the CLONE_NEW* as CLONE_NEWIPC , CLONE_NEWNS , CLONE_NEWNET , CLONE_NEWPID , CLONE_NEWUSER , and CLONE_NEWUTS .Process in a namespace can be differ by its unique inode number when it is created.

#ls -al /proc/<pid>/ns
lrwxrwxrwx 1 root root 0 Feb  7 13:52 ipc -> ipc:[4026532253]
lrwxrwxrwx 1 root root 0 Feb  7 15:39 mnt -> mnt:[4026532251]
lrwxrwxrwx 1 root root 0 Feb  7 13:52 net -> net:[4026531957]
lrwxrwxrwx 1 root root 0 Feb  7 13:52 pid -> pid:[4026532254]
lrwxrwxrwx 1 root root 0 Feb  7 13:52 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Feb  7 15:39 uts -> uts:[4026532252]

Mount namespace:-

Process view diffrent mount point then the original system mount point /.It create a seprate filesystem tree associated with different process which restrict them to make changes to the root filesystem.

Pid namespace

Pid namespace isolate a process ID from the main pid hierarchy.A process inside a pid namespace can have same pid as a process outside it and even inside namespace you can have different init with pid 1.

Uts namespace:-

In uts (Unix Timesharing system) namespace a process can have different set of domainname and hostname then the main system.They use sethostname() and setdomainname() to do that.

IPC namespace:-

Use for interprocess communication resources isolation and POSIX message queue.

User namespace:-

It isolate user and group id inside a namespace which allow to have same uid or gid in namespace as in host machine.In your system unprivileged process can create user namespaces in which they have full privileges.

Network namespaces:-

Inside this namespace processes can have different network stack i.e different network device,ip address,routing table etc.

Sandboxing tools avaliable in linux use these feature namespaces to isolate process or create new virtual enviornment.A much secure tool will be that which use maximum namespace for isolation.Now lets talk about different methods for sandboxing from soft to hard isolation.

chroot

chroot is the oldest sandboxing tool avaliable in linux.Its work is same as mount namespace but is implemented much earlier then that. chroot change the root directory for a process to any chroot directory(like /chroot).As the root directory is the top of the filesystem hierarchy, applications are unable to access directories higher up than the root directory, and so are isolated from the rest of the system. This prevents applications inside the chroot from interfering with files elsewhere on your computer.To create a isolated environment in old SystemV based operating system first you need to copy all required packages and libraries to that directory.
For demonstration I am running "ls" on chroot directory.
First create a directory to set as root filesystem for a process:-

$mkdir /chroot

make important required directories inside it.

$mkdir /chroot/{lib,lib64,bin,etc} 

To get shell inside the chroot you need /bin/bash.

$cp -v /bin/{bash,ls} /chroot/bin

Now the most important step is to copy the executable and libraries.To see libraries required for these script run:

$ldd /bin/bash
linux-vdso.so.1 (0x00007fff70deb000)
libncurses.so.5 => /lib/x86_64-linux-gnu/libncurses.so.5 (0x00007f25e33a9000)
libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007f25e317f000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f25e2f7a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f25e2bd6000)
/lib64/ld-linux-x86-64.so.2 (0x00007f25e360d000)
$ldd /bin/ls
linux-vdso.so.1 (0x00007fff4f8e6000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f9f00aec000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9f00748000)
libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f9f004d7000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9f002d3000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9f00d4f000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9f000b6000)

now copy these files to the lib or lib64 of /chroot as required.
Once you have copied all the necessary file.Its time to enter the chroot.

$sudo chroot /chroot/ /bin/bash

you will be prompt with a shell running inside your virtual environment.Here you don't have much things to run beside 'ls' but it has changed the root filesystem for the process to /chroot.
To get more featured enviornment you can use debootstrap utility to bootstrap a basic debian system

$debootstrap --arch=amd64 unstable my_deb/

it will download a minimal system to run under chroot.You can use this to even test 32-bit applications on 64-bit systems or for testing your program before installation.To get process management mount proc and other important filesystem to the chroot and to make the content of home lost on exit mount tmpfs at /home//

$sudo mount -o bind /proc my_deb/proc
$mount -o bind /dev my_deb/dev
$mount -t sysfs sysfs my_deb//sys

$mount -t tmpfs -o size=100m tmpfs /home/user

to get internet connection inside

$sudo cp /etc/resolv.conf /var/chroot/etc/resolv.conf

after that you are ready to enter inside your enviornment.

$chroot my_deb/ /bin/bash

Here you get a minimal linux distribution inside your chroot.But it only differ from your host system by mount point only since it only uses mount property as isolator. It has same hostname,ip addr and process running as in the host system. That's why it is very less secure (even given in the man page of chroot) and any running process can still harm your computer by killing your tasks or affecting network based services.

Note:
To run graphical applications inside chroot open x server by running this on host system

$xhost +

and on chroot system

$export DISPLAY=:0.0

On systemd based linux chrooting become preety straight forward. Its needed to define the root directory on the processes as unit file only.

[Unit]
Description=my_chroot_Service
[Service]
RootDirectory=/chroot/foobar
ExecStartPre=/usr/local/bin/pre.sh
ExecStart=/bin/my_program
RootDirectoryStartOnly=yes

Here RootDirectory= define where the root directory have to be for foobard process.

Note:
The program script path have to be inside chroot, that make the full path of that process script as /chroot/bin/my_program'

Before the daemon is started a shell script pre.sh is invoked, whose purpose is to set up the chroot environment, i.e. mount /proc and similar file systems into it, depending on what the service might need. You can start your service by

#systemctl start my_chroot_Service.service

Ip-netns

Ip-netns utility is few of utility that directly use network namespace to create virtual interfaces.
To create a new network namespace use

$ip netns add netns1

To check the interfaces inside

$ip netns exec netns ip addr

you can even get the shell inside it

$ip netns exec netns /bin/bash

this will take you inside the network namespace which had only single network interface with no ip.So,we are not connected with the external network and hence can't ping.

$ip netns exec netns ip link set dev lo up

this will bring the loop interface up.But to connect to external network you need to create a virtual ethernet and add it to netns

$ ip link add veth0 type veth peer name veth1
$ ip link set veth1 netns netns1

now its time to set the ip to these interfaces

$ ip netns exec netns1 ifconfig veth1 10.1.1.1/24 up
$ ifconfig veth0 10.1.1.2/24 up

Unshare

Unshare utility is used to create any namespaces isolated environment and run a program or shell inside it.
To get a network namespace and run shell inside it

$unshare --net /bin/bash

The shell you get back will come with different network stack.You can check this by

$ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

To create a user namespace enviornment.

$unshare --user /bin/bash

you can check your user inside shell by

$whoami
nobody

To get pid namespace

$unshare --pid --fork /bin/bash

inside this namespace you can see all the process but cannot kill anyone.

$ps -aux |grep firefox
root      1110 42.6 11.0 1209424 436756 tty1   Sl   23:36   0:15 .firefox1/./firefox
root      1208  0.0  0.0  12660  1648 pts/2    S+   23:37   0:00 grep firefox
$kill 1110
bash: kill: (1110) - No such process

To get whole different process tree isolation you need to mount another proc for namespace

unshare --pid --fork --mount-proc /bin/bash

In this way you can use unshare to create single namespace.More can be found on man page of unshare.

Note:
Created namespace using unshare can also be combine to create a single shell which uses different namespaces For example:-

$unshare --pid --fork --user /bin/bash

will create a isolated enviorment using pid and user namespace.

*** Thats it for this part. In the next part we will look into some more tools for sandboxing. Stay tuned! ***

Shubham Dubey

Shubham Dubey

Besides being a Linux enthusiast, he works in the fields of cloud computing, virtualisation and cyber security(low level security stuff).

Read More