Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Kartikharitwal/Myrun---Container-Runtime-Engine

Open more actions menu

Repository files navigation

Myrun

myrun is a small Linux container runtime demo written in C. It implements the core lifecycle described in the prompt:

  • PID, UTS, mount, and optional network namespaces with clone(2)
  • cgroups v2 limits for memory, CPU, and process count
  • OverlayFS writable container layers
  • pivot_root(2) into the merged filesystem
  • a fresh /proc mount inside the PID namespace
  • parent-side cleanup after the container exits

This project targets Linux only and must be run as root because it uses namespace, mount, cgroup, and pivot_root operations.

See SECURITY.md for the rootful security model, current protections, and what real user namespace support would require.

Build

Install a Linux C toolchain first if needed, for example build-essential on Debian/Ubuntu or build-base on Alpine.

make

Prepare a Root Filesystem

One easy test image is an Alpine or BusyBox rootfs. For example, using Docker as a bootstrap step:

docker create --name myrun-alpine alpine:latest
docker export myrun-alpine > /tmp/alpine-rootfs.tar
docker rm myrun-alpine
make import-rootfs NAME=alpine TARBALL=/tmp/alpine-rootfs.tar
sudo ./myrun run images/alpine /bin/sh

The importer accepts any rootfs tarball and unpacks it into images/<name>.

Run

For the built-in BusyBox demo rootfs:

sudo make smoke-test
sudo make cleanup-test
sudo make net-test
sudo make security-test
sudo make seccomp-test
sudo make cli-test
sudo ./myrun run /tmp/myrun-rootfs /bin/sh
sudo ./myrun run images/alpine /bin/sh

With limits:

sudo ./myrun run --memory 100M --cpu 10000:100000 --pids 64 images/alpine /bin/sh

Optional isolated network namespace:

sudo ./myrun run --net images/alpine /bin/sh
sudo ./myrun run --net --host-ip 10.201.0.1/24 --container-ip 10.201.0.2 images/alpine /bin/sh

--net creates a fresh network namespace, wires a veth pair, assigns 10.200.0.1/24 on the host side and 10.200.0.2/24 inside the container by default, and brings both interfaces up. This gives host-to-container connectivity on that private link. Internet access still needs host-side forwarding/NAT, which is intentionally left as a follow-up.

Because the final container process drops capabilities before exec, tools that need special capabilities, such as raw-socket ping, may fail inside the container even when the interface and route are present.

CLI

myrun run [--hostname NAME] [--memory BYTES|K|M|G|max] [--cpu QUOTA:PERIOD|max] [--pids N|max] [--net] [--host-ip CIDR] [--container-ip IP] [--container-netmask MASK] [--seccomp-basic] ROOTFS COMMAND [ARGS...]

Examples:

  • --memory 100M writes 104857600 to memory.max
  • --cpu 10000:100000 writes 10000 100000 to cpu.max
  • --pids 64 writes 64 to pids.max
  • --host-ip 10.201.0.1/24 --container-ip 10.201.0.2 customizes the veth link addresses
  • --seccomp-basic enables a small seccomp filter before the command is executed

Notes

The parent process creates the OverlayFS mount and cgroup, then calls clone() with namespace flags. The child sets the hostname, makes mounts private, pivots into the merged root, mounts /proc, brings up loopback when --net is used, and finally execvp()s the requested command.

The parent writes the child's host PID into cgroup.procs, waits for the container's init process, then unmounts and removes temporary state.

Before executing the requested command, the child sets no_new_privs and drops all effective, permitted, and inheritable Linux capabilities. With --seccomp-basic, it also installs a small seccomp-BPF filter that denies mount, umount2, ptrace, reboot, kernel module loading, and kexec_load.

This is still an educational runtime, not a hardened sandbox. User namespaces and a broader Docker-style seccomp profile are good next security upgrades.

Architecture

myrun is split into a parent-side setup path and a child-side container init path.

user CLI
  |
  v
parent process
  |-- create OverlayFS upper/work/merged dirs
  |-- mount lower rootfs + writable upper layer
  |-- create cgroup v2 directory and write limits
  |-- clone child with PID, UTS, mount, and optional network namespaces
  |-- optionally create veth pair and move one end into child netns
  |-- add child host PID to cgroup.procs
  |-- wait for child exit
  '-- cleanup veth, cgroup, overlay mount, and temp dirs

child process
  |-- become PID 1 inside the new PID namespace
  |-- set UTS hostname
  |-- wait for parent network setup when --net is enabled
  |-- configure loopback and container veth address
  |-- pivot_root into OverlayFS merged root
  |-- mount fresh /proc
  |-- optionally install seccomp filter
  |-- set no_new_privs and drop capabilities
  '-- exec requested command

Feature Matrix

Area Implementation
PID isolation CLONE_NEWPID; target command runs as PID 1 inside the container
Hostname isolation CLONE_NEWUTS; configurable with --hostname
Filesystem isolation OverlayFS plus pivot_root
Mount isolation CLONE_NEWNS; private mount propagation before pivot
Process view fresh /proc mounted after entering the PID namespace
Resource limits cgroups v2: memory.max, cpu.max, pids.max
Networking optional --net with veth pair and configurable private IPv4 link
Image import rootfs tarball import into images/<name>
Cleanup success and failure cleanup tests for temp mounts/cgroups
Security polish no_new_privs, capability drop, optional basic seccomp filter

Demo Script

Run the complete validation suite:

sudo make clean
sudo make smoke-test
sudo make cleanup-test
sudo make net-test
sudo make security-test
sudo make seccomp-test
sudo make cli-test

Useful manual demo commands:

sudo make rootfs
sudo ./myrun run --hostname demo --memory 100M --cpu 10000:100000 --pids 64 /tmp/myrun-rootfs /check.sh
sudo ./myrun run --net --host-ip 10.201.0.1/24 --container-ip 10.201.0.2 /tmp/myrun-rootfs /bin/sh
sudo ./myrun run --seccomp-basic /tmp/myrun-rootfs /bin/sh

Inside an interactive shell, useful checks are:

hostname
ps
cat /proc/1/status
cat /proc/net/dev
cat /proc/net/route

Interview Talking Points

  • Namespaces change what a process can see; they do not make the process disappear from the host. The container's PID 1 is still a normal host PID outside the namespace.
  • PID namespaces only take effect for children, so the runtime uses clone() rather than expecting the current process to become PID 1.
  • /proc must be mounted after entering the PID namespace, otherwise process listings reflect the wrong namespace.
  • OverlayFS separates the read-only image layer from the writable container layer, which is the same core idea behind layered container images.
  • cgroups v2 are configured through filesystem writes, not special container syscalls.
  • pivot_root is stronger than plain chroot because the old root can be detached from the container's mount namespace.
  • The runtime performs privileged setup first, then reduces the final process with no_new_privs, capability dropping, and optional seccomp.
  • Networking is explicit: a new network namespace starts isolated, so the runtime wires connectivity through a veth pair.

Remaining Stretch Goals

  • user namespaces and UID/GID mapping
  • host-side NAT/forwarding for internet access from the container
  • read-only rootfs mode and masked sensitive paths
  • broader Docker-style seccomp profile
  • AppArmor or SELinux integration
  • CI that runs compile-only checks on Linux

About

A mini Linux container runtime in C using namespaces, cgroups v2, OverlayFS, pivot_root, veth networking, and seccomp.

Topics

Resources

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.