Tutorial7_VM_emulation
Tutorial7_VM_emulation
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.
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.
#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
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);
}
// 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");
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);
}
int main() {
pid_t pid;
// Create the virtual machine root filesystem
create_vm_rootfs();
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);
}
return 0;
}
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:
Compile:
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.