Module 5 · Unit 12 · Laboratory 11
Security and Protection
This laboratory examines how the operating system
protects the resources it manages. You will inspect
Linux's authentication and authorization mechanisms,
apply the standard access-control models (DAC, MAC,
RBAC), demonstrate privilege escalation through a
misconfigured setuid binary, sandbox a process with
namespaces and seccomp, and harden a system using
the standard tools (SELinux/AppArmor, capability
bounding, systemd restrictions). The
laboratory closes by reasoning about the
principle of least privilege and its practical
limits.
01 Lab overview
| Course | COMP 3150 / CMIS 3150 — Operating Systems |
|---|---|
| Unit | Unit 12 — Security and Protection |
| Weight | 1.25% of the final grade (1/12 of the 15% laboratory component) |
| Estimated duration | 4–5 hours of hands-on work |
| Submission | One archive containing the C source files, the shell scripts, the Makefile, the output logs, and a short lab report (see § 06) |
| Environment | Linux VM, gcc, make, strace, sudo, setcap, unshare, systemd (for unit restrictions), optional firejail or bubblewrap |
This lab contributes to U12.1 through U12.7, and to course learning outcomes CLO6, CLO7, and CLO8.
02 Learning objectives
By the end of this laboratory you will be able to
- Explain the classic security goals — confidentiality, integrity, availability — and the principle of least privilege.
- Describe Linux authentication (PAM, shadow password file, hashing) and apply a simple password policy.
- Explain the difference between authentication and authorization, and apply discretionary access control (DAC) using file permissions and ACLs.
- Describe mandatory access control (MAC) with SELinux/AppArmor, and role-based access control (RBAC) with
sudopolicies. - Demonstrate a privilege escalation through a setuid binary and explain why
setuidis dangerous. - Sandbox a process with namespaces, seccomp, and
systemdrestrictions. - Harden a Linux system: disable unused services, restrict capabilities, enable auditing.
03 Background
3.1 Security goals and the threat model
The classical CIA triad defines three security goals: confidentiality (data is not disclosed to unauthorised parties), integrity (data is not modified without authorisation), and availability (data and services are accessible when needed). A threat model describes the adversary: what the adversary can do, what they cannot do, and what they are trying to achieve. Every security mechanism is designed against a threat model; a mechanism that is secure against one adversary may be useless against another.
3.2 Authentication
Authentication answers the question
"who are you?". Linux supports three classes:
something you know (password), something you have
(a security token), something you are (biometrics).
The password database is /etc/passwd
(world-readable) for the account records, and
/etc/shadow (root-readable only) for
the password hashes. Hashes use a modern algorithm
such as SHA-512 with a salt; the salt prevents
precomputed rainbow tables and identical passwords
produce different hashes. Pluggable Authentication
Modules (PAM) allow the authentication mechanism
to be changed per service without modifying the
applications.
3.3 Authorization and access control
Authorization answers "what are you allowed to do?".
- Discretionary access control (DAC). The owner of a resource decides who can access it. Linux's classic mode bits (
rwxfor owner, group, and others) and POSIX ACLs are DAC. - Mandatory access control (MAC). The system enforces a global policy that even the owner cannot override. SELinux and AppArmor are MAC systems: each process and each object has a label, and the policy defines which labels may interact.
- Role-based access control (RBAC). Permissions are assigned to roles, and users are assigned to roles.
sudois a form of RBAC:/etc/sudoersdefines which users may run which commands as which other users.
3.4 Privilege escalation
Privilege escalation is any
mechanism by which a process gains more privileges
than it should have. The classic vector is a
setuid binary: a program owned by
root and marked setuid runs with root's effective
UID, regardless of who invokes it. If the program
is poorly written — for example, it invokes another
program without resetting its environment, or it
writes to a file whose path is controlled by the
caller — an attacker can leverage the setuid
binary to run arbitrary commands as root. Modern
Linux mitigates this with
capabilities: instead of granting
all of root's privileges, a setuid binary can be
granted only the specific capabilities it needs
(for example, CAP_NET_BIND_SERVICE
to bind a low port). The rest of root's privileges
are not available.
3.5 Sandboxing
A sandbox isolates a process so that even if it is compromised, it cannot affect the rest of the system. Linux provides several mechanisms:
- Namespaces: a process can have its own view of the file system (mount namespace), process IDs (PID namespace), network (network namespace), user IDs (user namespace), and so on. Containers are built on namespaces.
- seccomp: a filter that restricts which system calls the process may make. A compromised process cannot invoke a system call that the filter denies.
- cgroups: resource limits on CPU, memory, I/O, and device access.
- AppArmor / SELinux: MAC policies that restrict what files, network ports, and other resources the process may access.
3.6 Hardening
Hardening is the process of reducing a system's attack surface. Standard measures: disable unused services, apply the principle of least privilege to every process, restrict capabilities, enable auditing, keep the system patched, and enable MAC policies in enforcing mode. The goal is not to make a system impenetrable — that is impossible — but to make a successful attack require more effort and to limit the damage that a successful attack can do.
04 Guided activities
Activity 4.1 — Authentication and the shadow file
- Create the lab directory:
mkdir -p ~/comp3150/lab11 && cd ~/comp3150/lab11 - Inspect
/etc/passwdand/etc/shadow. In the passwd file, identify the fields: username, password placeholder, UID, GID, GECOS, home directory, login shell. In the shadow file (withsudo), identify the fields: username, hashed password, last change, minimum age, maximum age, warning period, inactivity, expiry. - Create a test user with
sudo useradd -m testuserand set a password withsudo passwd testuser. Inspect the new entries in both files. - Verify that the hash in
/etc/shadowis salted and hashed: runsudo cat /etc/shadow | grep testuserand identify the algorithm identifier ($6$for SHA-512), the salt, and the hash. Change the password to the same value and verify that the hash is different (a new salt was chosen). - Configure a password policy in
/etc/security/pwquality.conf: minimum length 12, at least one digit, at least one uppercase. Attempt to change the password to a weak one and observe the rejection.
Activity 4.2 — Authorization with DAC and ACLs
- Create a file
secret.txtwithecho "top secret" > secret.txt. Set its mode to600withchmod 600 secret.txt. Verify withls -landstat. - As
testuser(usesu - testuserorsudo -u testuser cat secret.txt), attempt to read the file. Observe the permission denied error. - Grant
testuserread access with a POSIX ACL:
Verify thatsudo setfacl -m u:testuser:r secret.txt getfacl secret.txttestusercan now read the file, and thatls -lshows a+after the mode bits indicating an ACL is present. - Set the default ACL on a directory so that all new files inherit the permission:
Create a file in the directory and verify the inherited ACL.sudo setfacl -d -m u:testuser:r somedir/ - Remove the ACL with
setfacl -x u:testuser secret.txt. Verify thattestusercan no longer read the file. Explain the difference between the mode bits and the ACL: the mode bits grant permissions to one owner, one group, and everyone else; the ACL allows arbitrary users and groups to be granted specific permissions.
Activity 4.3 — Privilege escalation with setuid
- Write a program
vuln.cthat runs with setuid root and reads a file whose path is supplied on the command line:#include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "usage: %s <file>\n", argv[0]); return 1; } FILE *f = fopen(argv[1], "r"); if (!f) { perror("fopen"); return 1; } char buf[256]; while (fgets(buf, sizeof buf, f)) fputs(buf, stdout); fclose(f); return 0; } - Compile it, change its owner to root, and set the setuid bit:
gcc -o vuln vuln.c sudo chown root:root vuln sudo chmod 4755 vuln ls -l vuln - As
testuser, run./vuln /etc/shadow. The program reads the shadow file even thoughtestuserdoes not have permission — because the process's effective UID is root, not testuser. This is the intended use of setuid: the program is trusted to decide which files to read. - Now modify the program to invoke a shell command using
system():
Compile, mark setuid root, and assystem(argv[1]);testuserrun./vuln "/bin/sh". You get a root shell. This is a classic setuid vulnerability: the program trusts its caller to supply a safe command. Explain why usingsystem()orexeclp()in a setuid program is dangerous, and how to avoid it (drop privileges before invoking external programs, or useexecvewith a full path and a sanitised environment). - Remove the setuid bit and demonstrate that the same command now fails. Explain the mitigation with capabilities: instead of setuid root, use
setcap cap_dac_read_search+ep ./vulnto grant only the capability to bypass file read permissions.
Activity 4.4 — Sandboxing a process
- Run a simple command in a new set of namespaces:
Inside the new shell, runsudo unshare --mount --uts --ipc --pid --fork --mount-proc /bin/bashps auxand observe that only a few processes are visible (the PID namespace is isolated). Runhostname newhostand observe that the hostname change does not affect the outer system (the UTS namespace is isolated). - Use
seccompto restrict a process to a small set of system calls. Write a C program that installs a seccomp filter allowing onlyread,write,exit, andexit_group, then attempts to open a file. The program should be killed bySIGSYSwhen it tries the denied call. - Use
systemd-runto launch a process with resource and access restrictions:
Inside the unit, attempt to read files insudo systemd-run --unit=locked --property=ProtectHome=yes \ --property=ProtectSystem=strict --property=NoNewPrivileges=yes \ --property=PrivateTmp=yes /bin/bash/homeand/root, and observe the denials. - If
firejailorbubblewrapis available, use it to run a browser or a text editor in a sandbox. Inspect the sandbox's mount namespace withls /proc/<pid>/ns/and compare it to the outer system's.
Activity 4.5 — Hardening a Linux system
- List the services that are enabled at boot:
For each service, decide whether it is necessary. Disable a service you do not need:systemctl list-unit-files --state=enabledsudo systemctl disable --now <service> - Check the capabilities of the setuid binaries on the system:
For each one, verify that it is necessary and that it has been updated with the latest security patches. Remove the setuid bit from any that are not needed.find / -perm -4000 -type f 2>/dev/null | xargs ls -l - Enable a MAC policy. If your system uses AppArmor:
If it uses SELinux:sudo aa-status sudo systemctl enable --now apparmor
Verify that the policy is in enforcing mode and that a test program is denied access to a resource it would otherwise reach.getenforce sudo setenforce 1 - Enable auditing for sensitive operations:
Modifysudo systemctl enable --now auditd sudo auditctl -w /etc/passwd -p wa -k passwd_changes sudo auditctl -w /etc/shadow -p wa -k shadow_changes/etc/passwd(for example, change a user's shell) and inspect the audit log withsudo ausearch -k passwd_changes. - Configure a minimal
sudoersentry that allows a user to run only one specific command as root, and verify that other commands are denied:
Fromtestuser ALL=(root) NOPASSWD: /usr/bin/systemctl restart nginxtestuser, run the permitted command and observe success; run a different command and observe denial.
05 Exercises
- Password strength checker. Write a program that implements a simple password policy: minimum length, character classes, no dictionary words. Test it on a set of passwords, including some common weak ones. Explain why length is a more important factor than complexity in resisting offline attacks.
-
RBAC with sudo.
Design a
sudoerspolicy for a small team: an operator role that can restart services, an admin role that can manage users, and an auditor role that can read the audit log. Write thesudoersfile, test each role with a separate account, and verify that each role can do exactly what it should — no more, no less. -
TOCTOU vulnerability.
Write a program that checks a file's
permissions with
access()and then opens it withfopen(). Then write an attacker that swaps the file between the check and the open (a time-of-check to time-of-use or TOCTOU race). Demonstrate the vulnerability by running the attacker while the check-then-open program runs in a loop. Explain how to fix it (useopenwithO_NOFOLLOWand check the opened file descriptor, not the path). -
Capabilities.
Take a program that needs one specific
privileged operation — for example, binding a
low-numbered port, or reading a file that
requires root — and grant it only the
necessary capability with
setcap. Verify that the program works and that it cannot perform other privileged operations. Explain why capabilities are strictly better than setuid root. -
Container isolation.
Build a minimal container with
unshareandchroot: start a shell in a new mount, PID, and network namespace, with its own root file system. From inside the container, attempt to see the host's processes, read the host's files, and connect to the host's network. Verify that each attempt fails. Explain which namespace enforces which isolation. -
Audit analysis.
Enable auditing for a set of sensitive files
and a set of sensitive system calls
(
execve,openwithO_WRONLY). Run a scripted workload and analyse the audit log withausearchandaureport. Produce a summary of what happened and describe how an administrator would use the log to investigate an incident. - Hardening checklist. Produce a hardening checklist for a Linux web server. Include at least 20 items across the categories of authentication, authorization, network exposure, process isolation, logging, and patch management. For each item, give the command or configuration that implements it and one sentence explaining the threat it mitigates.
06 Deliverables
Submit a single archive named
lab11-<lastname>-<studentnumber>.tar.gz
containing:
vuln.candvuln_fixed.c— Activity 4.3.seccomp_test.c— Activity 4.4.password_policy.c— Exercise 1.toctou.candtoctou_attack.sh— Exercise 3.sudoers.example— Exercise 2.container.sh— Exercise 5.hardening.md— Exercise 7.outputs.txt— the output logs of all commands with the commands that produced them.report.md(orreport.pdf) — the lab report described below.
Lab report
The report should be 5–7 pages (excluding code) and contain:
-
Authentication.
The
/etc/passwdand/etc/shadowentries for your test user, with the hash fields annotated. The password policy configuration and the demonstration of a rejected weak password. -
Authorization.
The DAC and ACL demonstrations, with the
ls -landgetfacloutput for each step, and an explanation of when to use ACLs in preference to mode bits. -
Privilege escalation.
The
vuln.cprogram, the root shell demonstration, and the mitigation. A clear explanation of why setuid programs must not invoke external commands with a sanitised environment, and how capabilities improve on setuid root. -
Sandboxing.
The namespace demonstrations, the seccomp
filter, and the
systemdrestrictions. A table listing each isolation mechanism and the resources it protects. - Hardening. The list of services you disabled, the setuid binaries you removed or verified, the MAC policy you enabled, the audit rules you configured, and the RBAC policy you wrote.
- Reflection. A discussion of the principle of least privilege and its practical limits: why most real systems grant more privilege than strictly necessary, what the trade-off is, and how modern sandboxing and capability mechanisms try to reduce the gap between the privilege a process has and the privilege it needs.
07 Grading rubric
| Criterion | Points | CLOs | Exemplary (90–100%) | Proficient (80–89%) | Developing (70–79%) |
|---|---|---|---|---|---|
| Authentication and authorization | 20 | CLO7 | All fields of passwd and shadow interpreted correctly; DAC and ACL demonstrations complete. | Most fields interpreted; demonstrations mostly complete. | Fields or demonstrations incomplete. |
| Privilege escalation | 20 | CLO6, CLO7 | Setuid escalation demonstrated and explained; mitigation with capabilities demonstrated. | Demonstration complete; mitigation explained briefly. | Demonstration incomplete or mitigation missing. |
| Sandboxing | 20 | CLO7, CLO8 | Namespaces, seccomp, and systemd restrictions all demonstrated and correctly mapped to the resources they protect. | Most mechanisms demonstrated; mapping partial. | Mechanisms missing or demonstration incomplete. |
| Hardening | 25 | CLO7, CLO8 | Services disabled, setuid binaries audited, MAC enabled, auditing configured, RBAC policy written and tested. | Most hardening steps completed; testing partial. | Hardening steps incomplete or untested. |
| Report quality | 15 | CLO7, CLO8 | Report is evidence-based, well-structured, and reflective. | Report is clear; some claims unsupported. | Report is disorganised or inaccurate. |
Late submission penalty: 10% per day, up to a maximum of three days, after which the lab is accepted only with documented extenuating circumstances.
08 Knowledge check
Check your understanding
Question 1
What are the three goals of the CIA triad, and what is the principle of least privilege?
Show answer
CAP_NET_BIND_SERVICE capability is
compromised, the attacker cannot read arbitrary
files or modify the kernel, because those
capabilities are not held. Least privilege is
the guiding principle behind capabilities,
sandboxing, and role-based access control.
Question 2
Explain the difference between authentication and authorization, and give an example of each in Linux.
Show answer
sudo; the password is checked
against the hash in /etc/shadow.
Authorization answers "what are
you allowed to do?" — it determines the actions
the authenticated identity may perform. In
Linux, authorization is performed by the file
permission system (mode bits and ACLs), by the
sudoers policy, and by MAC systems
like SELinux and AppArmor. A user can be
authenticated successfully and still be denied
authorization to perform a specific action.
Question 3
Why is a setuid root binary dangerous? Describe a concrete attack and the mitigation.
Show answer
system(argv[1]) or
execlp("sh", "sh", NULL). The
attacker runs the program with an argument that
spawns a shell, and gets a root shell. The
attack exploits the program's trust that its
input is safe.
Mitigation: do not use setuid root. Use
capabilities instead: grant the binary only
the specific capability it needs (for example,
CAP_NET_BIND_SERVICE to bind a low
port). If a setuid binary is unavoidable, drop
privileges as soon as they are no longer needed
(with setresuid or
setresgid), use only absolute paths
for external programs, and sanitise the
environment (clear PATH,
IFS, LD_PRELOAD).
Question 4
Compare DAC, MAC, and RBAC. Give an example of each in Linux.
Show answer
chmod
it to grant or deny access to any user.
MAC (mandatory access control):
the system enforces a global policy that even
the owner cannot override. Linux examples:
SELinux and AppArmor. A process labelled
httpd_t cannot read a file labelled
shadow_t even if the file's owner
grants permission, because the MAC policy
forbids it. RBAC (role-based access
control): permissions are assigned to
roles, and users are assigned to roles. Linux
example: sudo. The
/etc/sudoers file defines which
users (or groups) may run which commands as
which other users; a user in the
webadmin group might be allowed to
restart nginx but nothing else.
Question 5
What is a sandbox, and what mechanisms does Linux provide for sandboxing?
Show answer
- Namespaces: a process can have its own view of the file system (mount namespace), process IDs (PID namespace), network (network namespace), user and group IDs (user namespace), hostname (UTS namespace), and IPC resources (IPC namespace). Containers are built on namespaces.
- seccomp: a filter that restricts which system calls the process may make. A denied call causes the process to be killed with
SIGSYS. - cgroups: resource limits on CPU, memory, I/O, and device access.
- MAC policies (SELinux, AppArmor): restrict what files, network ports, and other resources the process may access, regardless of DAC permissions.
- Capability bounding: restrict the capabilities a process can ever acquire.
09 References
- Silberschatz, A., Galvin, P. B., & Gagne, G. Operating System Concepts, 10th ed., Chapter 16.
- Tanenbaum, A. S., & Bos, H. Modern Operating Systems, 4th ed., Chapter 9.
- Saltzer, J. H., & Schroeder, M. D. The Protection of Information in Computer Systems. Proceedings of the IEEE, 1975.
- Anderson, J. P. Computer Security Technology Planning Study. USAF Electronic Systems Division, 1972 (the origin of the reference monitor concept).
- Smalley, S., Vance, C., & Salamon, W. Implementing SELinux as a Linux Security Module. NSA Technical Report, 2001.
- Bauer, M. Paranoid Penguin: Linux Security. Linux Journal (multiple articles).
- Linux man-pages:
man 5 passwd,man 5 shadow,man 5 sudoers,man 7 capabilities,man 2 seccomp,man 7 namespaces,man 8 setfacl,man 8 setcap. - Linux kernel documentation:
Documentation/admin-guide/LSM/,Documentation/userspace-api/seccomp_filter.rst.