0% found this document useful (0 votes)
5 views

Tutorial7_VM_emulation

This tutorial explains how to emulate a system-level virtual machine on Linux using namespaces and cgroups for resource isolation. It provides a step-by-step guide to creating a minimal program that sets up a VM-like environment, executes a shell, and monitors system resources like CPU and memory. The tutorial includes code examples, explanations of key functions, and instructions for compiling and running the program with root privileges.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views

Tutorial7_VM_emulation

This tutorial explains how to emulate a system-level virtual machine on Linux using namespaces and cgroups for resource isolation. It provides a step-by-step guide to creating a minimal program that sets up a VM-like environment, executes a shell, and monitors system resources like CPU and memory. The tutorial includes code examples, explanations of key functions, and instructions for compiling and running the program with root privileges.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 6

TUTORIAL 7 – EMULATING SYSTEM VIRTUAL MACHINE

To emulate a system-level virtual machine on Linux, we can create a simple VM-like


environment using Linux namespaces and cgroups. These kernel features allow us to
isolate resources such as process IDs (PID), file systems, network interfaces, and memory,
effectively creating a "lightweight" virtual machine (container) that runs commands and
gives us control over system resources.

In this tutorial, we will create a minimal program that:

1. Sets up a Linux namespace to isolate the environment.


2. Executes a simple shell within the isolated environment.
3. Monitors important system resources such as CPU, memory, and disk usage.

We'll use unshare() system calls for creating the namespaces, chroot() for isolating the
filesystem, and cgroups for limiting resources (like CPU and memory).

1. Basic Setup

First, ensure your system supports namespaces and cgroups. For namespaces, you'll
need a kernel version that supports user namespaces (available since Linux 3.8). For
cgroups, make sure you have cgroup support enabled.

2. Creating the Program

The following code will create a very basic virtual machine that isolates the user in a new
namespace and allows them to run a simple shell. It will also monitor the VM's resources
(memory, CPU) periodically.

Full Example Code:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <sched.h> // Include sched.h for namespaces

#define VM_ROOT_DIR "/tmp/vm_root"


#define VM_MOUNT_DIR "/mnt/vm"

void create_vm_rootfs() {
// Create root directory for VM (this is a simple version, you might want to use a real
filesystem)
if (mkdir(VM_ROOT_DIR, 0755) != 0 && errno != EEXIST) {
perror("Failed to create VM root");
exit(1);
}

// Create necessary directories for the VM


if (mkdir(VM_ROOT_DIR "/proc", 0755) != 0 && errno != EEXIST) {
perror("Failed to create /proc directory");
exit(1);
}

if (mkdir(VM_ROOT_DIR "/sys", 0755) != 0 && errno != EEXIST) {


perror("Failed to create /sys directory");
exit(1);
}

// Set up the basic file system for the VM (could be a mounted loopback image)
if (mount("proc", VM_ROOT_DIR "/proc", "proc", 0, NULL) != 0) {
perror("Failed to mount proc");
exit(1);
}
if (mount("sysfs", VM_ROOT_DIR "/sys", "sysfs", 0, NULL) != 0) {
perror("Failed to mount sysfs");
exit(1);
}
}

void execute_vm_shell() {
printf("Entering virtual machine shell...\n");

// The VM will run a simple shell, allowing user interaction


char *const shell_args[] = {"/bin/bash", NULL};
execv(shell_args[0], shell_args);
}

void monitor_resources() {
// Simple resource monitoring function for CPU and memory usage
printf("\n--- Monitoring Resources ---\n");
while (1) {
FILE *cpuinfo = fopen("/proc/stat", "r");
if (cpuinfo) {
char buffer[1024];
fgets(buffer, sizeof(buffer), cpuinfo);
printf("CPU Usage: %s", buffer);
fclose(cpuinfo);
}

FILE *meminfo = fopen("/proc/meminfo", "r");


if (meminfo) {
char buffer[1024];
fgets(buffer, sizeof(buffer), meminfo);
printf("Memory Usage: %s", buffer);
fclose(meminfo);
}

sleep(5); // Monitor every 5 seconds


}
}

int main() {
pid_t pid;
// Create the virtual machine root filesystem
create_vm_rootfs();

// Fork to create a new process for the VM


pid = fork();
if (pid < 0) {
perror("Failed to fork");
return 1;
}

if (pid == 0) {
// In child process, isolate the VM environment
if (unshare(CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID |
CLONE_NEWNET) == -1) {
perror("Failed to unshare namespaces");
exit(1);
}

// Change root to the new root directory for the VM


if (chroot(VM_ROOT_DIR) != 0) {
perror("Failed to chroot");
exit(1);
}

// Change working directory to the root


if (chdir("/") != 0) {
perror("Failed to chdir");
exit(1);
}

// Mount proc and sys again (since we chroot'd)


if (mount("proc", "/proc", "proc", 0, NULL) != 0) {
perror("Failed to mount proc in chroot");
exit(1);
}

if (mount("sysfs", "/sys", "sysfs", 0, NULL) != 0) {


perror("Failed to mount sysfs in chroot");
exit(1);
}

// Execute the shell inside the VM


execute_vm_shell();
} else {
// In the parent process, monitor resources of the VM periodically
monitor_resources();
wait(NULL); // Wait for the child process (VM) to terminate
}

return 0;
}

3. Explanation of the Code:

1. Namespace Isolation:
a. The program uses the unshare() system call to create new namespaces for
the VM. This includes namespaces for the filesystem, network, process IDs,
etc. This ensures that the virtual machine is isolated from the host system.
b. The VM is isolated in a separate user-space environment, meaning that
changes inside the VM (like process IDs) won't affect the host system.
2. Filesystem Isolation (chroot):
After unsharing the namespaces, the program calls chroot() to change the
root directory to a new location. This means the virtual machine can only see
the files within this directory, further isolating it from the host filesystem.
3. Mounting Virtual Filesystems:
The program mounts proc and sysfs in the new root to provide the virtual
machine with essential kernel information, like CPU and memory stats,
which are needed to monitor resources later.
4. Shell Execution:
The program executes a simple shell (/bin/bash) inside the VM, allowing the
user to run commands within the isolated environment.
5. Resource Monitoring:
The program monitors the system's CPU and memory usage by reading from
/proc/stat and /proc/meminfo. It prints the resource usage every 5 seconds
while the VM is running.
Some notes:

1. Create /proc and /sys Directories:


a. Before mounting /proc and /sys, we ensure that the directories exist by
explicitly creating them under VM_ROOT_DIR using mkdir().
b. If the directories already exist, it checks for EEXIST (error code for "directory
already exists") and continues.
2. Mount /proc and /sys:
a. We mount /proc and /sys in the new root (/tmp/vm_root) to ensure that the
virtual machine has access to the procfs and sysfs, which are necessary for
system information like CPU and memory stats.

4. How to Compile and Run:

Compile:

gcc -o simple_vm simple_vm.c

Run with root privileges (as it involves unshare() and chroot()):

sudo ./simple_vm

5. Expected Behavior:

1. The program will first create the necessary directories in the virtual machine's root
directory (/tmp/vm_root).
2. It will mount the proc and sys filesystems.
3. The child process will create the isolated environment (namespace), chroot to
/tmp/vm_root, and mount the filesystems again inside the VM.
4. The virtual machine will run a basic shell (/bin/bash).
5. The parent process will monitor the system resources (CPU and memory usage)
every 5 seconds.

You might also like