System Programming for Linux Containers course outline
- Course Introduction
- Fundamental Concepts
- Process vs kernel: different views of the world
- System calls and library functions
- Error handling
- System data types
- Notes on code examples
- File I/O and Files
- File I/O overview
- open(), read(), write(), and close()
- The file offset and lseek()
- Relationship between file descriptors and open files
- Duplicating file descriptors
- File status flags (and fcntl())
- Retrieving file information: stat()
- Processes
- Process IDs
- Process memory layout
- Process credentials
- The
/proc
filesystem
- Signals: Introduction
- Overview of signals
- Signal dispositions
- Signal handlers
- Useful signal-related functions
- Signal sets, the signal mask, and pending signals
- Designing signal handlers
- Signals: Signal Handlers (*)
- Reentrant and async-signal-safe functions
- Interruption and restarting of system calls
SA_SIGINFO
signal handlers
- The signal trampoline
- Process Lifecycle
- Introduction
- Creating a new process: fork()
- Process termination
- Monitoring child processes
- Orphans and zombies
- The
SIGCHLD
signal
- Executing programs: execve()
- System Call Tracing: strace (*)
- Tracing child processes
- Filtering strace output
- Further strace options
- Security and Isolation APIs Overview (*)
- Privileged Programs
- Process credentials
- Set-user-ID and set-group-ID programs
- Changing process credentials
- A few guidelines for writing privileged programs
- Capabilities
- Process and file capabilities
- Setting and viewing file capabilities
- Text form capabilities
- Capabilities and execve(); further capability sets
- Ambient capabilities
- Capabilities: Further Topics (*)
- Root, UID transitions, and capabilities
- Making a capabilities-only environment: securebits
- Programming with capabilities
- Namespaces
- Namespace types
- Mount namespaces
- UTS, IPC, cgroup, and network namespaces
- PID namespaces
- Namespaces APIs
- API Overview
- Creating a child process in a new namespace: clone()
/proc/PID/ns
- Entering a namespace: setns()
- Creating a namespace: unshare()
- PID namespaces idiosyncrasies
- ioctl() operations
- Namespace lifetime
- User Namespaces
- Overview of user namespaces
- Creating and joining a user NS
- User namespaces: UID and GID mappings
- User namespaces, execve(), and user ID 0
- Security issues
- Use cases
- Combining user namespaces with other namespaces
- User Namespaces and Capabilities
- User namespaces and capabilities
- What does it mean to be superuser in a namespace?
- User namespace "set-UID-root" programs(*)
- Namespaced file capabilities (*)
- Mount Namespaces and Shared Subtrees (*)
- Mount namespaces
- Shared subtrees
- Bind mounts
- Peer groups
- Private mounts
- Slave mounts
- Unbindable mounts
- Seccomp
- Introduction and history
- Seccomp filtering and BPF
- The BPF virtual machine and BPF instructions
- Checking the architecture
- BPF filter return values
- BPF programs
- Discovering the system calls made by a program
- Audit logging of filter actions
- Caveats
- Productivity aids (libseccomp and other tools)
- Cgroups
- Introduction to cgroups v1 and v2
- Cgroups v1: hierarchies and controllers
- Cgroups v1: populating a cgroup
- Cgroups v1: release notification
- Cgroups v1: a survey of the controllers
- Cgroups
/proc
files
- Cgroups Version 2
- Problems with cgroups v1; rationale for v2
- Cgroups v2 controllers
- Enabling and disabling controllers
- Organizing cgroups and processes
- Release notification (
cgroup.events
file)
- Delegation
- Cgroups v2 Thread Mode (*)
- Overview of thread mode
- Creating and using a threaded subtree
(*) Topics marked with an asterisk will be covered subject to time
constraints.