πŸ“ ACTC Assignment 2 : Build a "Mini" Container Runtime

This assignment will be formatted and submitted using a simulated Linux kernel mailing list patchset submission and review workflow.

Details of the assignment itself are presented first, followed by submission instructions.

Before beginning work for this assignment, please obtain your credentials by entering your student ID on the registration page.

Then, please enter our fedora container with the following invocation, setting $username and $password appropriately beforehand.

sh -c 'read -rp "username: " username && curl -u $username https://winter2025-iit.actc.underground.software/Containerfile | podman build -t kdlp_container -'

Why do this, why skip... etc TODO

Due dates

Component Date
Initial Submission Deadline EOD Thursday, 25 December 2025
Peer Review Deadline EOD Sunday, 28 December 2025
Final Submission Deadline EOD Tuesday, 30 December 2025

All due dates are 23:59 IST on the day stated

1. Overview

In this assignment, you will demystify container technology (like Docker or Podman) by writing a simple container runtime in C from scratch. You will interact directly with the Linux kernel's isolation primitivesβ€”Namespaces, Cgroups, and Seccompβ€”to create a secure, isolated environment for a process.

By the end of this task, you will have a program that can run a shell inside a custom root filesystem, isolated from the host's process list, hostname, and protected by security policies.


2. Prerequisites


3. Program Requirements

Your program must be named simple_container and accept the following arguments:

sudo ./simple_container <rootfs_path> <command> [args...]

Core Rules


4. Implementation Steps

Phase 1: The Skeleton & Namespace Isolation

Create the basic process structure. Container runtimes typically use clone or unshare to create new namespaces.

Tasks:
  1. Use fork() to create a child process.
  2. The parent waits for the child to exit.
  3. Child uses unshare(CLONE_NEWUTS) to detach its hostname from the host. Unshare other namespaces such as CLONE_NEWNS, CLONE_NEWIPC and CLONE_NEWPID
  4. Child changes its hostname to mycontainer.
Manual pages:
  1. man 2 fork
  2. man 2 unshare
  3. man 7 uts_namespaces
  4. man 2 clone

Phase 2: Filesystem Isolation (The Jail)

Trap the process inside the provided rootfs directory. Do not use chroot. You must use pivot_root for better security.

Tasks:
  1. Private Mounts: Mark the root mount (/) as MS_PRIVATE so mount events don't leak to the host.
  2. Bind Mount: pivot_root requires the new root to be a mount point. Bind mount the rootfs path to itself.
  3. Pivot: Use syscall(SYS_pivot_root, ...) to swap the root.
  4. Cleanup: Unmount the old host root (detach it) and remove the temporary directory.
Manual pages:
  1. man 2 pivot_root

Phase 3: PID Isolation (Process Identity)

Isolate the process IDs so the container cannot see host processes.

Food for thought

There are two ways to make the child PID 1 * Unshare the namespace before forking. * The child forks for a second time.

Tasks (follow the first way):
  1. Refactor Unshare: Add unshare(CLONE_NEWPID) to the Parent process (before the fork) and remove it from the Child's unshare.
  2. Mount /proc: The ps command relies on the /proc filesystem. You must mount a fresh proc filesystem at /proc after pivoting root.
Manual pages:
  1. man 7 pid_namespaces

Phase 4: Resource Isolation (Cgroups)

Prevent the container from consuming all system memory using Cgroup v2.

Tasks (in Parent Process):
  1. Create Group: Create a directory /sys/fs/cgroup/simple_container.
  2. Set Limit: Write "100000000" (100MB) to memory.max in that directory.
  3. Add Process: Write the Child's PID to cgroup.procs.
  4. Cleanup: After the child exits, remove the cgroup directory using rmdir.
Man pages
  1. man 7 cgroups

Phase 5: Security - Capabilities

The root user inside a container shouldn't be as powerful as the real root.

Tasks (in Child Process):
  1. Create a whitelist of exactly these allowed capabilities: CAP_KILL, CAP_SETGID, CAP_SETUID, CAP_NET_BIND_SERVICE, CAP_SYS_CHROOT
  2. Use capng_clear to wipe the slate clean.
  3. Use capng_update to add your whitelist to Effective, Permitted and Bounding sets.
  4. Apply the changes with capng_apply.
Man pages
  1. man 7 capabilities
  2. man 3 capng_clear, capng_update, capng_apply

Phase 6: Security - Seccomp (Syscall Filtering)

Restrict which system calls the container can make to the kernel.

Tasks (in Child Process):
  1. Initialize a filter with seccomp_init(SCMP_ACT_ALLOW) (Allow-list by default).
  2. Add rules to block specific syscalls: reboot, swapon, swapoff, init_module, finit_module and delete_module. Use SCMP_ACT_ERRNO(EPERM) to return a permission error. Using the SCMP_SYS() macro is recommended.
  3. Load the filter into the kernel using seccomp_load.
Man pages

1. man 2 seccomp

5. Helpful Snippets

pivot_root wrapper is not in the standard libc headers. You must define a wrapper:

static int pivot_root(const char *new_root, const char *put_old) {
    return syscall(SYS_pivot_root, new_root, put_old);
}

Compiling: You must link against the security libraries:

gcc -o simple_container simple_container.c -lcap-ng -lseccomp
# pkg-config --libs libcap-ng  libseccomp # to see these flags


6. Submission

Submit patches-by-mail with a single C file named simple_container.c, a README and a Makefile.

Submitting this assignment

The assignment must be submitted in the form of an email patchset generated by git format-patch from commits made in your local copy of this repository that includes a cover letter describing your work. You will use git send-email to submit the assignment as described above.

As part of the peer review process, this assignment will require you to submit your patchset at least twice.

Start the assignment early. If you run into issues and get stuck it gives you time to ask questions and get help before the deadlines so you can submit something on time and get credit for the assignment. If you finish early, you can resubmit as many times as you'd like.

Any submission that violates these guidelines or fails to compile with no warnings or errors will receive a zero.

With the exception of presentations, all work in this course takes place on our mailing list. Students submit assignments and review peer submissions on this list.

Each assignment involves the following three stages:

Step 1: Initial Submission (due Thursday, 25 December 2025)

Step 2: Peer Review (due Sunday, 28 December 2025)

Acked-by: $FIRSTNAME $LASTNAME <$USERNAME@winter2025-iit.actc.underground.software>
Nacked-by: $FIRSTNAME $LASTNAME <$USERNAME@winter2025-iit.actc.underground.software>

Step 3: Final submission (due Tuesday, 30 December 2025)


msg = (silence)
whoami = None
singularity v0.8 https://github.com/underground-software/singularity