Home/Linux
Lab · Manual of Linux

Linux

The engine under the hood.

32 exercises9 Parts5 appendices
The colour code shows the level:FoundationalIntermediateAdvanced
get the exercises
git clone --filter=blob:none --sparse https://github.com/calmict/book_labs.git
cd book_labs
git sparse-checkout set linux/ed1
calm@calmict:~$ cat linux/topics
Part 1

The foundations and the philosophy

  • 01Traces of History on Your MachineFoundational
  • 02Build a Tool That Does Not ExistFoundational
  • 03The Boundary, Seen from the Service WindowFoundational
  • 04Read a Machine You Do Not KnowFoundational
Part 2

Powering on

  • 05Identify and Safeguard Your Boot ChainFoundational
  • 06Enter a System Through the Service DoorFoundational
  • 07Open the Borrowed ToolboxFoundational
  • 08Write a Service and Measure a BootFoundational
Part 3

Processes

  • 09X-Ray a ProcessFoundational
  • 10Duplicate, Transform, DisappearFoundational
  • 11Watch the Scheduler DecideIntermediate
  • 12Talk to a Process That Refuses to ListenFoundational
Part 4

Memory

  • 13Two Processes, One Address, Two MemoriesFoundational
  • 14Trigger Faults and Watch Them HappenFoundational
  • 15Fill Memory and See What FallsFoundational
Part 5

Files and filesystems

  • 16Work with Numbers, Not NamesFoundational
  • 17One Tree, Many WorldsIntermediate
  • 18The Name Is Not the FileFoundational
  • 19The Data You Think You SavedIntermediate
Part 6

Identity, permissions, security

  • 20The Number Behind the NameFoundational
  • 21Deleting a File You Cannot ReadFoundational
  • 22Two Groups, One DirectoryIntermediate
  • 23Stop Root with a PolicyAdvanced
Part 7

The shell and the kernel interface

  • 24The Command You Did Not WriteFoundational
  • 25Fill the Service WindowFoundational
  • 26Seeing What Nobody Tells YouIntermediate
Part 8

Networking

  • 27Following a PacketIntermediate
  • 28Building a Network by HandIntermediate
  • 29A Minimal Firewall, with Proof of Where It FiltersIntermediate
Part 9

Isolation: the bridge to containers

  • 30Building an IllusionAdvanced
  • 31Setting a CeilingAdvanced
  • 32Your Container, from the First LineAdvanced
calm@calmict:~$ ls linux/exercises/
01Traces of History on Your MachineFoundational

What you build

> Exercise for Chapter 1 — From Unix to Linux: The History That Explains the Present of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • read a kernel release and distinguish its base version from the distribution suffix;
  • trace a command back to its package and the license declared in local package metadata;
  • recognize a merged-/usr system and explain why /bin points to /usr/bin.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap01/solution
./run.sh

Expected result

  • [ ] The script prints the release returned by uname -r, its base numeric triplet, and any distribution or build suffix.
  • [ ] The output explains that the numbers identify a release line but do not, by themselves, prove whether fixes have been backported.
  • [ ] The output for ls and uname includes the path, owning package, declared license, and local source consulted.
  • [ ] The script shows what /bin is on the current machine and, when it is a link, where it leads.
  • [ ] The explanation connects the old need for /bin before /usr was mounted with the modern merge into /usr/bin.
  • [ ] The script exits successfully, needs no privileges, and makes no system changes.
02Build a Tool That Does Not ExistFoundational

What you build

> Exercise for Chapter 2 — The Unix Philosophy: Tools That Work Together of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • turn an operational question into a sequence of small filters;
  • connect awk, sort, uniq, and head in a reproducible pipeline;
  • distinguish a concurrent pipeline from a plain sequence of commands;
  • inspect intermediate and final results instead of trusting appearances.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap02/solution
./run.sh

Expected result

  • [ ] report.txt lists the 5xx paths in descending count order.
  • [ ] You inspected at least one intermediate result before the final report.
  • [ ] start/answers.md describes the data flowing through every pipe.
  • [ ] You saw the consumer's first line before the two-second pause ended.
  • [ ] You can explain why sort may delay output while still belonging to a concurrent pipeline.
  • [ ] solution/run.sh completes all checks and leaves no temporary files behind.
03The Boundary, Seen from the Service WindowFoundational

What you build

> Exercise for Chapter 3 — Kernel and User Space: The Line Between Two Worlds of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • observe the requests a user-space program makes to the kernel;
  • count and classify system calls with a strace summary;
  • recognize ENOENT as the result of looking up a nonexistent file;
  • distinguish the administrative identity UID 0 from the CPU's privileged mode.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap03/solution
./run.sh

Expected result

  • [ ] You recorded the strace -c summary and the total number of system calls.
  • [ ] You found a failed openat with ENOENT for the nonexistent file.
  • [ ] You traced a process that prints UID 0 and observed its system calls.
  • [ ] You can explain why UID 0 and kernel mode are not the same thing.
  • [ ] solution/run.sh passes its checks or explicitly reports a ptrace restriction.
  • [ ] All temporary traces have been removed.
04Read a Machine You Do Not KnowFoundational

What you build

> Exercise for Chapter 4 — Anatomy of an Installed System of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • derive a distribution's identity and family from /etc/os-release;
  • identify the package manager and query its database;
  • compare the running kernel with the packages declared as installed;
  • use findmnt and lsblk to find directories backed by separate filesystems.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap04/solution
./run.sh

Expected result

  • [ ] You recorded the distribution, version, and family from /etc/os-release.
  • [ ] You identified the package manager and queried one installed package.
  • [ ] You compared uname -r with the package database declaration.
  • [ ] You listed directories backed by block partitions other than the one for /.
  • [ ] You distinguished a separate mount from a subtree of the same source.
  • [ ] solution/run.sh completes all checks without changing the system.
05Identify and Safeguard Your Boot ChainFoundational

What you build

> Exercise for Chapter 5 — BIOS and UEFI: Two Ways to Start a Machine of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • distinguish a UEFI boot from a BIOS boot by inspecting the firmware interface;
  • locate and explore the EFI System Partition without modifying it;
  • read BootCurrent, BootOrder, and the BootNNNN entries printed by efibootmgr -v;
  • create and verify a boot-chain backup without writing to NVRAM.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap05/solution
./run.sh

Expected result

  • [ ] You determined UEFI or BIOS from the presence of /sys/firmware/efi.
  • [ ] On UEFI, you identified the ESP source, type, and mount options.
  • [ ] You listed ESP loaders without unmounting, remounting, or writing to it.
  • [ ] You interpreted BootCurrent, BootOrder, and at least one BootNNNN entry.
  • [ ] You created a verified archive containing the ESP copy, metadata, and checksums.
  • [ ] You planned a second copy on separate storage.
  • [ ] You ran no efibootmgr command that writes to NVRAM.
06Enter a System Through the Service DoorFoundational

What you build

> Exercise for Chapter 6 — The Bootloader and the Handoff of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • read and preserve the running kernel command line;
  • edit a GRUB entry temporarily without changing its on-disk configuration;
  • compare a quiet boot with one that exposes kernel messages;
  • reach rescue mode and start /bin/bash as PID 1;
  • explain why access to the boot console often amounts to control of the system.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap06/solution
./run.sh

Expected result

  • [ ] You preserved and interpreted the current host command line.
  • [ ] You observed a boot without quiet and the messages it previously hid.
  • [ ] You reached the rescue-mode maintenance prompt.
  • [ ] You verified /bin/bash as PID 1 after using init=/bin/bash.
  • [ ] You edited GRUB only for the current boot and changed no boot configuration.
  • [ ] You explained the risk associated with physical console access.
  • [ ] The qemu process stopped and the directory containing the overlay is gone.
07Open the Borrowed ToolboxFoundational

What you build

> Exercise for Chapter 7 — The Kernel Takes Control of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • distinguish dracut modules from kernel modules stored in an initramfs;
  • identify the drivers selected to reach the root disk and filesystem;
  • find the hooks or units that prepare /sysroot and hand off to the real root;
  • demonstrate in a VM why a missing storage driver prevents booting;
  • rebuild a working initramfs without knowing the guest password.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap07/solution
./run.sh

Expected result

  • [ ] You inspected a copy and never the original file in /boot.
  • [ ] You distinguished dracut modules from kernel modules.
  • [ ] You related the storage and filesystem drivers to the host root.
  • [ ] You read at least one real hook and the switch-root mechanism.
  • [ ] You broke only the overlay initramfs and observed the dracut shell.
  • [ ] You preserved the guest's actual failure message.
  • [ ] You repaired the image without a password and verified the final boot.
  • [ ] The QEMU process and temporary directory no longer exist.
08Write a Service and Measure a BootFoundational

What you build

> Exercise for Chapter 8 — PID 1: From init to systemd of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • write and validate a user unit with explicit dependencies;
  • configure and observe an automatic restart;
  • distinguish an immediate start with systemctl --user start from enablement at future starts with systemctl --user enable;
  • compare systemd-analyze blame with systemd-analyze critical-chain without confusing duration with impact on the critical path.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap08/solution
./run.sh

Expected result

  • [ ] The main service starts only after its oneshot dependency.
  • [ ] The log contains at least two timestamps and NRestarts is at least 1.
  • [ ] After start, the service is active but not enabled.
  • [ ] After enable and before the new start, the service is enabled but inactive.
  • [ ] You compared the first blame entry with the critical chain and explained why they need not identify the same unit.
  • [ ] The lab units, enablement link, and runtime data no longer exist at the end.
09X-Ray a ProcessFoundational

What you build

> Exercise for Chapter 9 — Anatomy of a Process of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • inspect a live process's state, memory, open descriptors, and namespaces through /proc;
  • recognize a zombie and relate it to a missing wait call in its parent;
  • distinguish interruptible sleep S from uninterruptible sleep D;
  • experimentally verify the effect of SIGKILL on a process blocked on a FIFO;
  • (optional step, needs sudo) produce a genuine D state with a device-mapper delay target, and see why a FIFO cannot.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap09/solution
./run.sh

Expected result

  • [ ] You found the file held open by the test process through /proc.
  • [ ] You read VmRSS, smaps_rollup, and the process's namespace links.
  • [ ] You observed state Z and its disappearance after waitpid.
  • [ ] You observed that the FIFO wait is S, not D.
  • [ ] You verified that SIGKILL terminates the FIFO-blocked process with wait status 137.
  • [ ] You recorded why the FIFO cannot demonstrate the D state, without claiming it was verified anyway.
  • [ ] (if you ran step 6) You observed STAT D and State: D (disk sleep) during the wait on the dm-delay device, and a non-zero dmsetup status counter while the I/O was pending.
  • [ ] No labcap09 process, device-mapper node, loop device, or temporary file remains at the end.
10Duplicate, Transform, DisappearFoundational

What you build

> Exercise for Chapter 10 — fork, exec, wait: How a Process Is Born and Dies of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • observe the relationship between a parent process and the child created by fork() from the outside;
  • prove that exec() replaces a program without changing its PID;
  • recognize a zombie by its Z state and remove it by making the parent call wait().

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap10/solution
./run.sh

Expected result

  • [ ] ps shows the parent and child at the same time, with the correct PID/PPID relationship.
  • [ ] The PID before and after exec is identical, and the program observed after exec is sleep.
  • [ ] The terminated child appears in state Z before the parent's wait call.
  • [ ] After SIGUSR1 is sent to the parent, the zombie's PID no longer exists.
  • [ ] Every test process has exited and the temporary directory has been removed.
11Watch the Scheduler DecideIntermediate

What you build

> Exercise for Chapter 11 — The Scheduler: Who Runs, and for How Long of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • observe several CPU-bound processes sharing a limited CPU quota;
  • measure the CPU effect of nice and distinguish it from I/O priority;
  • recognize high load with mostly idle CPUs by reading load average, runnable processes, and CPU use together.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap11/solution
./run.sh

Expected result

  • [ ] Every docker run command has an explicit --cpus limit and ends within a few seconds.
  • [ ] You observed four processes sharing two CPUs and recorded each process's ticks.
  • [ ] Under CPU contention, the nice 0 process accumulated more ticks than the nice 15 process.
  • [ ] The dd comparison documents that nice alone does not guarantee I/O priority and identifies the other relevant variables.
  • [ ] You recognized many runnable processes alongside CPU use confined to about one quarter of one core.
  • [ ] No labcap11 container remains running.
12Talk to a Process That Refuses to ListenFoundational

What you build

> Exercise for Chapter 12 — Signals: The Kernel's Messaging System of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • catch SIGTERM and perform an orderly shutdown outside the signal handler;
  • prove that SIGKILL cannot be caught and prevents application cleanup;
  • use SIGHUP to reload configuration without changing the PID;
  • diagnose and fix a PID 1 process that makes docker stop wait for ten seconds.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap12/solution
./run.sh

Expected result

  • [ ] SIGHUP reloads the changed value and the service PID does not change.
  • [ ] SIGTERM produces an orderly-shutdown entry and removes the work file.
  • [ ] SIGKILL leaves the work file behind, proving that cleanup did not run.
  • [ ] The faulty container takes about ten seconds to stop.
  • [ ] The corrected PID 1 forwards termination to its child, reaps it, and stops quickly.
  • [ ] No test process or labcap12 container remains active.
13Two Processes, One Address, Two MemoriesFoundational

What you build

> Exercise for Chapter 13 — Virtual Memory: Addresses That Lie of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • prove that two processes can use the same virtual address for different contents;
  • read /proc/PID/maps and interpret the permissions and purpose of its main regions;
  • measure RSS and PSS in /proc/PID/smaps_rollup and explain how shared pages are accounted for.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap13/solution
./run.sh

Expected result

  • [ ] Two distinct processes report the same virtual address and different initial values.
  • [ ] Changing alpha's page does not alter the value observed by beta.
  • [ ] You identified the executable, heap, stack, anonymous page, libraries, vvar, and vdso from their permissions.
  • [ ] You measured RSS and PSS for both instances and explained why PSS is lower when pages are shared.
  • [ ] Both test processes have exited and temporary files have been removed.
14Trigger Faults and Watch Them HappenFoundational

What you build

> Exercise for Chapter 14 — Paging, Page Faults, and Swap of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • distinguish minor and major faults by measuring two reads of the same file;
  • watch copy-on-write create private copies one page at a time after fork;
  • recognize the onset of thrashing from scans, refaults, and memory pressure;
  • contain a memory-pressure experiment in a resource-limited cgroup.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap14/solution
./run.sh

Expected result

  • [ ] You recorded minor and major faults for the first and second reads of the same file.
  • [ ] You observed minor faults increase while the child modified shared pages after fork.
  • [ ] You explained the relationship between copy-on-write and minor faults.
  • [ ] You ran memory pressure only in a container with explicit limits and a timeout, or documented why the daemon was unavailable.
  • [ ] You compared at least two metrics among scans, refaults, and memory pressure.
  • [ ] No lab container or process remains after completion.
15Fill Memory and See What FallsFoundational

What you build

> Exercise for Chapter 15 — Allocation, Cache, and the OOM Killer of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • distinguish free memory from available memory as the page cache grows;
  • observe that a large virtual allocation consumes no physical memory until its pages are touched;
  • trigger a contained out-of-memory event and identify the process killed by the kernel;
  • verify memory limits and the OOM outcome through container state.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap15/solution
./run.sh

Expected result

  • [ ] You compared free memory with an available-memory estimate before and after filling the page cache.
  • [ ] You showed that virtual memory grows much more than physical memory for an untouched allocation.
  • [ ] You obtained OOMKilled=true and exit code 137 for the OOM container only.
  • [ ] You read the allocator log through the block immediately before termination.
  • [ ] You verified that memory and memory-swap limits match for every container.
  • [ ] No lab process or container remains active at the end.
16Work with Numbers, Not NamesFoundational

What you build

> Exercise for Chapter 16 — Everything Is a File: Descriptors and I/O of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • inspect a process's descriptor table across open and close operations;
  • verify that redirection changes the object assigned to a descriptor number;
  • identify an unlinked file that is still open;
  • connect the last descriptor's close operation with reclamation of the occupied space.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap16/solution
./run.sh

Expected result

  • [ ] You compared the descriptor table before open, after open, and after close.
  • [ ] You identified the descriptor number that was added and later removed.
  • [ ] You verified that descriptor 1 refers to the file after redirection.
  • [ ] You found the open unlinked file with lsof and observed an NLINK value of zero.
  • [ ] You verified that the entry disappears after close.
  • [ ] No lab process or temporary file remains at the end.
17One Tree, Many WorldsIntermediate

What you build

> Exercise for Chapter 17 — VFS: The Layer That Unifies Filesystems of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • observe how a mount temporarily hides the underlying directory contents;
  • create a private view of the mount tree without administrative privileges;
  • compare the same pathname from inside and outside a namespace;
  • traverse /proc/PID/root to reach an isolated process's view when permissions allow it.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap17/solution
./run.sh

Expected result

  • [ ] You saw the original file before the mount, hidden during the mount, and visible again after umount.
  • [ ] You verified that the file created in tmpfs is visible only from the isolated view.
  • [ ] You confirmed through mountinfo that labcap17tmpfs belongs only to the private namespace.
  • [ ] You reached the inside file through /proc/PID/root or documented the permission denial.
  • [ ] You used no sudo command and mounted nothing in the host's real view.
  • [ ] No lab process, mount, or scratch directory remains at the end.
18The Name Is Not the FileFoundational

What you build

> Exercise for Chapter 18 — Inodes, Links, and Filesystem Structure of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • distinguish a directory entry from the inode it points to;
  • compare hard links and symbolic links when a name is removed;
  • recognize inode exhaustion even when data space remains available;
  • publish a complete file through an atomic rename.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap18/solution
./run.sh

Expected result

  • [ ] Both hard links have the same inode and the count rises to 2, then returns to 1 after one name is removed.
  • [ ] The broken symbolic link is recognized as a link but not as a path to an existing file.
  • [ ] Exhaustion occurs only on labcap18.img, and df shows no free inodes while data space remains.
  • [ ] The atomic-rename reader observes no missing or partial state.
  • [ ] The loop device, mount, image, and temporary files have been removed at the end.
19The Data You Think You SavedIntermediate

What you build

> Exercise for Chapter 19 — Real Filesystems and the Block Layer of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • observe dirty data in the kernel cache after a write;
  • measure the difference between finishing a write and requesting synchronization;
  • replace a file without exposing intermediate states and make the new directory entry durable;
  • trace the stack from a mount to its underlying block devices.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap19/solution
./run.sh

Expected result

  • [ ] You collected Dirty before the write, immediately after it, and after synchronizing the file.
  • [ ] You timed both writes and can distinguish write completion from persistence requested through fsync.
  • [ ] The producer performs a complete write, file fsync, rename, and directory fsync, in that order.
  • [ ] The concurrent reader sees no missing, partial, or mixed state.
  • [ ] The conv=fsync copy passes cmp and produces matching checksums; no real crash was induced.
  • [ ] You inspected the device stack with findmnt and lsblk without writing to a block device.
  • [ ] All test files were removed at the end.
20The Number Behind the NameFoundational

What you build

> Exercise for Chapter 20 — Users, Groups, and Identity of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • distinguish an account name from its numeric UID;
  • predict how renumbering affects the ownership name displayed for files;
  • diagnose permission failures on a volume shared by environments with different UID maps;
  • follow a PAM chain and identify the auth, account, password, and session groups.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap20/solution
./run.sh

Expected result

  • [ ] useradd and usermod ran only inside an ephemeral container.
  • [ ] You observed UID 21001 remain in the inode while its displayed owner name disappeared and then changed.
  • [ ] The shared volume reproduces a read denial between UIDs 23001 and 24001 despite matching user names.
  • [ ] You identified auth, account, password, and session in the host's PAM chain.
  • [ ] PAM files were not modified, and all labcap20 containers and test data were removed.
21Deleting a File You Cannot ReadFoundational

What you build

> Exercise for Chapter 21 — Permissions, Setuid, and Capabilities of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • connect file creation and deletion to directory permissions rather than file permissions;
  • distinguish directory traversal from directory listing;
  • compare a setuid-root executable with the same executable carrying only the capability it needs;
  • verify effective privileges and cleanup without modifying host binaries or accounts.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap21/solution
./run.sh

Expected result

  • [ ] You deleted an unreadable file by relying on directory write and search permission.
  • [ ] You saw rm fail both without directory write permission and without directory search permission.
  • [ ] A known path works in a mode 0111 directory, but ls is denied.
  • [ ] Setuid and setcap were applied only to the copy in the container's isolated scratch directory.
  • [ ] The setuid test works with EUID 0; the cap_net_raw test works while retaining labcap21user's EUID.
  • [ ] No host account, security attribute, container, or test file remains.
22Two Groups, One DirectoryIntermediate

What you build

> Exercise for Chapter 22 — ACLs and Extended Permissions of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • grant different rights to two groups on the same directory;
  • define default ACLs that propagate to newly created content;
  • interpret the ACL mask and the effect of chmod on extended ACLs;
  • verify which copy methods preserve ACLs.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap22/solution
./run.sh

Expected result

  • [ ] The directory grants different rights to two groups beyond the traditional nine mode bits.
  • [ ] A new file and subdirectory inherit the default ACL.
  • [ ] You observed chmod changing the mask and restored access with setfacl.
  • [ ] You compared one copy that preserves ACLs with two copies that do not clone the named ACL.
  • [ ] You completed answers.md and removed the scratch directory.
23Stop Root with a PolicyAdvanced

What you build

> Exercise for Chapter 23 — Mandatory Access Control and Hardening of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • identify an SELinux denial that appears as an HTTP 403 response;
  • fix a content label without broadening Unix permissions;
  • use permissive mode for one domain only while diagnosing a denial;
  • prove that process arguments are not a safe place for secrets.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap23/solution
./run.sh

Expected result

  • [ ] You reproduced a label-driven 403 and a 200 after chcon, without chmod.
  • [ ] You diagnosed the denial by making only httpd_t permissive, then removed the exception.
  • [ ] A second user in the container read the secret from /proc/PID/cmdline.
  • [ ] No lab server or container remains active, and the scratch directory was removed.
  • [ ] answers.md contains the requested contexts, HTTP status codes, and explanations.
24The Command You Did Not WriteFoundational

What you build

> Exercise for Chapter 24 — The Shell: What Happens Before Execution of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • distinguish typed command text from the arguments received by a program;
  • recognize the effects of word splitting and pathname expansion;
  • protect file names and variable values with quotes;
  • make a script independent of its current directory and interactive PATH.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap24/solution
./run.sh

Expected result

  • [ ] You displayed the argument vector produced by quoting, variables, and pathname expansion.
  • [ ] You reproduced the failure caused by a space in a file name and fixed it with quotes.
  • [ ] The original script succeeds with the interactive PATH and fails under env -i.
  • [ ] The fixed script succeeds under env -i by deriving a path from its own location.
  • [ ] You completed answers.md and removed all temporary files.
25Fill the Service WindowFoundational

What you build

> Exercise for Chapter 25 — Pipes and Redirection: Composing Tools of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • measure a pipe's actual capacity without assuming a fixed value;
  • observe backpressure between a producer and a consumer;
  • recognize a subshell created by a Bash pipeline;
  • connect status 141 to SIGPIPE when pipefail is enabled.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap25/solution
./run.sh

Expected result

  • [ ] You measured capacity by actually filling a pipe until EAGAIN.
  • [ ] You observed the blocked producer and its resumption after the consumer read data.
  • [ ] You obtained count=0 with the pipeline and count=3 with process substitution.
  • [ ] You triggered status 141 and identified the producer as the process terminated by SIGPIPE.
  • [ ] Every test process and file descriptor has terminated.
26Seeing What Nobody Tells YouIntermediate

What you build

> Exercise for Chapter 26 — System Calls, procfs, and sysfs: Looking Inside of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • use strace to find the system call behind an error that a program hides;
  • recognize stdio buffering when stdout is connected to a pipe and fix it;
  • read and change a network sysctl inside an isolated namespace;
  • distinguish an immediate change from a configuration loaded at boot.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap26/solution
./run.sh

Expected result

  • [ ] The trace shows openat returning -1 ENOENT for the missing file.
  • [ ] You observed zero bytes during the buffered run and data already visible during the unbuffered run.
  • [ ] You verified sysctl values 0 and 1 exclusively inside labcap26.
  • [ ] You can explain the role of the file under /etc/sysctl.d and performed any reboot test only on a disposable machine.
  • [ ] The labcap26 namespace and all temporary files have been removed.
27Following a PacketIntermediate

What you build

> Exercise for Chapter 27 — The TCP/IP Stack Inside the Kernel of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • read the per-CPU distribution of network-related interrupts;
  • trigger and identify drops caused by a full UDP receive buffer;
  • distinguish socket drops from drops recorded on an interface;
  • test whether net.netfilter.nf_conntrack_max is really namespace-isolated, and recognize the symptom when it is not.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap27/solution
./run.sh

Expected result

  • [ ] You recorded per-CPU counters for at least one network interrupt source, or documented that the environment exposes none.
  • [ ] You increased Udp RcvbufErrors and socket drops without incorrectly attributing them to interface RX dropped.
  • [ ] You read nf_conntrack_max back from inside labcap27 and from the initial namespace after writing 128 inside the namespace, and confirmed the value did not change.
  • [ ] You confirmed that every UDP flow sent was tracked and received, consistent with no ceiling actually being applied.
  • [ ] You recorded why nf_conntrack_max is not namespace-isolated on this kernel, unlike net.ipv4.ip_forward.
  • [ ] labcap27, its nft table, and all test processes have been removed.
28Building a Network by HandIntermediate

What you build

> Exercise for Chapter 28 — Interfaces, Addresses, Routing, and Sockets of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • create network namespaces and move the ends of a veth pair into them;
  • configure addresses and verify connectivity between two isolated network stacks;
  • build an Ethernet segment with a bridge and three endpoints;
  • use ip route get to predict the interface and source address selected by the kernel.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap28/solution
./run.sh

Expected result

  • [ ] The labcap28 names were checked before creation.
  • [ ] labcap28a reaches labcap28b over the direct veth pair.
  • [ ] Three endpoints reach one another through labcap28br.
  • [ ] The decisions shown by ip route get match the connectivity tests.
  • [ ] All namespaces, the bridge, and all labcap28 veth devices have been removed.
29A Minimal Firewall, with Proof of Where It FiltersIntermediate

What you build

> Exercise for Chapter 29 — nftables and the Firewall of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • build a ruleset with a default drop policy and explicit exceptions;
  • distinguish the input and forward paths using named counters;
  • publish an internal service with DNAT;
  • identify the address and port before and after translation.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap29/solution
./run.sh

Expected result

  • [ ] The ruleset has a drop policy and exposes only the required exceptions.
  • [ ] The published connection increments labcap29_forward_web but not labcap29_input_seen.
  • [ ] The service is reachable through 10.29.1.1:18080 and the server records 10.29.2.2:8080 as its local destination.
  • [ ] An unauthorized connection to 10.29.2.2:9090 fails.
  • [ ] All three namespaces, veth devices, processes, and the isolated ruleset have been removed.
30Building an IllusionAdvanced

What you build

> Exercise for Chapter 30 — Namespaces: The Kernel's Illusions of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • create user, PID, network, UTS, and mount namespaces together without administrative privileges;
  • compare the PIDs, hostname, and network seen from the host with the view inside an isolated shell;
  • enter a process's namespaces from the outside with nsenter;
  • interpret the mapping that makes a user root in a namespace without granting root privileges on the host.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap30/solution
./run.sh

Expected result

  • [ ] The shell uses user, PID, network, UTS, and mount namespaces together with private propagation.
  • [ ] The internal PID, hostname, and network namespace differ from the values observed on the host.
  • [ ] nsenter starts a process from the outside that sees the same isolated view.
  • [ ] /proc/self/uid_map proves that internal root maps to the unprivileged host UID.
  • [ ] The isolated network contains only loopback and the shell cannot see host processes.
  • [ ] All temporary processes and resources have been removed.
31Setting a CeilingAdvanced

What you build

> Exercise for Chapter 31 — Cgroups v2: Accounting and Limits of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • create cgroup v2 subgroups only inside a delegated user scope;
  • restrict a workload to half a CPU and read throttling data from cpu.stat;
  • confine a memory allocator and observe an OOM kill limited to its group;
  • compare the recoverable pressure created by memory.high with the hard boundary enforced by memory.max.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap31/solution
./run.sh

Expected result

  • [ ] Every lab cgroup is a child of an explicitly delegated user scope.
  • [ ] cpu.max represents half a CPU and cpu.stat reports at least one throttling event.
  • [ ] The same 72 MiB workload survives memory.high but is killed by memory.max.
  • [ ] memory.events reports an increase in high for the first case and oom_kill for the second.
  • [ ] The control process remains outside the limited cgroups.
  • [ ] Every workload is time-bounded and all temporary cgroups and processes are removed.
32Your Container, from the First LineAdvanced

What you build

> Exercise for Chapter 32 — A Container by Hand, Without Docker of the > *Linux Manual* (Calm ICT series — [calmict.com](https://calmict.com)).

Objectives

  • build a base filesystem in a temporary directory;
  • combine user, PID, network, UTS, mount, and IPC namespaces without host privileges;
  • replace the root with pivot_root and mount proc only inside the new root;
  • enforce CPU and memory limits through a delegated cgroup v2 subgroup;
  • connect the container to an isolated host side with a veth pair;
  • trigger bounded CPU saturation and an OOM event while proving that host processes remain invisible.

How to test it

Fill in the TODOs in the starter files, then run the solution's test:

cd linux/ed1/cap32/solution
./run.sh

Expected result

  • [ ] The filesystem was built in a temporary directory and pivot_root made the old root unreachable.
  • [ ] The container uses every required namespace and proc was mounted only after pivot_root.
  • [ ] The labcap32-host and labcap32-guest pair connects the container to the isolated host side without changing the real network.
  • [ ] The host sentinel process is not visible from the container.
  • [ ] cpu.stat reports throttling and memory.events reports an OOM kill in the limited cgroup.
  • [ ] Every workload is short and bounded; no process, cgroup, mount, interface, or temporary file remains afterward.