Module 5 · Unit 12 · Lesson 6 of 7
Sandboxing
Lesson 12.5 presented the Linux security's mechanisms: the identity's model, the permissions, the capabilities, the LSM's modules, and the hardening's practices. This lesson presents the confinement's mechanisms: the designs that restrict a process (or a group of processes) to the minimum resources it needs, so a compromise's damage is bounded. The sandbox is the security's least privilege's principle applied at the process's level: the untrusted's code (a web page's JavaScript, a downloaded's application, a container's image) runs inside the sandbox, and the sandbox's walls — the namespaces, the cgroups, the seccomp's filters, the LSM's profiles — confine the code to the resources it was granted. The lesson presents the isolation's mechanisms, the Linux namespaces and the cgroups, the seccomp's filters, the containers, and the browsers' sandboxes, and it shows how the mechanisms combine into the modern systems' confinement's designs.
01 Introduction
The security's classical's model (Lessons 12.1–12.5) is the perimeter's defence: the system's boundary (the network's firewall, the user's account) protects the trusted's interior, and the interior's components (the users, the processes, the applications) trust one another. The model's assumption is the perimeter's impermeability, and the modern's threats (the remote's code's execution, the supply chain's compromise, the malicious's insider, the malware) invalidate the assumption: the attacker who breaches the perimeter (or the user who runs the untrusted's code) has the interior's trust, and the damage's scope is the whole system. The sandbox is the answer to the assumption's failure: the untrusted's code runs in the isolated's environment (the sandbox), and the sandbox's walls confine the code's capabilities to the minimum it needs. The compromise's damage is the sandbox's damage, not the system's.
The sandboxing is the security's least privilege's principle (Lesson 12.1's principle 6) applied at the process's (or the process group's) level: the process is granted the minimum resources it needs to do its work, and the kernel's mechanisms enforce the grant. The sandbox's walls are the mechanisms that the operating system provides:
- The namespaces (the isolation's mechanisms: the process's view of the file system, the process's table, the network, the IPC, the users, the hostname, the cgroups, and the time).
- The control groups (cgroups) (the resource's limits: the CPU's share, the memory's cap, the I/O's bandwidth, the process's count).
- The seccomp's filters (the system calls' restrictions: the whitelist or the blacklist of the system calls the process may invoke).
-
The capabilities (the fine-grained's
privileges: the process's capability's sets'
restriction, the
CapabilityBoundingSet's design). - The LSM's profiles (the SELinux's types, the AppArmor's profiles: the mandatory access control's confinement).
- The chroot and the pivot_root (the file system's confinement: the process's root's directory's change).
-
The systemd's hardening's
directives (the services'
confinement: the
ProtectSystem, theProtectHome, thePrivateTmp, theNoNewPrivileges, theRestrictAddressFamilies). - The Landlock (the unprivileged's sandboxing: the file system's access's restriction for the unprivileged's processes).
- The virtual machines (the strongest's isolation: the hardware's virtualization, the hypervisor's confinement). The VMs are the unit's next's subject (Unit 13), and they are the sandbox's extreme's case.
The sandboxing's design's central's principle is the defence in depth (Lesson 12.1's principle): the sandbox's walls are the multiple's mechanisms, and the compromise requires the multiple's failures. A well-designed's sandbox (the Chrome's, the modern's containers) combines the namespaces, the seccomp, the capabilities' minimization, the LSM's profiles, and the cgroups, so the attacker who escapes one layer is still confined by the others. The observation is the reason the sandboxing is the modern security's central's architecture: the untrusted's code's execution is the unavoidable (the web, the applications, the containers), and the sandbox is the design that makes the execution's risk acceptable.
This lesson presents the sandboxing. It defines the isolation's goals and the confinement's spectrum. It presents the Linux namespaces (the eight namespaces and their isolation's semantics). It presents the control groups (the v1 and the v2 and the resource's controllers). It presents the seccomp's BPF filters (the system calls' restrictions and their design). It presents the chroot and the pivot_root (the file system's confinement), the containers (the Docker, the Podman, the LXC, and the OCI's standards), and the browsers' sandboxes (the Chrome's and the Firefox's designs). It presents the systemd's hardening's directives and the Landlock's unprivileged's sandboxing. It presents the sandbox's escapes' attacks and the sandboxing's design's principles. It closes with the sandboxing's role in the modern systems and the lesson's synthesis.
Prerequisites
This lesson builds on Lessons 12.1 through 12.5.
The security's goals (the CIA triad), the AAA
model, the reference monitor, the Saltzer and
Schroeder principles, and the defence in depth
are assumed (Lesson 12.1). The authentication's
mechanisms are assumed (Lesson 12.2). The
authorization's concepts, the access control
matrix, and the four models (the DAC, the MAC,
the RBAC, the ABAC) are assumed (Lesson 12.3).
The formal models (the Bell-LaPadula, the Biba,
the Clark-Wilson) are assumed (Lesson 12.4).
The Linux security's mechanisms (the identity's
model, the permissions, the capabilities, the
LSM's framework, the SELinux, the AppArmor) are
assumed (Lesson 12.5). The virtual memory and
the process's model (Units 3, 8, and 9) are the
context for the namespace's and the cgroup's
discussions. Familiarity with the Linux command
line from Lesson 2.2 is essential, since the
interactive activity uses the
unshare, the nsenter,
the ip netns, the
systemd-cgls, the
systemd-run, the
docker (or the podman),
the chroot, and the
systemd-analyze security commands.
02 Learning objectives
By the end of this lesson you will be able to
- Define the sandbox and explain the isolation's goals, and describe the confinement's spectrum from the chroot to the virtual machines.
- Describe the Linux namespaces (the mount, the PID, the network, the user, the IPC, the UTS, the cgroup, and the time) and explain each namespace's isolation's semantics.
- Describe the control groups (the v1 and the v2) and their resource's controllers, and explain how the cgroups enforce the resource's limits.
- Describe the seccomp's BPF filters, the chroot and the pivot_root, and the systemd's hardening's directives, and explain how each contributes to the confinement.
- Describe the Linux containers (the Docker, the Podman, the LXC, and the OCI's standards) and the browsers' sandboxes (the Chrome's and the Firefox's designs), and explain their isolation's designs.
- Explain the sandbox's escapes' attacks and the sandboxing's design's principles, and evaluate a sandbox's strength against the lesson's criteria.
This lesson contributes to U12.6 and U12.7, and to course learning outcomes CLO1, CLO7, and CLO8.
03 Required reading
- Operating System Concepts — Chapter 16, Security, the sections on the isolation's mechanisms, and Chapter 17, Protection. The standard treatment of the protection's mechanisms and the isolation's goals.
- OSTEP — the Security chapters, and the Virtualization chapters (the discussion of the containers and the VMs). OSTEP's treatment of the virtualization's mechanisms is the clearest available account of the isolation's designs, and it is the basis for the worked example in this lesson.
- Tanenbaum & Bos — Modern Operating Systems, Chapters 7 (the virtualization) and 9 (the security). A complementary treatment that develops the isolation's mechanisms from first principles.
- Kerrisk, M. — The Linux Programming Interface. No Starch Press, 2010. Chapters 20 (the signals), 24 (the process creation), 28 (the process's credentials), 37 (the daemons), and 61 (the sockets). The definitive reference for the Linux process's isolation's mechanisms.
-
Kerrisk, M. — The Linux
namespaces and the containers. The
man 7 namespacespage and the LWN's articles ("The namespaces in the operating system"). The authoritative reference for the Linux namespaces. - Rosen, R. — Resource Management: The Linux and the SUSE Approaches. The Novell/SUSE's and the RHEL's resource-management's guides. The authoritative references for the cgroups.
- Edge, J., & other LWN's authors. — The LWN's series on the seccomp's filters, the Landlock, and the container's security. The LWN's articles are the authoritative references for the modern's isolation's mechanisms.
- Reis, C. — Docker and the OCI: The container's standards. The OCI's specifications (the Runtime's Specification, the Image's Specification, the Distribution's Specification). The authoritative references for the container's standards.
- Rice, L. — Container Security. O'Reilly, 2020. The comprehensive treatment of the container's security's mechanisms and the escapes' attacks.
-
Linux man pages:
man 7 namespaces,man 2 clone,man 2 unshare,man 1 unshare,man 1 nsenter,man 2 setns,man 5 proc(the/proc/PID/ns/interface),man 7 cgroups,man 1 systemd-cgls,man 1 systemd-cgtop,man 1 systemd-run,man 5 systemd.resource-control,man 2 seccomp,man 3 seccomp_init(thelibseccomp),man 1 systemd-analyze(thesecurityverb),man 2 chroot,man 1 chroot,man 2 pivot_root,man 8 docker,man 1 podman,man 1 docker-run,man 1 docker-exec,man 1 firejail,man 1 bubblewrap,man 7 landlock(if available),man 2 seccomp_unotify,man 5 systemd.exec,man 5 systemd.resource-control.
Reading strategy
Read the man 7 namespaces page first.
It is the authoritative reference for the Linux
namespaces, and it explains the eight namespaces
(the mount, the PID, the network, the user, the
IPC, the UTS, the cgroup, and the time) and
their isolation's semantics with the precision
that the lesson's discussion requires. Then read
the man 7 cgroups page for the
control groups' design and the v1's and the v2's
differences. The Kerrisk book is the deeper's
reference, and its chapters on the process's
creation and the credentials are the context
for the clone's and the
unshare's discussions. The Rice
book is the comprehensive's container's
security's reference, and it is worth reading
for the escapes' attacks and the defence's
designs. The OCI's specifications are the
container's standards, and they are worth
consulting for the container's runtime's
design. Finally, the Linux man pages are the
practical's tools: the unshare and
the nsenter create and enter the
namespaces, the ip netns manages
the network's namespaces, the
systemd-cgls and the
systemd-cgtop display the
cgroups' hierarchy, the systemd-run
creates the transient's services with the
resource's limits, and the
systemd-analyze security evaluates
a service's sandbox's strength. Pay particular
attention to the distinction between the
namespaces (the isolation's
mechanisms: the process's view of the
resources) and the cgroups (the
resource's limits: the process's usage
of the resources). The two are the
complementary's mechanisms: the namespaces hide
the resources (the process cannot see the other
namespaces' processes, files, and networks),
and the cgroups limit the resources (the
process cannot use more than the cgroup's
grant). The observation is the reason the
modern's containers combine the both: the
container's process sees the container's
namespace's view, and the container's cgroup
caps the process's resource's usage.
04 Core content
4.1 The sandbox and the confinement's spectrum
A sandbox is the isolated's environment in which the untrusted's code (or the untrusted's user's code) runs, with the walls that confine the code's capabilities to the minimum it needs. The sandbox's goals:
- The damage's limitation. The compromise's damage is the sandbox's damage, not the system's: the attacker who compromises the sandboxed's code has only the sandbox's resources.
- The least privilege's enforcement. The sandbox's code has only the resources it needs (the least privilege's principle), so the compromised's code's capabilities are the minimum.
- The isolation's guarantee. The sandbox's code cannot affect the system's other's components (the other processes, the other users, the other applications), and the system's other's components cannot affect the sandbox's code (except through the sandbox's allowed's channels).
- The multi-tenancy's support. The sandboxes can coexist on the same system (the server's containers, the browser's tabs, the mobile's applications), and each sandbox's code is confined to its own's resources.
The sandbox's confinement's spectrum is the range of the isolation's mechanisms, from the weakest (the chroot) to the strongest (the virtual machines):
| Mechanism | The isolation's scope | The strength | The typical use |
|---|---|---|---|
| chroot | The file system's view (the root's directory's change) | Weak (the escapes are the known, the privileged's user can bypass) | The build's environments, the legacy's services |
| The capabilities | The fine-grained's privileges | Medium (the capability's model's breadth) | The services' privilege's restriction |
| The LSM's profiles (the AppArmor, the SELinux) | The mandatory access control's policy | Medium to strong (the policy's coverage) | The services' confinement, the browsers' profiles |
| seccomp | The system calls' filter | Strong (the attack's surface's reduction) | The browsers, the containers, the systemd's services |
| The namespaces | The process's view of the file system, the PIDs, the network, the IPC, the users, the hostname, the cgroups, the time | Strong (the kernel's enforced) | The containers, the browsers, the systemd's services |
| The cgroups | The resource's usage's limits | Medium (the limit's enforcement, not the isolation) | The containers, the systemd's services, the user's sessions |
| The virtual machines | The hardware's virtualization (the CPU, the memory, the devices) | Strongest (the separate's kernel) | The cloud's multi-tenancy, the browsers' isolated's processes, the untrusted's code's execution |
The spectrum's central's observation: the mechanisms are the complementary, not the alternatives. The modern's sandboxes (the Chrome's, the containers) combine the mechanisms: the namespaces provide the isolation's view, the cgroups provide the resource's limits, the seccomp provides the system calls' filter, the capabilities provide the privilege's minimization, and the LSM's profiles provide the mandatory access control's policy. The combination's design is the defence in depth's principle (Lesson 12.1): the attacker must bypass the multiple's mechanisms, and the multiple's mechanisms' failures are the uncorrelated.
4.2 The Linux namespaces
The Linux namespaces are the kernel's mechanisms that give the processes the isolated's views of the system's resources. The namespace's design: the kernel's resources (the processes, the files, the networks, the IPC's objects, the users) are tagged with the namespace's identifier, and the processes see only the resources with their own's namespace's identifier. The namespaces' types (the eight):
- The mount's namespace (
CLONE_NEWNS) -
The isolation of the file system's mount's
points: the processes in the different mount's
namespaces see the different file system's
hierarchies. The mount's namespace's design:
the processes'
mountandumountoperations affect only their own's namespace, so a container's file system's mounts are the container's, not the host's. The mount's namespace is thechroot's modern's successor: the container's file system's view is the namespace's mount's table, not the process's root's directory's change. - The PID's namespace (
CLONE_NEWPID) -
The isolation of the process's table: the
processes in the different PID's namespaces
have the different PID's numbers. The
namespace's design: the first process in the
new's namespace has the PID 1 (the init's
process), and the processes' PIDs in the
namespace are the namespace's internal's
numbers; the host's kernel's view shows the
processes with the host's PIDs (the
namespace's PIDs' mapping). The design's
consequence: the process in the namespace
cannot see the other namespaces' processes
(the
/procshows only the namespace's processes), and the PID 1's process's death kills the namespace's other processes. - The network's namespace (
CLONE_NEWNET) - The isolation of the network's stack: the processes in the different network's namespaces have the different network's interfaces, the different routing's tables, the different firewall's rules, the different sockets. The namespace's design: the new's network's namespace starts with only the loopback's interface, and the administrator (or the container's runtime) configures the namespace's interfaces (the virtual's Ethernet pairs, the bridges, the IP's addresses). The network's namespace is the containers' network's isolation's mechanism: the container's processes see only the container's network, and the container's network is the virtual's Ethernet's pair, which connects to the host's bridge (or the overlay's network).
- The user's namespace (
CLONE_NEWUSER) -
The isolation of the user's and the group's
IDs: the processes in the different user's
namespaces have the different UIDs and GIDs'
mappings. The namespace's design: the
namespace's process can be the root (the UID
0) inside the namespace while the host's
kernel sees the process with the
namespace's owner's UID (the unprivileged's
user's UID), so the unprivileged's user can
create the namespace and be the root inside
it (the rootless's containers).
The namespace's subtlety: the mapping is the
explicit (the
/proc/PID/uid_mapand the/proc/PID/gid_map), and the mapping's design determines the namespace's capabilities (the mapped's UIDs have the namespace's privileges, the unmapped's UIDs have the none). - The IPC's namespace (
CLONE_NEWIPC) - The isolation of the System V's IPC and the POSIX's message queues: the processes in the different IPC's namespaces have the different IPC's objects (the shared's memory's segments, the semaphores, the message's queues). The design's purpose: the processes' IPC's isolation, so the container's processes cannot see the host's IPC's objects.
- The UTS's namespace (
CLONE_NEWUTS) - The isolation of the hostname and the NIS's domain name: the processes in the different UTS's namespaces have the different hostnames. The design's name: the UTS is the Unix Time-sharing System (the historical's name), and the namespace's design's purpose is the containers' hostname's isolation.
- The cgroup's namespace (
CLONE_NEWCGROUP) -
The isolation of the cgroup's hierarchy's view:
the processes in the different cgroup's
namespaces see the different cgroup's
hierarchies (the
/proc/PID/cgroupand the/sys/fs/cgroup's views). The design's purpose: the container's processes see only the container's cgroup's subtree, so the container's processes cannot see the host's cgroup's structure. - The time's namespace (
CLONE_NEWTIME) -
The isolation of the boot's time and the
monotonic's clock's offsets: the processes in
the different time's namespaces have the
different offsets. The namespace's design is
the newest (the Linux 5.6), and its purpose
is the containers' time's isolation (the
containers can have the different
CLOCK_MONOTONICandCLOCK_BOOTTIME's values, so the containers can be checkpointed and restored).
The namespaces' management's mechanisms:
-
The
clone's system call (man 2 clone). The system call that creates the new's processes with the namespace's flags (theCLONE_NEWNS, theCLONE_NEWPID, theCLONE_NEWNET, theCLONE_NEWUSER, theCLONE_NEWIPC, theCLONE_NEWUTS, theCLONE_NEWCGROUP, theCLONE_NEWTIME). The new's process runs in the new's namespaces, and the process's children inherit the namespaces. -
The
unshare's system call and theunshare's command. The mechanism that moves the calling's process into the new's namespaces (without theclone's new's process). Theunshare's command (theutil-linux's tool) is the administrator's and the developer's tool for the namespace's experiments:unshare --mount --pid --fork --mount-proc /bin/bashcreates a new's shell with the new's mount and PID's namespaces. -
The
setns's system call and thensenter's command. The mechanism that moves the calling's process into the existing's namespaces (the/proc/PID/ns/'s file descriptors). Thensenter's command is the administrator's tool for the entering of a container's namespaces:nsenter --target <PID> --mount --pid --net /bin/bashenters the container's namespaces and runs the shell inside them. -
The
/proc/PID/ns/'s interface. The kernel exposes the process's namespaces as the symbolic links (/proc/PID/ns/mnt, the/proc/PID/ns/pid, the/proc/PID/ns/net, the/proc/PID/ns/user, the/proc/PID/ns/ipc, the/proc/PID/ns/uts, the/proc/PID/ns/cgroup, the/proc/PID/ns/time), and the process can open the links and pass the file descriptors to thesetns's call. The/proc/PID/ns/'s links' values (themnt:[4026531840]'s format) are the namespace's identifiers, and the processes with the same identifier share the namespace. -
The
ip netns's command. Theiproute2's tool for the network's namespaces' management: theip netns addcreates a named's network's namespace (the/var/run/netns/'s bind mount), theip netns listlists them, theip netns execruns a command in the namespace, and theip netns deldeletes it.
The namespaces' design's observations:
- The namespaces are the views, not the limits. The namespaces isolate the processes' views of the resources, but they do not limit the processes' usage of the resources. The limits are the cgroups' role (section 4.3), and the two mechanisms are the complementary.
-
The namespaces' capabilities' checks
are the privileged's operations. The
namespace's creation requires the
CAP_SYS_ADMIN's capability (the classic's requirement), except the user's namespace (theCLONE_NEWUSERis the unprivileged's since the Linux 3.8), and the user's namespace is the rootless's containers' foundation. - The namespace's nesting. The namespaces can be nested (the namespace's process can create the new's namespaces within it), and the nesting's design is the containers' the-inside's containers (the Docker's in the Docker's) and the rootless's containers' mechanism.
system.slice, the
user.slice, the container's
cgroup), and the resource's controllers (the
cpu, the memory, the
io, the pids, and the
others) that the cgroups use to limit the
processes' resource's usage. The two mechanisms
are the complementary: the namespaces isolate
the views, and the cgroups limit the usage.
4.3 The control groups (cgroups)
The control groups (cgroups) are the kernel's mechanisms that limit and account the processes' resource's usage. The cgroups' design: the processes are organized into the hierarchy of the groups (the cgroups), and the resource's controllers (the subsystems) attach to the groups and enforce the resource's limits. The cgroups' two versions:
- The cgroups v1 (the classical's design)
-
The v1's design: the multiple hierarchies,
one per the resource's controller (the
cpu's hierarchy, thememory's hierarchy, theblkio's hierarchy, thepids's hierarchy, and the others). The process can be in the different groups in the different hierarchies, and the controllers' limits are the separate. The v1's design's disadvantage: the complexity (the multiple hierarchies, the controllers' interactions, the inconsistent's semantics), and the observation is the reason the v2 replaced it. - The cgroups v2 (the unified's design)
-
The v2's design: the single's hierarchy (the
/sys/fs/cgroup/'s unified's tree), with the controllers attached to the groups' nodes (thecgroup.controllers, thecgroup.subtree_control). The v2's design's advantages: the consistency (the single hierarchy, the controllers' coherent's semantics), the delegation (the unprivileged's users can manage the sub-hierarchies), the pressure's information (thecgroup.pressure's interfaces: the/proc/pressure/'s and thecgroup.pressure's metrics), and the nesting (the container's runtime can create the sub-cgroups). The modern's distributions (the Fedora's, the Ubuntu's recent, the Debian's recent) use the v2 by default, and the v1's controllers' migration is the ongoing.
The cgroups' resource's controllers:
-
The
cpu's controller. The CPU's time's allocation: thecpu.weight(the relative's share: the v2's design, the 1–10000's range) and thecpu.max(the absolute's quota: the<quota> <period>'s format, for example the "200000 1000000" for the 20% of the one CPU). -
The
memory's controller. The memory's limits: thememory.max(the hard's limit: the cgroup's processes' total's memory's usage's cap, and the exceeding's allocation fails), thememory.high(the soft's limit: the exceeding's allocation is throttled), thememory.lowand thememory.min(the protection's limits: the pages' reclaim's preference), and thememory.swap.max(the swap's limit). -
The
io's controller. The I/O's limits: theio.weight(the relative's share), theio.max(the per-device's absolute's limit: thethe major:minor the rbps=... the wbps=... the riops=... the wiops=...'s format), and theio.latency(the latency's target: the cgroup's I/O's latency's guarantee). -
The
pids's controller. The process's count's limit: thepids.max(the maximum's number of the processes and the threads in the cgroup, and the exceeding's fork fails). The controller's purpose: the fork's bomb's prevention (the process's count's limit bounds the damage). -
The other's controllers. The
cpuset(the CPU's and the memory's nodes' binding), thehugetlb(the huge pages' limit), thefreezer(the cgroup's processes' freezing), therdma(the RDMA's resources' limit), thedevices(the devices' access's control: the cgroup's allow or deny of the device's nodes), and thenet_clsand thenet_prio(the network's classification and the priority).
The cgroups' management's mechanisms:
-
The
/sys/fs/cgroup/'s interface. The cgroups' file system: the administrator creates the cgroups (the directories), sets the controllers' limits (the files' writes), and moves the processes into the cgroups (thecgroup.procs's and thecgroup.threads's files' writes). -
The
systemd's integration. The systemd manages the cgroups on the modern's systems: the services are the cgroups (thesystem.slice, theuser.slice, themachine.slice), the services' units' resource's directives (theCPUWeight, theCPUQuota, theMemoryMax, theMemoryHigh, theIOWeight, theTasksMax, and the others) configure the limits, and the tools (systemd-cgls, thesystemd-cgtop, thesystemctl status) display the cgroups' state. -
The
systemd-run's command. The tool that creates the transient's services (thesystemd-run --unit=myjob --property=MemoryMax=1G --property=CPUQuota=50% command), and the tool is the administrator's and the developer's mechanism for the ad-hoc's resource's limits. -
The
cgroupfs's and thecgroup2's mounts. The v1's multiple's mounts (the/sys/fs/cgroup/cpu, the/sys/fs/cgroup/memory, the others) and the v2's single's mount (the/sys/fs/cgroup/), with thecgroup_no_v1='s and thesystemd.unified_cgroup_hierarchy=1's kernel's parameters controlling the version.
The cgroups' design's observations:
- The cgroups are the limits, not the isolation. The cgroups limit the processes' resource's usage, but they do not isolate the processes' views. The isolation is the namespaces' role, and the two are the complementary (the section 4.1's observation).
-
The cgroups' metrics. The
cgroups expose the processes' resource's
usage (the
cpu.stat, thememory.current, theio.stat, thepids.current), so the administrator can monitor the usage and tune the limits. The pressure's stall's information (thecpu.pressure, thememory.pressure, theio.pressure) shows the resource's contention, and the information is the modern's monitoring's basis. -
The cgroups' delegation. The
v2's design supports the delegation: the
unprivileged's user (or the container's
runtime) can create the sub-cgroups within
the delegated's cgroup (the
systemd'sDelegate=yes's directive), and the delegation's design is the rootless's containers' and the user's sessions' foundation.
4.4 The seccomp's filters
The seccomp (the secure
computing's mode) is the kernel's mechanism that
filters the process's system calls. The
mechanism's design: the process installs the
BPF's filter (the Berkeley Packet
Filter's program) that the kernel evaluates on
the every's system call, and the filter's
action determines the system call's
fate: the SECCOMP_RET_ALLOW (the
system call's execution), the
SECCOMP_RET_ERRNO (the system call
returns the specified's error), the
SECCOMP_RET_KILL_PROCESS (the
process is killed), the
SECCOMP_RET_KILL_THREAD (the
thread is killed), the
SECCOMP_RET_TRAP (the
SIGSYS's signal's delivery), the
SECCOMP_RET_TRACE (the tracer's
notification), the
SECCOMP_RET_LOG (the system call's
logging), and the
SECCOMP_RET_USER_NOTIF (the
user-space's supervisor's notification).
The seccomp's modes:
-
The strict's mode
(
SECCOMP_MODE_STRICT). The original's mode: the process can invoke only theread, thewrite, the_exit, and thesigreturn's system calls. The mode's design's purpose: the minimal's filter for the untrusted's code, and its use is the rare (the modern's systems use the filter's mode). -
The filter's mode
(
SECCOMP_MODE_FILTER). The modern's mode: the process installs the BPF's program that filters the arbitrary's system calls, and the program's action determines the fate. The mode's design's advantages: the flexibility (the arbitrary's filters), the performance (the BPF's compiled's program's evaluation's efficiency), and the composability (the multiple's filters' stacking, theseccomp's filters' addition's restriction: the additional's filters can only be the more restrictive).
The seccomp's design's observations:
- The seccomp's filter is the attack's surface's reduction. The system calls are the kernel's interface, and the kernel's bugs (the vulnerabilities) are the system calls' exploits. The seccomp's filter reduces the exposed's system calls, so the kernel's attack's surface is the smaller. The observation is the reason the browsers (the Chrome's and the Firefox's sandboxes) and the containers (the Docker's default's profile) use the seccomp's filters: the untrusted's code's system calls are the restricted's set, so the kernel's vulnerabilities' exploitation is the harder.
-
The seccomp's filter's design's
subtleties. The filter's whitelist
(the allow's list: the system calls the
process may invoke, and the every's other's
system call is the denied) is the stronger's
design; the filter's blacklist (the deny's
list: the system calls the process may not
invoke) is the weaker (the unknown's system
calls are the allowed). The filter's
granularity: the seccomp's filter can
inspect the system call's number and its
arguments (the scalar's values, the
pointers' values, not the pointed's data),
so the filter's design can be the
fine-grained (the
open's arguments' flags' inspection) or the coarse-grained (the system call's number's only). -
The
libseccomp's library. The user-space's library that generates the BPF's filters from the high-level's descriptions (theseccomp_rule_add's calls), and the library is the developers' tool for the seccomp's filters' design. Thesystemd'sSystemCallFilter='s directive uses the library (or the pre-defined's groups: the@system-service, the@basic-io, the@network-io, the@process), and the containers' runtimes use the library for the default's profiles.
4.5 The chroot and the pivot_root
The chroot is the classical's
file system's confinement's mechanism: the
chroot's system call changes the
process's root's directory (the
/'s view) to the specified's
directory, so the process and its children see the
specified's directory as the root. The
mechanism's design's purpose: the file system's
view's restriction (the process cannot access the
files outside the chroot's directory by the
absolute's paths). The mechanism's design's
weakness: the chroot is not the security's
boundary. The process with the
CAP_SYS_CHROOT's capability can
escape (the chroot's nesting's
tricks, the chdir's tricks), and
the root's process can escape by the multiple's
mechanisms (the /proc's access, the
mknod's device's creation, the
ptrace's debugging). The
observation is the reason the chroot is the
convenience's mechanism (the build's
environments, the legacy's services), not the
security's: the modern's sandboxes use
the mount's namespace (the
CLONE_NEWNS) and the
pivot_root's mechanism instead.
The pivot_root is the modern's
mechanism: the pivot_root's system
call changes the process's root's and the
current's directory to the new's file system,
and it moves the old's root to the specified's
directory (the put_old). The
mechanism's design's difference from the chroot:
the pivot_root changes the root's mount,
not the directory, so the old's root is
the separate's mount (the
put_old's directory), and the
process can unmount it (the umount's
operation), so the escape's paths (the
/proc's, the
chroot's) are the closed. The
pivot_root is the containers' runtimes' mechanism
(the runc's, the
crrun's, the LXC's): the
container's file system is the mount's
namespace's root, and the host's file system is
the unmounted's (or the hidden's) mount.
4.6 The containers
The containers are the modern's sandboxing's architecture: the processes (the container's processes) run in the isolated's environment (the container), and the environment is the combination of the namespaces, the cgroups, the seccomp's filters, the capabilities' minimization, the LSM's profiles, and the container's file system (the image's layers). The containers' design's observation: the containers are not the virtual machines (the containers share the host's kernel, and the VMs have the separate's kernel), and the containers' isolation is the kernel's mechanisms' (the namespaces and the cgroups), while the VMs' isolation is the hardware's virtualization's (the hypervisor and the separate's kernel).
The containers' components:
-
The container's image. The file
system's template: the layered's file system
(the OCI's image's specification: the layers
are the tar's archives, and the layers are
the stacked's file systems via the
overlayfs's union mount), the image's configuration (the entrypoint, the command, the environment's variables, the exposed's ports), and the image's metadata. -
The container's runtime. The
program that creates the container's
environment: the low-level's runtimes (the
runc, thecrun) create the namespaces, the cgroups, the seccomp's filters, and the file system's mounts; the high-level's runtimes (the Docker'scontainerd, the Podman'sconmon, the LXC'slxc-start) manage the container's lifecycle (the image's pulling, the container's creation, the container's start, the container's stop, the logs). -
The container's engine. The
user-facing's tool: the Docker's
dockerd, the Podman'spodman(the daemonless's design), the LXC'slxc-*, the Kubernetes'skubelet(the orchestrator's agent). The engine's design varies: the Docker's daemon's architecture (the client's and the daemon's separation), the Podman's daemonless's design (the rootless's containers' support), and the Kubernetes's declarative's design. - The container's standards. The Open Container Initiative (the OCI) defines the standards: the Runtime's Specification (the container's configuration and the runtime's interface), the Image's Specification (the image's format and the layers), and the Distribution's Specification (the registry's protocol). The standards' purpose: the interoperability (the same image runs on the different runtimes: the Docker, the Podman, the containerd, the CRI-O), and the standards' design is the container's ecosystem's foundation.
The containers' security's mechanisms:
- The namespaces. The container's runtime creates the container's namespaces (the mount, the PID, the network, the user, the IPC, the UTS, the cgroup), so the container's processes see only the container's resources.
-
The cgroups. The container's
runtime places the container's processes in
the container's cgroup, and the cgroup's
controllers (the
cpu, thememory, theio, thepids) limit the processes' resource's usage. -
The seccomp's filter. The
container's runtime installs the default's
seccomp's filter (the Docker's and the
Podman's default's profiles: the ~44's
blocked's system calls, including the
mount, thereboot, thekexec_load, theinit_module, theptrace), so the container's processes' system calls are the restricted's set. -
The capabilities' minimization.
The container's runtime drops the
unnecessary's capabilities (the Docker's
default: the
CAP_CHOWN, theCAP_DAC_OVERRIDE, theCAP_FOWNER, theCAP_KILL, theCAP_NET_BIND_SERVICE, theCAP_NET_RAW, theCAP_SETGID, theCAP_SETUID, the ~14), and the--cap-drop=ALL --cap-add=CAP_*'s options let the administrator's finer's control. -
The LSM's profiles. The
container's runtime applies the SELinux's
or the AppArmor's profile (the Docker's
default: the
docker-default's AppArmor's profile, or the SELinux'scontainer_t's type), so the container's processes' accesses are the mandatory access control's confined. -
The user's namespace and the rootless's
containers. The container's runtime
can use the user's namespace (the
--userns=host's default's change), so the container's root (the UID 0 inside) is the unprivileged's user (the UID 1000's mapping) on the host, and the container's root's privileges are the bounded (the rootless's containers: the Podman's default's design). -
The read-only's file system and the
tmpfs's mounts. The container's
file system can be the read-only (the
--read-only's option), and the writable's paths are the tmpfs's mounts, so the container's processes cannot modify the image's layers, and the persistence is the explicit (the volumes' mounts).
The containers' design's observations:
-
The containers' isolation's strength.
The containers' isolation is the kernel's
mechanisms' (the namespaces and the cgroups),
and the containers' security depends on the
kernel's security: a kernel's vulnerability
(the
Dirty COW, theDirty Pipe, theOverlayFS's bugs) can be the container's escape's vector, and the containers' shared's kernel is the VMs' separate's kernel's security's difference. The observation is the reason the high-security's multi-tenancy uses the VMs (or the VM's and the container's combination: the Kata Containers, the gVisor, the Firecracker), and the containers' use is the trusted's or the single-tenant's workloads. - The containers' ecosystem's security's concerns. The containers' security includes the image's security (the base's image's vulnerabilities, the dependencies' vulnerabilities, the secrets' leakage), the registry's security (the images' signing, the trusted's registries), the runtime's security (the runtime's vulnerabilities, the configuration's mistakes), and the orchestration's security (the Kubernetes's RBAC, the network's policies, the secrets' management). The security's concerns are the modern's container's security's central's subjects.
4.7 The browsers' sandboxes
The browsers are the modern systems' most visible sandboxes, and their designs are the sandboxing's case studies. The browsers' threat's model: the web's pages (the JavaScript, the HTML, the CSS, the WebAssembly, the plugins) are the untrusted's code, and the browser must execute the code without the code compromising the user's system. The browsers' sandboxing's designs:
- The Chrome's sandbox
-
The Chrome's design: the multi-process's
architecture (the browser's process, the
renderer's process per site, the GPU's
process, the utility's processes) and the
renderer's sandbox. The renderer's
sandbox's mechanisms: the
chroot(the file system's view's restriction to the minimal's set of the files), theseccomp's filter (the system calls' whitelist, the platform-specific's filters), theclone's namespaces (the Linux: the PID's, the network's, the user's, and the IPC's namespaces), thesetuid's and thesetgid's sandbox's user (the dedicated's unprivileged's user), the capabilities' dropping, and thepledge's and theunveil's mechanisms (the OpenBSD's), thesandbox_init's (the macOS's Seatbelt's profiles). The renderer's process has no direct access to the file system (the accesses are the broker's process's mediation: the IPC's requests), and the renderer's system calls are the whitelist's set. - The Firefox's sandbox
-
The Firefox's design: the
multi-process's architecture (the
parent's process, the content's processes,
the GPU's process) and the content's
processes' sandbox. The content's sandbox's
mechanisms: the
seccomp-bpf's filter (the Linux's, the default's enabled), thechroot's (the file system's view's restriction, the macOS's and the Linux's), the user's namespace's (the Linux's), the capabilities' dropping, the file's access's brokering (the parent's process's mediation), and theWindows's and themacOS's platform-specific's sandboxes. The Firefox's sandbox's levels (thecontent, thesocket, theutility, thewidevine) and the settings (security.sandbox.content.level) determine the confinement's strength.
The browsers' sandboxing's observations:
- The browsers' sandbox is the multi-process's architecture's application. The renderer's process (the untrusted's code's executor) is the sandboxed's process, and the browser's process (the trusted's broker) is the privileged's process. The architecture's design: the untrusted's code's compromise (the renderer's process) gives the attacker only the renderer's process's resources, and the escape requires the sandbox's bypass (the kernel's vulnerability, the broker's IPC's vulnerability, the configuration's mistake).
-
The sandbox's trade-offs. The
sandbox's design has the performance's cost
(the IPC's brokering's overhead, the
process's creation's cost) and the
compatibility's cost (the sandbox's
restrictions can break the legitimate's
pages' features). The observation is the
reason the browsers' sandboxes have the
escape's hatches (the
--no-sandbox's option, the plugin's processes' less restricted's sandboxes), and the hatches' designs are the security's and the usability's tension's examples.
4.8 The systemd's hardening's directives
The systemd is the modern's Linux's init's system and the services' manager, and its sandboxing's directives are the services' confinement's mechanisms. The directives:
-
The file system's directives.
The
ProtectSystem=strict(the/usr, the/boot, the/etc's read-only's mounts), theProtectHome=yes(the/home, the/root, the/run/user's inaccessibility), theReadWritePaths=and theReadOnlyPaths=(the specific's paths' access's modification), theInaccessiblePaths=(the paths' hiding), thePrivateTmp=yes(the private's/tmpand the/var/tmp), thePrivateDevices=yes(the private's/devwith only thenull, thezero, thefull, therandom, theurandom, thetty), and theProtectKernelTunables=yes(the/proc/sys, the/sys's read-only's mounts). -
The user's and the group's
directives. The
User=and theGroup=(the service's user's and group's identities), theDynamicUser=yes(the transient's user's and group's allocation), theSupplementaryGroups=(the additional's groups' specification), and theRemoveIPC=yes(the IPC's objects' removal on the service's stop). -
The capabilities' and the privilege's
directives. The
CapabilityBoundingSet=(the service's capabilities' limit), theAmbientCapabilities=(the service's ambient's capabilities), theNoNewPrivileges=yes(the setuid's and the capabilities' programs' privilege's escalation's prevention), and theSecureBits=(the kernel's securebits's flags). -
The namespaces' directives. The
PrivateMounts=yes(the private's mount's namespace), thePrivateNetwork=yes(the private's network's namespace with only the loopback), thePrivateUsers=yes(the private's user's namespace), thePrivateIPC=yes(the private's IPC's namespace), theProtectHostname=yes(the private's UTS's namespace), and theProtectClock=yes(the clock's modification's prevention). -
The system calls' and the addressing's
directives. The
SystemCallFilter=(the seccomp's filter: the@system-service's group, the~@privileged's denial, the specific's system calls), theSystemCallArchitectures=(the system calls' architectures' restriction), theRestrictAddressFamilies=(the socket's address's families' restriction: theAF_UNIX, theAF_INET, theAF_INET6), theRestrictNamespaces=(the namespace's creation's restriction), and theLockPersonality=yes(thepersonality's system call's restriction). -
The memory's and the kernel's
directives. The
MemoryDenyWriteExecute=yes(the writable's and the executable's memory's mappings' prevention: the JIT's code's prevention), theRestrictRealtime=yes(the real-time's scheduling's restriction), theRestrictSUIDSGID=yes(the setuid's and the setgid's bits' creation's prevention), theProtectKernelModules=yes(the kernel's modules' loading's prevention), theProtectKernelLogs=yes(the kernel's log's reading's prevention), and theProtectProc=invisible(the/proc's view's hiding).
The systemd's directives' management's tools: the
systemd-analyze security's command
evaluates the service's sandbox's strength and
produces the score (the exposure's level: the
OK, the
EXPOSED, the
MEDIUM, the
UNSAFE), the systemd-run's
command creates the transient's services with the
directives, and the unit's files
(/etc/systemd/system/*.service, the
[Service]'s section) hold the
persistent's configuration. The observation is
the reason the modern's distributions ship the
services' units with the sandboxing's directives
(the ProtectSystem=strict, the
NoNewPrivileges=yes, the
SystemCallFilter=@system-service):
the directives' defaults are the security's
sensible's choices, and the observation is the
psychological acceptability's principle's
application (Lesson 12.1's principle 8).
4.9 The Landlock and the unprivileged's sandboxing
The Landlock is the Linux's
mechanism for the unprivileged's
sandboxing (the Linux 5.13). The mechanism's
design: the process (the unprivileged's, without
the CAP_SYS_ADMIN's capability)
creates the Landlock's domain and
attaches the rules that restrict the
process's file system's accesses. The rules'
design: the access's rights (the
LANDLOCK_ACCESS_FS_EXECUTE, the
LANDLOCK_ACCESS_FS_READ_FILE, the
LANDLOCK_ACCESS_FS_WRITE_FILE, the
LANDLOCK_ACCESS_FS_READ_DIR, the
LANDLOCK_ACCESS_FS_REMOVE_DIR, the
LANDLOCK_ACCESS_FS_REMOVE_FILE, the
LANDLOCK_ACCESS_FS_MAKE_*) are the
restricted's operations, and the rules' scope is
the specified's paths (the file's or the
directory's hierarchy). The mechanism's
restriction: the Landlock's rules are the
additional's restrictions (the rules can
only remove the accesses, not grant them), so the
sandbox's design is the
least privilege's
(the process's accesses are the subset of the
accesses the process would otherwise have).
The Landlock's design's advantages: the
unprivileged's use (the process does not need the
CAP_SYS_ADMIN's capability, so the
ordinary's applications can sandbox themselves),
the composability (the Landlock's domains can be
stacked, and the multiple's domains' rules are the
intersection), and the file system's focus (the
mechanism's design is the file system's accesses'
restriction, which is the common's sandboxing's
need). The Landlock's design's limitations: the
file system's only's scope (the mechanism does not
restrict the network, the IPC, or the other
resources: the seccomp and the namespaces are the
complementary's mechanisms), and the
kernel's version's requirement (the Linux 5.13+,
and the ABI's versions' extensions: the Linux
5.19's and the 6.x's additions).
The unprivileged's sandboxing's other's mechanisms:
-
The
bubblewrap's tool. The container's runtime's lightweight's tool (the Flatpak's and the GNOME's foundation): thebwrap's command creates the sandboxed's environment (the namespaces, the bind mounts, the seccomp's filters, the capabilities' dropping), and the tool's design is the unprivileged's user's (the user's namespace's use). -
The
firejail's tool. The user-space's sandboxing's tool: thefirejail's command runs the program with the sandbox (the namespaces, the seccomp's filters, the capabilities' dropping, the AppArmor's profiles, the firejail's profiles' library), and the tool's design is the administrator's and the developer's convenience's mechanism. -
The
systemd-run --user's mechanism. The systemd's user's services: thesystemd-run --usercreates the transient's user's services with the sandboxing's directives (theProtectSystem, thePrivateTmp, theNoNewPrivileges, theSystemCallFilter), and the mechanism's design is the unprivileged's user's sandboxing's convenience.
4.10 The sandbox's escapes and the attacks
The sandbox's escape is the attacker's bypass of the sandbox's walls, and the escape's mechanisms are the sandbox's design's weaknesses:
-
The kernel's vulnerabilities.
The sandbox's walls are the kernel's
mechanisms (the namespaces, the seccomp, the
LSM, the capabilities), and the kernel's
bugs (the privilege's escalation's
vulnerabilities, the use-after-free, the
race conditions, the memory's corruptions)
are the escape's vectors. The classical's
examples: the
Dirty COW(the CVE-2016-5195: the copy-on-write's race), theDirty Pipe(the CVE-2022-0847: the pipe's buffers' overwrite), theOverlayFS's bugs (the CVE-2021-3493, the CVE-2023-0386), and theio_uring's bugs. The observation is the reason the containers' security depends on the kernel's security: the containers share the kernel, and the kernel's vulnerability compromises the every container. -
The configuration's mistakes.
The sandbox's strength depends on the
configuration: the missing's seccomp's
filter, the excessive's capabilities, the
disabled's LSM's module, the
--privileged's flag (the Docker's flag: the full's host's privileges), the--pid=host's or the--net=host's flags (the host's namespaces' sharing), the mounted's sensitive's paths (the-v /:/host's mount: the host's root's exposure), thedocker.sock's mount (the container's control of the Docker's daemon: the full's host's compromise). The observation is the reason the containers' security's practice includes the configuration's review (the CIS's Docker's benchmark, the Kubernetes's hardening's guides). - The design's flaws. The sandbox's design can have the flaws: the incomplete's mediation (the seccomp's filter's missing's system calls), the incorrect's assumptions (the path's confinement's hard links' bypass: the AppArmor's profile's paths are the names, and the hard links can bypass the path's check), the IPC's channels (the sandbox's broker's interface: the broker's vulnerability is the escape's vector), and the shared's resources (the shared's memory, the device's nodes, the mounted's file systems).
- The side channels. The sandbox's isolation does not cover the side channels: the timing's channels (the CPU's caches' timing), the speculative's execution (the Spectre's and the Meltdown's attacks: the CPU's microarchitectural's leaks), the power's channels, and the electromagnetic's channels. The side channels' defence requires the hardware's mitigations (the microcode's updates, the kernel's mitigations: the page-table's isolation, the branch's prediction's hardening), and the observation is the reason the VMs' or the separate's hardware's designs are the high-security's choices.
The escapes' defensive's practices:
- The kernel's updates. The kernel's security's patches' application is the escapes' prevention's foundation: the vulnerabilities are the published, and the unpatched's kernel is the vulnerable's.
-
The configuration's minimization.
The sandbox's configuration should have the
minimum's privileges: the
--cap-drop=ALLand the--cap-add='s specific's capabilities, the--security-opt's options (theno-new-privileges, theseccomp=, theapparmor=), the read-only's file system, the non-root's user, and the no-host's namespaces. - The defence in depth's layering. The sandbox's walls should be the multiple's: the namespaces, the cgroups, the seccomp, the capabilities, the LSM, the user's namespace, the read-only's file system. The multiple's walls' failures are the uncorrelated, and the escape requires the multiple's bypasses.
-
The monitoring and the detection.
The sandbox's audit's logs (the SELinux's
avc's denials, the seccomp'sSECCOMP_RET_LOG's events, the container's runtime's logs) and the system's monitoring (the anomaly's detection: the unusual's system calls, the unexpected's network's connections) can detect the escape's attempts and the ongoing's compromises.
4.11 The sandboxing's design principles
The sandboxing's design applies the Lesson 12.1's principles, and the specific's applications:
- The least privilege (the principle 6). The sandbox's code has the minimum's resources: the namespaces' minimal's views, the cgroups' tight's limits, the seccomp's whitelist's filters, the capabilities' dropped's sets, the LSM's profiles' confined's policies.
- The fail-safe defaults (the principle 2). The sandbox's default is the denial: the container's default's capabilities are the dropped's set, the default's seccomp's filter is the restrictive's set, the default's user is the unprivileged's, and the default's file system is the read-only's.
- The complete mediation (the principle 3). The sandbox's every access is mediated: the namespaces' every view's check, the cgroups' every resource's accounting, the seccomp's every system call's filter, the LSM's every access's policy's check. The incomplete's mediation (the missing's seccomp's rules, the unconfined's paths) is the escape's vector.
- The economy of mechanism (the principle 1). The sandbox's mechanism is the simple and the small: the small reference's monitor (the kernel's mediation), the simple's seccomp's filters, the minimal's capabilities' sets. The complexity (the excessive's rules, the unnecessary's features) is the bugs' and the misconfigurations' source.
- The separation of privilege (the principle 5). The sandbox's critical's operations require the multiple's conditions: the multi-factor's authentication for the privileged's operations, the separation of duties for the sensitive's changes.
- The least common mechanism (the principle 7). The sandbox's shared's resources are the minimized: the per-sandbox's namespaces, the per-sandbox's file systems, the per-sandbox's networks. The shared's kernel is the containers' design's limitation (the VMs' separate's kernel is the alternative).
-
The psychological acceptability (the
principle 8). The sandbox's
mechanism is the usable: the sensible's
defaults (the systemd's directives, the
Docker's default's profiles), the escape's
hatches for the legitimate's needs (the
--privileged's flag, the--no-sandbox's option), and the understandable's configuration. The inusable's sandbox (the excessive's complexity, the constant's breakages) is the bypassed's sandbox. - The open design (the principle 4). The sandbox's mechanism is the public and the auditable: the open-source's implementations (the Linux's kernel, the containers' runtimes), the standardized's interfaces (the OCI's specifications), and the reviewable's configurations.
4.12 Common misconceptions
"The containers are the lightweight's virtual machines."
The containers are not the VMs: the containers share the host's kernel (the namespaces and the cgroups are the isolation's mechanisms), and the VMs have the separate's kernel (the hypervisor and the hardware's virtualization). The containers' isolation is the kernel's mechanisms', and the containers' security depends on the kernel's security: the kernel's vulnerability compromises the every container. The observation is the reason the high-security's multi-tenancy uses the VMs (or the VM's and the container's combination: the Kata Containers, the gVisor, the Firecracker).
"The chroot is the security's boundary."
The chroot is the file system's view's
restriction, not the security's boundary:
the process with the
CAP_SYS_CHROOT's capability
can escape (the chroot's nesting's
tricks, the chdir's tricks),
and the root's process can escape by the
multiple's mechanisms (the
/proc's access, the
mknod's device's creation).
The modern's sandboxes use the mount's
namespace (the CLONE_NEWNS)
and the pivot_root's
mechanism, and the chroot is the
convenience's mechanism (the build's
environments, the legacy's services).
"The namespaces are the resource's limits."
The namespaces are the views (the isolation's mechanisms), not the limits (the resource's usage's mechanisms). The namespaces isolate the processes' views of the resources, and the cgroups limit the processes' usage of the resources. The two are the complementary: the container's process sees the container's namespace's view, and the container's cgroup caps the process's resource's usage. A sandbox without the cgroups can consume the system's resources (the fork's bomb, the memory's exhaustion), and a sandbox without the namespaces can see the system's resources (the host's processes, the host's files).
"The seccomp is the containers' optional's feature."
The seccomp's filter is the containers'
security's central's mechanism: the
Docker's and the Podman's default's
profiles block the ~44's dangerous's
system calls (the mount, the
reboot, the
kexec_load, the
init_module, the
ptrace), and the filter's
absence is the escape's vector. The
observation is the reason the containers'
security's guides emphasize the seccomp's
profile's configuration (the
--security-opt seccomp='s
option, the custom's profiles), and the
containers' default's seccomp's filter is
the security's sensible's default.
"The rootless's containers are the root's containers with the different's user."
The rootless's containers use the user's
namespace (the CLONE_NEWUSER)
to map the container's root (the UID 0
inside) to the unprivileged's user (the
UID 1000's mapping) on the host. The
design's consequence: the container's
root's privileges are the bounded (the
host's kernel sees the unprivileged's
user), and the container's escape gives
the attacker only the unprivileged's
user's privileges, not the host's root's.
The observation is the reason the
rootless's containers (the Podman's
default) are the security's
recommended's design for the
unprivileged's users' workloads.
"The sandbox is the absolute's isolation."
The sandbox is the isolation's mechanisms' combination, not the absolute's guarantee: the escapes are the known (the kernel's vulnerabilities, the configuration's mistakes, the design's flaws, the side channels), and the sandbox's strength depends on the kernel's security, the configuration's correctness, and the escape's hatches' control. The observation is the reason the sandboxing is the defence in depth's application: the multiple's walls, the multiple's failures' uncorrelation, and the monitoring's detection.
"The containers are the secure by default."
The containers' defaults are the
security's sensible's choices (the
dropped's capabilities, the default's
seccomp's filter, the non-root's user,
the unprivileged's ports), but the
containers' security depends on the
configuration: the
--privileged's flag, the
host's namespaces' sharing
(--pid=host,
--net=host), the sensitive's
mounts (the docker.sock's
mount, the host's root's mount), and the
image's vulnerabilities are the
common's weaknesses. The observation is
the reason the containers' security's
practice includes the configuration's
review (the CIS's Docker's benchmark,
the Kubernetes's hardening's guides).
"The systemd's sandboxing is the optional's hardening."
The systemd's sandboxing's directives are
the services' confinement's central's
mechanisms, and the modern's distributions
ship the services' units with the
directives (the
ProtectSystem=strict, the
NoNewPrivileges=yes, the
SystemCallFilter=@system-service,
the PrivateTmp=yes). The
directives' defaults are the security's
sensible's choices, and the
systemd-analyze security's
command evaluates the service's
sandbox's strength and produces the
score (the OK, the
MEDIUM, the
UNSAFE).
05 Worked example
The following example traces a sandbox's
creation with the unshare's and the
bubblewrap's tools, computes the
sandbox's walls, and evaluates a service's
sandbox's strength with the
systemd-analyze security's
command.
Creating a sandbox with the namespaces and the seccomp
The following commands create a minimal's
sandbox with the unshare's
command and observe its walls:
# The minimal's sandbox: the new's mount and PID and UTS's
# namespaces, with the new's mount's propagation's control
sudo unshare --mount --pid --fork --uts --mount-proc \
/bin/bash -c '
echo "The sandbox is running."
echo "The PID: $$"
echo "The hostname: $(hostname)"
echo "The hostname's change:"
hostname sandbox
hostname
echo "The processes:"
ps aux
'
The command's output shows the sandbox's walls:
-
The PID's namespace. The
$$'s value is 1 (or a low's number), because the sandbox's first process is the PID 1 in the namespace. Theps aux's output shows only the sandbox's processes (the shell and theps), not the host's processes. -
The UTS's namespace. The
hostname's output shows the host's hostname initially, and thehostname sandbox's command changes the namespace's hostname without affecting the host's (the host'shostname's command's output is the unchanged). -
The mount's namespace. The
--mount-proc's option mounts the new's/procin the namespace (themount -t proc proc /proc's equivalent), so the/proc's view shows only the namespace's processes.
The sandbox's walls and their checks
The sandbox's walls and the ways to verify them:
| Wall | The verification's command | The expected's output |
|---|---|---|
| The PID's namespace | echo $$, ps aux |
The low's PID, the sandbox's processes only |
| The mount's namespace | mount | wc -l, ls / |
The sandbox's mounts, the host's file system's hierarchy (if the bind mounts are the not's applied) |
| The UTS's namespace | hostname |
The host's hostname initially, the sandbox's after the change |
| The user's namespace | id, cat /proc/self/uid_map |
The UID 0 inside (if the mapping), the mapping's view |
| The network's namespace | ip link, ip addr |
The loopback's interface only |
| The IPC's namespace | ipcs |
The empty's IPC's objects |
| The cgroup's namespace | cat /proc/self/cgroup |
The namespace's cgroup's subtree |
The seccomp's filter's effect
The seccomp's filter's effect:
# Install a seccomp's filter that denies the 'chmod' system call
# (the 'chmod' is the syscall's number 90 on x86_64)
# The following is the conceptual's demonstration;
# the practical's use is via the libseccomp or the systemd.
# The Python's example with the seccomp's library:
python3 -c '
import seccomp
filter = seccomp.SyscallFilter(defaction=seccomp.ALLOW)
filter.add_rule(seccomp.ERRNO(1), "chmod")
filter.add_rule(seccomp.ERRNO(1), "fchmod")
filter.load()
import os
os.chmod("/tmp/test", 0o777)
'
The filter's effect: the chmod's
system call returns the
EPERM's error (the errno 1),
and the os.chmod's call fails.
The observation: the seccomp's filter is the
system calls' filter, and the filter's
design determines the process's allowed's
system calls. The modern's containers'
runtimes use the libseccomp's filters with
the default's profiles (the Docker's and
the Podman's: the ~44's blocked's system
calls), and the observation is the reason
the seccomp's filter is the containers'
security's central's mechanism.
The systemd's sandbox's evaluation
The systemd-analyze security's
command evaluates a service's sandbox's
strength:
# Evaluate the sshd's service's sandbox
systemd-analyze security sshd 2>/dev/null | head -40
# Evaluate the systemd's own's service
systemd-analyze security systemd-journald 2>/dev/null | head -40
# The output shows the service's exposure's score
# (the 0.0 is the perfect's sandbox, the 10.0 is the
# unsandboxed's service) and the per-directive's
# assessment (the OK, the MEDIUM, the EXPOSED).
# The example's output (the abbreviated):
# NAME DESCRIPTION EXPOSURE
# ✗ PrivateNetwork= Service has access to the host's network 0.5
# ✗ User=/DynamicUser= Service runs as root user 0.4
# ✗ CapabilityBoundingSet=~CAP_SYS_ADMIN Service has the CAP_SYS_ADMIN's capability 0.2
# ✓ PrivateTmp= Service has a private's /tmp —
# ...
# Overall exposure level for sshd.service: 9.6 UNSAFE 😱
The command's output shows the service's
sandbox's assessment: the per-directive's
exposure (the ✗'s marks for
the unmet's recommendations, the
✓'s for the met's) and the
overall's score. The sshd's
score is the high (the 9.6 UNSAFE), because
the sshd's service needs the
privileged's operations (the port 22's
binding, the user's authentication, the
session's setup), and the observation is
the reason the systemd's hardening's
directives are the services' trade-offs:
the directives' application must account
for the services' legitimate's needs, and
the observation is the reason the
hardening's process is the iterative (the
directives' application, the testing, the
adjustment).
A container's security's inspection
The following commands inspect a container's security's configuration (if the Docker or the Podman is installed):
# Run a container with the default's configuration
docker run -d --name test-container alpine sleep 3600 2>/dev/null
# Inspect the container's security's configuration
docker inspect test-container 2>/dev/null | \
grep -A5 -E 'CapDrop|CapAdd|SecurityOpt|ReadonlyRootfs|Privileged|User|PidMode|NetworkMode'
# The output shows the container's dropped's capabilities
# (the CapDrop: the ALL's list, the CapAdd: the default's set),
# the SecurityOpt (the seccomp's filter, the AppArmor's profile,
# the no-new-privileges's flag), the ReadonlyRootfs's status,
# the Privileged's flag, the User, the PidMode, the NetworkMode.
# Show the container's namespaces
ls -la /proc/$(docker inspect -f '{{.State.Pid}}' test-container 2>/dev/null)/ns/ 2>/dev/null
# Show the container's cgroup's limits
cat /sys/fs/cgroup/system.slice/docker-*.scope/memory.max 2>/dev/null
cat /sys/fs/cgroup/system.slice/docker-*.scope/cpu.max 2>/dev/null
# Show the container's seccomp's status
grep Seccomp /proc/$(docker inspect -f '{{.State.Pid}}' test-container 2>/dev/null)/status 2>/dev/null
# Show the container's capabilities
capsh --print 2>/dev/null | head -5
sudo nsenter -t $(docker inspect -f '{{.State.Pid}}' test-container 2>/dev/null) -a capsh --print 2>/dev/null | head -10
# Clean up
docker rm -f test-container 2>/dev/null
The commands' outputs show the container's security's configuration: the dropped's and the added's capabilities, the security's options (the seccomp's filter, the AppArmor's profile), the read-only's file system's status, the privileged's flag, the user, the namespaces (the PID's, the network's, the mount's, the IPC's, the UTS's), the cgroup's limits (the memory's max, the CPU's max), and the seccomp's status (the mode 2: the filter's mode). The inspection is the container's security's assessment's first step, and the observation is the reason the containers' security's practice includes the configuration's review.
06 Interactive activity
Activity · explore the sandboxing on a live system
The goal of this activity is to use the Linux command line to create and inspect the sandboxes: the namespaces, the cgroups, the seccomp's filters, the chroot, the containers, and the systemd's hardening's directives. Work through the steps in your course VM.
-
Inventory the namespaces.
Use the
/proc's interfaces to inspect the current process's namespaces.
How many namespaces does the system have? What are the current process's namespace's identifiers? Do the current process and the PID 1 share the namespaces? Write down what you find.# Show the current process's namespaces ls -la /proc/self/ns/ # Show the namespaces' identifiers readlink /proc/self/ns/mnt readlink /proc/self/ns/pid readlink /proc/self/ns/net readlink /proc/self/ns/user readlink /proc/self/ns/ipc readlink /proc/self/ns/uts readlink /proc/self/ns/cgroup readlink /proc/self/ns/time 2>/dev/null # Show the processes with the same namespace for pid in $$ 1; do echo "PID $pid:" ls -la /proc/$pid/ns/ 2>/dev/null done # List the network's namespaces sudo ip netns list 2>/dev/null # List the containers' namespaces (if Docker is installed) ls -la /var/run/docker/netns/ 2>/dev/null | head -5 -
Create and inspect a namespace.
Use the
unshare's command to create the new's namespaces and inspect them.
What is the sandbox's PID? Did the hostname's change affect the host? How many processes are visible in the sandbox? Explain the isolation's design.# Create a new's mount and PID and UTS's namespaces sudo unshare --mount --pid --fork --uts --mount-proc \ /bin/bash -c ' echo "=== The sandbox ===" echo "PID: $$" echo "Hostname: $(hostname)" hostname test-sandbox echo "After the hostname's change: $(hostname)" echo "The namespace's identifiers:" readlink /proc/self/ns/mnt readlink /proc/self/ns/pid readlink /proc/self/ns/uts echo "The processes in the namespace:" ps aux ' # Verify the host's hostname is unchanged hostname -
Create a network's namespace.
Use the
ip netns's command to create and configure a network's namespace.
Did the namespace's interfaces appear? Did the connectivity's test work? How does the network's namespace's isolation work? What are the containers' network's isolation's mechanisms?# Create a network's namespace sudo ip netns add test-ns # Show the namespace's interfaces sudo ip netns exec test-ns ip link sudo ip netns exec test-ns ip addr # Create a virtual's Ethernet's pair sudo ip link add veth-host type veth peer name veth-ns # Move one end to the namespace sudo ip link set veth-ns netns test-ns # Configure the interfaces sudo ip addr add 10.99.0.1/24 dev veth-host sudo ip link set veth-host up sudo ip netns exec test-ns ip addr add 10.99.0.2/24 dev veth-ns sudo ip netns exec test-ns ip link set veth-ns up sudo ip netns exec test-ns ip link set lo up # Test the connectivity ping -c 2 10.99.0.2 sudo ip netns exec test-ns ping -c 2 10.99.0.1 # Clean up sudo ip netns delete test-ns sudo ip link delete veth-host 2>/dev/null -
Inspect the cgroups.
Use the cgroups' interfaces to inspect the
hierarchy and the limits.
What is the cgroup's version (the v1, the v2)? What are the current process's cgroup's limits? What is the system's resource's usage's distribution? How do the cgroups complement the namespaces?# Show the cgroup's version stat -fc %T /sys/fs/cgroup/ mount | grep cgroup # Show the cgroup's hierarchy systemd-cgls 2>/dev/null | head -30 ls /sys/fs/cgroup/ 2>/dev/null # Show the current process's cgroup cat /proc/self/cgroup # Show the current cgroup's limits cat /sys/fs/cgroup/$(cat /proc/self/cgroup | cut -d: -f3)/memory.max 2>/dev/null cat /sys/fs/cgroup/$(cat /proc/self/cgroup | cut -d: -f3)/cpu.max 2>/dev/null # Show the resource's usage systemd-cgtop -b -n 1 2>/dev/null | head -10 -
Create a cgroup's limit.
Use the
systemd-run's command to create a transient's service with the resource's limits.
Did the memory's limit cause the service to fail? Did the CPU's quota limit the service's CPU's usage? How do the cgroups' limits enforce the resource's constraints?# Create a transient's service with the memory's limit sudo systemd-run --unit=mem-limit-test --property=MemoryMax=50M \ /bin/bash -c 'dd if=/dev/zero of=/dev/null bs=1M count=1000' 2>&1 | head -3 # Watch the service's status systemctl status mem-limit-test 2>/dev/null | head -10 # Show the service's cgroup's limits cat /sys/fs/cgroup/system.slice/mem-limit-test.service/memory.max 2>/dev/null # Clean up sudo systemctl stop mem-limit-test 2>/dev/null sudo systemctl reset-failed mem-limit-test 2>/dev/null # Create a transient's service with the CPU's limit sudo systemd-run --unit=cpu-limit-test --property=CPUQuota=20% \ /bin/bash -c 'while true; do :; done' 2>&1 | head -3 # Check the service's status systemctl status cpu-limit-test 2>/dev/null | head -10 # Clean up sudo systemctl stop cpu-limit-test 2>/dev/null sudo systemctl reset-failed cpu-limit-test 2>/dev/null -
Evaluate a service's sandbox.
Use the
systemd-analyze security's command to evaluate the services' sandboxes.
What are the services' exposure's scores? Which service has the most hardened's sandbox? What is the hardened's service's score, and how does it compare with the others? What are the directives' effects?# Evaluate a few services for svc in sshd systemd-journald cron dbus; do echo "=== $svc ===" systemd-analyze security $svc 2>/dev/null | tail -5 done # Show the detailed's assessment for one service systemd-analyze security sshd 2>/dev/null | head -40 # Create a transient's service with the hardening's directives sudo systemd-run --unit=hardened-test \ --property=ProtectSystem=strict \ --property=ProtectHome=yes \ --property=PrivateTmp=yes \ --property=NoNewPrivileges=yes \ --property=CapabilityBoundingSet= \ --property=SystemCallFilter=@system-service \ /bin/bash -c 'echo "The hardened service is running."' # Evaluate the hardened's service systemd-analyze security hardened-test 2>/dev/null | tail -5 # Clean up sudo systemctl stop hardened-test 2>/dev/null sudo systemctl reset-failed hardened-test 2>/dev/null -
Test the chroot and the pivot_root.
Use the
chroot's command to create a file system's confinement and observe its limitations.
Did the chroot's environment work? How many files were in the chroot's# Create a minimal's chroot's environment sudo mkdir -p /tmp/chroot-test/{bin,lib,lib64,etc} sudo cp /bin/bash /tmp/chroot-test/bin/ sudo cp /bin/ls /tmp/chroot-test/bin/ sudo ldd /bin/bash | grep -oP '/\S+' | while read lib; do sudo cp --parents "$lib" /tmp/chroot-test/ 2>/dev/null done sudo ldd /bin/ls | grep -oP '/\S+' | while read lib; do sudo cp --parents "$lib" /tmp/chroot-test/ 2>/dev/null done # Enter the chroot sudo chroot /tmp/chroot-test /bin/bash -c 'echo "The chroot is active."; ls /; echo "The /etc's files:"; ls /etc/' # Test the escape's attempt (as the root, the escape succeeds) sudo chroot /tmp/chroot-test /bin/bash -c ' cd ../../../../.. echo "The escape attempt:" ls / 2>&1 | head -5 ' # Clean up sudo rm -rf /tmp/chroot-test/? Did the escape's attempt succeed? Explain the chroot's design's weakness and the modern's alternatives (the mount's namespace, thepivot_root). -
Read the man pages.
Read the man pages that document the
sandboxing's mechanisms.
For each, write a sentence describing its main contribution to your understanding of the sandboxing. Theman 7 namespaces man 2 clone man 1 unshare man 1 nsenter man 2 setns man 1 ip-netns man 7 cgroups man 1 systemd-cgls man 1 systemd-cgtop man 1 systemd-run man 2 seccomp man 2 chroot man 2 pivot_root man 5 systemd.exec man 5 systemd.resource-control man 1 systemd-analyze man 1 firejail man 1 bubblewrap man 1 docker man 1 podmanman 7 namespacespage documents the eight namespaces; theman 7 cgroupspage documents the control groups; theman 2 seccomppage documents the system calls' filter; theman 5 systemd.execpage documents the sandboxing's directives.
Reflect: the sandboxing is the modern security's central's architecture, and its mechanisms are the kernel's isolation's tools. The namespaces isolate the processes' views; the cgroups limit the processes' resource's usage; the seccomp's filters restrict the system calls; the chroot and the pivot_root confine the file system's view; the containers combine the mechanisms; the browsers' sandboxes apply the architecture at the web's scale; the systemd's directives configure the services' confinement; the Landlock enables the unprivileged's sandboxing. Which of the mechanisms from this lesson is the most important for the systems you use? What would you change about the sandboxing's design if you could? How would you explain the difference between the namespaces and the cgroups to someone who has never thought about it? What is the right balance between the sandbox's strength and the compatibility's needs?
07 Knowledge check
Check your understanding
Question 1
Define the sandbox and explain the isolation's goals. Describe the confinement's spectrum from the chroot to the virtual machines, and explain the mechanisms' complementarity.
Show answer
Question 2
Describe the Linux namespaces (the mount, the PID, the network, the user, the IPC, the UTS, the cgroup, and the time). What is each namespace's isolation's semantics, and what are the namespaces' management's mechanisms?
Show answer
CLONE_NEWNS: the isolation
of the file system's mount's points,
so the processes in the different
namespaces see the different file
system's hierarchies; the mount's
namespace is the chroot's
modern's successor);
the PID's namespace
(CLONE_NEWPID: the isolation
of the process's table, so the
processes in the different namespaces
have the different PID's numbers; the
namespace's first process has the PID
1, and the namespace's processes
cannot see the other namespaces'
processes);
the network's namespace
(CLONE_NEWNET: the
isolation of the network's stack, so
the processes in the different
namespaces have the different
interfaces, the routing's tables, the
firewall's rules, the sockets; the
new's namespace starts with the
loopback only);
the user's namespace
(CLONE_NEWUSER: the
isolation of the user's and the group's
IDs, so the processes in the different
namespaces have the different UIDs and
GIDs' mappings; the namespace's process
can be the root inside while the host
sees the unprivileged's user: the
rootless's containers' foundation);
the IPC's namespace
(CLONE_NEWIPC: the
isolation of the System V's IPC and
the POSIX's message queues);
the UTS's namespace
(CLONE_NEWUTS: the
isolation of the hostname and the
NIS's domain name);
the cgroup's namespace
(CLONE_NEWCGROUP: the
isolation of the cgroup's hierarchy's
view, so the namespace's processes
see only the namespace's cgroup's
subtree); and
the time's namespace
(CLONE_NEWTIME: the
isolation of the boot's time and the
monotonic's clock's offsets: the
newest, the Linux 5.6, and the purpose
is the containers' checkpoint's and
restore's time's isolation). The
namespaces' management's mechanisms:
the clone's system call
(the creation of the new's processes
with the namespace's flags), the
unshare's system call and
the unshare's command
(the move of the calling's process
into the new's namespaces), the
setns's system call and
the nsenter's command
(the move into the existing's
namespaces), the
/proc/PID/ns/'s interface
(the namespace's symbolic links and
their identifiers), and the
ip netns's command (the
network's namespaces' management). The
namespaces' design's central's
observation: the namespaces are the
views, not the limits,
so the cgroups are the complementary's
mechanism.
Question 3
Describe the control groups (the cgroups). What are the v1's and the v2's designs, what are the resource's controllers, and how do the cgroups complement the namespaces?
Show answer
cpu's hierarchy, the
memory's hierarchy, the
blkio's hierarchy, the
pids's hierarchy, and the
others), so the process can be in the
different groups in the different
hierarchies and the controllers' limits
are the separate. The v1's disadvantages:
the complexity, the controllers'
interactions, and the inconsistent's
semantics. The cgroups
v2's design: the single
hierarchy (the /sys/fs/cgroup/'s
unified's tree), with the controllers
attached to the groups' nodes (the
cgroup.controllers, the
cgroup.subtree_control).
The v2's advantages: the consistency
(the single hierarchy, the coherent's
semantics), the delegation (the
unprivileged's users can manage the
sub-hierarchies), the pressure's
information (the cgroup.pressure's
interfaces), and the nesting. The
resource's controllers:
the cpu (the
cpu.weight and the
cpu.max: the CPU's time's
allocation), the memory
(the memory.max, the
memory.high, the
memory.low, the
memory.min, the
memory.swap.max), the
io (the
io.weight, the
io.max, the
io.latency), the
pids (the
pids.max: the process's
count's limit, the fork's bomb's
prevention), and the others (the
cpuset, the
hugetlb, the
freezer, the
rdma, the
devices, the
net_cls, the
net_prio). The cgroups'
management's mechanisms: the
/sys/fs/cgroup/'s
interface, the systemd's integration
(the services are the cgroups, the
units' resource's directives, the
systemd-cgls and the
systemd-cgtop's tools),
the systemd-run's command
(the transient's services), and the
cgroupfs's and the
cgroup2's mounts. The
cgroups complement the namespaces: the
namespaces are the views (the
isolation of the processes' view of
the resources), and the cgroups are the
limits (the processes'
resource's usage's caps). The container's
process sees the container's namespace's
view, and the container's cgroup caps
the process's resource's usage. A
sandbox without the cgroups can consume
the system's resources (the fork's bomb,
the memory's exhaustion), and a sandbox
without the namespaces can see the
system's resources (the host's
processes, the host's files). The two
mechanisms' combination is the modern's
containers' design.
Question 4
Describe the seccomp's filters, the chroot and the pivot_root, and the systemd's hardening's directives. What is each mechanism's design, and how does each contribute to the confinement?
Show answer
SECCOMP_RET_ALLOW, the
SECCOMP_RET_ERRNO, the
SECCOMP_RET_KILL_PROCESS,
the SECCOMP_RET_TRAP, the
SECCOMP_RET_TRACE, the
SECCOMP_RET_LOG, the
SECCOMP_RET_USER_NOTIF).
The seccomp's two modes: the strict's
mode (the original: the
read, the
write, the
_exit, and the
sigreturn only) and the
filter's mode (the modern: the BPF's
filters, the flexible's rules). The
seccomp's contribution to the
confinement: the attack's surface's
reduction (the system calls are
the kernel's interface, and the
kernel's bugs are the system calls'
exploits; the filter reduces the
exposed's system calls, so the
kernel's vulnerabilities' exploitation
is the harder). The chroot
is the classical's file system's
confinement: the chroot's
system call changes the process's
root's directory, so the process sees
the specified's directory as the root.
The chroot's design's weakness: the
chroot is not the security's boundary
(the process with the
CAP_SYS_CHROOT's capability
can escape, and the root's process can
escape by the /proc's and
the mknod's mechanisms).
The pivot_root is the
modern's mechanism: the
pivot_root's system call
changes the process's root's and the
current's directory to the new's file
system, and it moves the old's root to
the specified's directory (the
put_old), so the old's root
is the separate's mount and the escape's
paths are the closed. The pivot_root is
the containers' runtimes' mechanism.
The systemd's hardening's
directives are the services'
confinement's mechanisms: the file
system's directives (the
ProtectSystem, the
ProtectHome, the
ReadWritePaths, the
InaccessiblePaths, the
PrivateTmp, the
PrivateDevices, the
ProtectKernelTunables),
the user's and the group's directives
(the User, the
Group, the
DynamicUser, the
SupplementaryGroups), the
capabilities' and the privilege's
directives (the
CapabilityBoundingSet, the
AmbientCapabilities, the
NoNewPrivileges, the
SecureBits), the
namespaces' directives (the
PrivateMounts, the
PrivateNetwork, the
PrivateUsers, the
PrivateIPC, the
ProtectHostname, the
ProtectClock), the system
calls' and the addressing's directives
(the SystemCallFilter, the
SystemCallArchitectures,
the RestrictAddressFamilies,
the RestrictNamespaces, the
LockPersonality), and the
memory's and the kernel's directives
(the MemoryDenyWriteExecute,
the RestrictRealtime, the
RestrictSUIDSGID, the
ProtectKernelModules, the
ProtectKernelLogs, the
ProtectProc). The
directives' contribution to the
confinement: the services' resource's
and privilege's restriction, so the
compromised's service's damage is the
bounded. The
systemd-analyze security's
command evaluates the service's
sandbox's strength, and the observation
is the reason the modern's
distributions ship the services' units
with the hardening's directives (the
sensible's defaults).
Question 5
Describe the Linux containers and the browsers' sandboxes. What are the containers' security's mechanisms, what are the browsers' sandboxing's designs, and what are the sandbox's escapes' attacks and the sandboxing's design principles?
Show answer
overlayfs's union mount),
the runtime (the low-level's
runtimes: the runc, the
crun; the high-level's
runtimes: the containerd,
the conmon), the
engine (the Docker's
dockerd, the Podman's
podman, the Kubernetes's
kubelet), and the
standards (the OCI's
specifications: the Runtime's, the
Image's, the Distribution's). The
containers' security's mechanisms: the
namespaces (the isolated views), the
cgroups (the resource's limits), the
seccomp's filter (the default's
profiles: the Docker's and the
Podman's ~44's blocked's system calls),
the capabilities' minimization (the
dropped's set: the ~14), the LSM's
profiles (the SELinux's
container_t, the
AppArmor's docker-default),
the user's namespace (the rootless's
containers), and the read-only's file
system (the --read-only's
option). The containers' central's
observation: the containers are
not the VMs (the containers
share the host's kernel, and the VMs
have the separate's kernel), so the
containers' security depends on the
kernel's security. The
browsers' sandboxes
are the modern systems' most visible
sandboxes. The Chrome's
sandbox: the multi-process's
architecture (the browser's process,
the renderer's process per site, the
GPU's process, the utility's processes)
and the renderer's sandbox (the
chroot, the
seccomp's filter, the
clone's namespaces, the
setuid's and the
setgid's sandbox's user,
the capabilities' dropping, the
OpenBSD's pledge and
unveil, the macOS's
sandbox_init). The
renderer's process has no direct access
to the file system (the broker's
process's mediation), and its system
calls are the whitelist's set. The
Firefox's sandbox: the
multi-process's architecture and the
content's processes' sandbox (the
seccomp-bpf's filter, the
chroot, the user's
namespace, the capabilities' dropping,
the file's access's brokering), with
the levels (the content,
the socket, the
utility, the
widevine). The
sandbox's escapes' attacks:
the kernel's vulnerabilities
(the Dirty COW, the
Dirty Pipe, the
OverlayFS's bugs: the
containers share the kernel, so the
kernel's vulnerability compromises the
every container), the configuration's
mistakes (the
--privileged's flag, the
host's namespaces' sharing, the
sensitive's mounts: the
docker.sock's mount), the
design's flaws (the incomplete's
mediation, the incorrect's assumptions,
the IPC's channels, the shared's
resources), and the side channels
(the timing's channels, the
speculative's execution: the Spectre's
and the Meltdown's attacks). The
sandboxing's design's
principles apply the Lesson
12.1's principles: the least privilege
(the minimum's resources), the
fail-safe defaults (the denial's
default), the complete mediation (the
every access's check), the economy of
mechanism (the simple and the small),
the separation of privilege (the
multiple's conditions), the least
common mechanism (the minimized's
sharing), the psychological
acceptability (the usable), and the
open design (the auditable). The
sandboxing's central's observation: the
sandbox is the defence in
depth's application (the
multiple's walls, the multiple's
failures' uncorrelation), and the
sandbox's strength depends on the
kernel's security, the configuration's
correctness, and the monitoring's
detection.
08 Unit discussion
Discussion prompt
The sandboxing is the modern security's
central's architecture, and its history is a
history of the isolation's mechanisms'
accumulation. The classical's Unix provided
the chroot (the file system's
view's restriction) and the users' separation
(the processes' isolation), and the design was
the sufficient for the time's single-tenant's
systems. The ptrace's and the
seccomp's mechanisms (the
system calls' filtering), the namespaces (the
views' isolation), and the cgroups (the
resources' limits) were the 2000s' additions,
and the containers (the Docker's, the Podman's,
the Kubernetes's) were the 2010s'
architecture. The browsers' sandboxes (the
Chrome's, the Firefox's) applied the
architecture at the web's scale, and the
systemd's hardening's directives (the 2010s
and the 2020s) brought the confinement to the
services. Each mechanism was the response to
the previous mechanisms' limitations, and
each was shaped by the threats of its time.
The trend is toward the layered's isolation and the least privilege. The classical's Unix was the single's mechanism (the chroot) and the coarse's isolation (the user's separation); the modern's Linux is the multiple's mechanisms (the namespaces, the cgroups, the seccomp, the capabilities, the LSM, the Landlock) and the fine-grained's isolation (the per-container's namespaces, the per-service's systemd's directives, the per-process's seccomp's filters). The trend's driver is the workloads' change: the modern's systems run the untrusted's code (the web's pages, the containers' images, the third-party's applications) at the scale, and the traditional's perimeter's defence cannot protect the interior's components. The sandboxing is the recognition that the perimeter is the permeable, and the zero trust's architecture is the trend's logical's end: the every component's isolation, the every access's verification, and the every resource's confinement.
The trend also raises a question about the
isolation's strength and the
compatibility's tension. The
stronger's isolation (the seccomp's
whitelist's filters, the read-only's file
systems, the minimal's capabilities, the VMs'
separate's kernels) is the more secure and
the less compatible, and the users' (and the
developers') response to the inconvenient's
isolation is the bypasses (the
--privileged's flag, the
--no-sandbox's option, the
iptables's rules' disabling,
the SELinux's permissive's mode). The
observation is the reason the psychological
acceptability's principle (Lesson 12.1's
principle 8) is the sandboxing's design's
central's concern: the sandbox's mechanism
must be the usable, or the users will find
the ways around it. The modern's approach
(the sensible's defaults: the containers'
default's profiles, the browsers' sandbox's
defaults, the systemd's hardening's
directives' defaults) is the principle's
practical's application.
Which of the sandboxing's mechanisms is the most important for the modern systems, and why? Should the sandboxing's design prioritize the isolation's strength (the seccomp's whitelist's filters, the VMs' separate's kernels) or the compatibility (the escape's hatches, the sensible's defaults)? What is the right balance between the sandbox's confinement and the legitimate's functionality? How should the sandboxing's design evolve for the AI's systems, the edge's computing, and the serverless's platforms? Post your response to the Unit 12 discussion forum and reply to at least two classmates. Supports CLO1, CLO7, and CLO8.
09 Practice exercise
This ungraded exercise consolidates the lesson and prepares you for Lesson 12.7. Aim to spend 60–90 minutes on it.
-
Explore the namespaces.
On your VM, create and inspect the
namespaces:
Which namespaces did the sandbox create? How many processes were visible in the sandbox's PID's namespace? Did the hostname's change affect the host? Write down your observations.# Show the current process's namespaces ls -la /proc/self/ns/ # Create a new's mount and PID and UTS's namespaces sudo unshare --mount --pid --fork --uts --mount-proc \ /bin/bash -c ' echo "PID: $$" hostname sandbox-test echo "Hostname: $(hostname)" ls /proc/ | grep -E "^[0-9]+$" | wc -l ps aux ' # Show the network's namespaces sudo ip netns list # Create a network's namespace and configure it sudo ip netns add test-ns sudo ip netns exec test-ns ip link sudo ip netns exec test-ns ip addr # Clean up sudo ip netns delete test-ns -
Create and test a cgroup's limit.
Use the
systemd-run's command to create the transient's services with the resource's limits, and observe the limits' effects:
Did the limits' effects appear? What was the memory's max's value? What was the CPU's quota's effect? How do the cgroups' limits enforce the resource's constraints?# Create a memory-limited service sudo systemd-run --unit=mem-test --property=MemoryMax=100M \ /bin/bash -c 'dd if=/dev/zero of=/dev/null bs=1M count=500' 2>&1 | head -3 # Monitor the service systemctl status mem-test 2>/dev/null | head -10 cat /sys/fs/cgroup/system.slice/mem-test.service/memory.max 2>/dev/null # Create a CPU-limited service sudo systemd-run --unit=cpu-test --property=CPUQuota=30% \ /bin/bash -c 'timeout 10 bash -c "while true; do :; done"' 2>&1 | head -3 # Check the CPU's usage systemd-cgtop -b -n 1 2>/dev/null | head -10 # Clean up sudo systemctl stop mem-test cpu-test 2>/dev/null sudo systemctl reset-failed mem-test cpu-test 2>/dev/null -
Evaluate the services' sandboxes.
Use the
systemd-analyze security's command to evaluate the system's services' sandboxes:
Which services have the highest exposure? Which have the lowest? What are the most common's unmet's directives? What would you harden on the system?# List the services systemctl list-units --type=service --state=running 2>/dev/null | head -20 # Evaluate each service's sandbox for svc in $(systemctl list-units --type=service --state=running --no-legend 2>/dev/null | awk '{print $1}'); do score=$(systemd-analyze security $svc 2>/dev/null | tail -1 | grep -oP '[\d.]+' | head -1) echo "$svc: $score" done | sort -t: -k2 -rn | head -10 -
Inspect a container's security.
If the Docker or the Podman is installed,
inspect a container's security's
configuration:
What are the container's dropped's and added's capabilities? What are the security's options? What are the container's namespaces? Is the seccomp's filter's mode the filter's (the mode 2)? What are the cgroup's limits?# Run a container docker run -d --name sec-test alpine sleep 3600 2>/dev/null # Inspect the container's security docker inspect sec-test 2>/dev/null | \ grep -A10 -E 'CapDrop|CapAdd|SecurityOpt|ReadonlyRootfs|Privileged|User' # Show the container's namespaces CONTAINER_PID=$(docker inspect -f '{{.State.Pid}}' sec-test 2>/dev/null) sudo ls -la /proc/$CONTAINER_PID/ns/ # Show the container's capabilities sudo nsenter -t $CONTAINER_PID -a capsh --print 2>/dev/null | head -10 # Show the container's seccomp's status sudo grep Seccomp /proc/$CONTAINER_PID/status 2>/dev/null # Show the container's cgroup's limits cat /sys/fs/cgroup/system.slice/docker-*.scope/memory.max 2>/dev/null # Clean up docker rm -f sec-test 2>/dev/null -
Design a container's security's
policy.
A web application is being containerized.
The application needs to bind to the port
8080 (unprivileged), to read the files in
the
/app's directory, and to connect to the database on the network. Design the container's security's policy:- Which namespaces would you enable?
- Which capabilities would you drop and which would you keep?
- Which seccomp's profile would you use (the default, the custom)?
- Which LSM's profile would you use?
- What would be the cgroup's limits?
- What would be the file system's configuration (the read-only's root, the volumes)?
- What would be the user's configuration (the non-root's user, the rootless's containers)?
-
Analyze a sandbox's escape.
Choose a known sandbox's escape (the
Dirty COWin the Docker, theCVE-2019-5736in therunc, theCVE-2020-15257in thecontainerd, theCVE-2021-25741in the Kubernetes's subpath, or the browser's escape) and analyze it:- The vulnerability's description.
- The escape's mechanism (which wall was bypassed?).
- The affected's versions and the fixes.
- The lessons for the sandboxing's design.
-
Compare the sandboxing's
mechanisms.
Write a short essay (400–500 words)
comparing the sandboxing's mechanisms
(the chroot, the capabilities, the
seccomp, the namespaces, the cgroups, the
LSM's profiles, the VMs). Your essay
should address:
- Each mechanism's isolation's scope.
- Each mechanism's strength.
- Each mechanism's cost (the performance, the compatibility).
- Each mechanism's appropriate use's cases.
- The mechanisms' combinations in the modern's sandboxes (the containers, the browsers).
-
Design a service's hardening.
A web server (the
nginx) is running on the system. Design the service's systemd's sandboxing's configuration:- Which file system's directives would you apply?
- Which namespaces' directives would you apply?
- Which capabilities' directives would you apply?
- Which system calls' directives would you apply?
- What would be the resource's limits (the CPU, the memory, the I/O)?
- How would you test the configuration and verify the service's operation?
[Service]'s section and justify the directives. - Reflect. In your own words, explain the sandboxing's goals and the confinement's mechanisms (the namespaces, the cgroups, the seccomp, the chroot, the containers, the browsers' sandboxes, the systemd's directives). Then describe one situation in your own experience — a container you have run, a browser you have used, or a service you have administered — where the sandboxing affected the security or the usability. What was the situation, and how would a different configuration have changed the outcome?
10 Summary
- A sandbox is the isolated's environment in which the untrusted's code runs, with the walls that confine the code's capabilities. The sandbox's goals: the damage's limitation, the least privilege's enforcement, the isolation's guarantee, and the multi-tenancy's support. The confinement's spectrum ranges from the chroot to the virtual machines, and the mechanisms are the complementary (the defence in depth).
-
The Linux namespaces give
the processes the isolated's views: the
mount, the PID, the network, the user, the
IPC, the UTS, the cgroup, and the time.
The management's mechanisms: the
clone, theunshare, thesetns, the/proc/PID/ns/'s interface, and theip netns's command. -
The control groups (cgroups)
limit and account the processes' resource's
usage. The v1's design is the multiple
hierarchies (one per the controller); the
v2's design is the single hierarchy. The
controllers: the
cpu, thememory, theio, thepids, and the others. -
The seccomp filters the
process's system calls: the BPF's filters
with the actions
(
SECCOMP_RET_ALLOW,SECCOMP_RET_ERRNO,SECCOMP_RET_KILL_PROCESS, the others). The seccomp is the attack's surface's reduction, and it is the containers' and the browsers' central's mechanism. - The chroot changes the process's root's directory (the file system's view's restriction), and the pivot_root changes the root's mount (the modern's mechanism, the containers' runtimes' design).
- The containers (the Docker, the Podman, the LXC, the OCI's standards) combine the namespaces, the cgroups, the seccomp's filters, the capabilities' minimization, the LSM's profiles, and the image's layers. The containers are the sandboxing's modern's architecture, and their isolation is the kernel's mechanisms' (the shared's kernel is the VMs' security's difference).
- The browsers' sandboxes (the Chrome's, the Firefox's) apply the multi-process's architecture and the renderer's sandbox (the chroot, the seccomp, the namespaces, the sandbox's user, the capabilities' dropping, the broker's IPC's mediation).
-
The systemd's hardening's
directives configure the services'
sandboxing: the file system's directives
(
ProtectSystem,ProtectHome,PrivateTmp, the others), the namespaces' directives (PrivateMounts,PrivateNetwork, the others), the capabilities' directives (CapabilityBoundingSet,NoNewPrivileges), the system calls' directives (SystemCallFilter, the others). Thesystemd-analyze security's command evaluates the service's sandbox's strength. -
The Landlock is the
unprivileged's sandboxing's mechanism (the
file system's access's restriction without
the
CAP_SYS_ADMIN's capability), and thebubblewrapand thefirejailare the user-space's tools. - The sandbox's escapes are the kernel's vulnerabilities, the configuration's mistakes, the design's flaws, and the side channels. The sandboxing's design's principles apply the Lesson 12.1's principles: the least privilege, the fail-safe defaults, the complete mediation, the economy of mechanism, the separation of privilege, the least common mechanism, the psychological acceptability, and the open design.
Looking ahead
This lesson presented the sandboxing: the isolation's goals, the confinement's spectrum, the Linux namespaces, the cgroups, the seccomp's filters, the chroot and the pivot_root, the containers, the browsers' sandboxes, the systemd's hardening's directives, the Landlock, the escapes' attacks, and the design's principles. It referred several times to the virtual machines — the sandboxing's strongest's mechanism, with the separate's kernel and the hardware's virtualization — and to the hypervisors. Lesson 12.7 presents the operating system's hardening in detail: the hardening's methodology (the CIS's benchmarks, the NIST's guides, the STIG's guides), the configuration's hardening (the services, the kernel, the network, the file systems), the monitoring's and the detection's mechanisms (the HIDS, the file's integrity's monitoring, the logs' analysis), the patch's management, and the security's operations. The lesson is the unit's final's synthesis, and it is the bridge to the virtualization and the cloud that Unit 13 presents.
11 References
- Silberschatz, A., Galvin, P. B., & Gagne, G. Operating System Concepts, 10th ed., Chapters 16 and 17.
-
Arpaci-Dusseau, R. H., & Arpaci-Dusseau, A. C.
Operating Systems: Three Easy Pieces,
the Security and the
Virtualization chapters. Available
online at
ostep.org. - Tanenbaum, A. S., & Bos, H. Modern Operating Systems, 4th ed., Chapters 7 and 9.
- Kerrisk, M. The Linux Programming Interface. No Starch Press, 2010. Chapters 20, 24, 28, 37, and 61.
-
Kerrisk, M. The Linux namespaces.
The
man 7 namespacespage and the LWN's articles. - Rosen, R. Resource Management: The Linux and the SUSE Approaches. The Novell/SUSE's and the RHEL's resource-management's guides.
- Edge, J., & other LWN's authors. The LWN's series on the seccomp's filters, the Landlock, and the container's security.
- Rice, L. Container Security. O'Reilly, 2020.
- The Open Container Initiative (the OCI). The Runtime's Specification, the Image's Specification, and the Distribution's Specification.
-
Linux man-pages:
man 7 namespaces,man 2 clone,man 1 unshare,man 1 nsenter,man 2 setns,man 1 ip-netns,man 7 cgroups,man 1 systemd-cgls,man 1 systemd-cgtop,man 1 systemd-run,man 2 seccomp,man 2 chroot,man 2 pivot_root,man 5 systemd.exec,man 5 systemd.resource-control,man 1 systemd-analyze,man 1 firejail,man 1 bubblewrap,man 8 docker,man 1 podman.