Prompt and context
A command-line tool must read a small set of input files, write a designated output directory, and run untrusted plugins. The deployment cannot grant extra privileges, and the kernel may expose only an older Landlock ABI. How would you design the sandbox, verify that the rules work, and avoid treating a stricter rule set as proof that the whole system is safe?
This question fits Linux, security, build-system, and multi-tenant execution roles. The signal is understanding Landlock as an unprivileged, stackable process self-restriction mechanism, not memorizing one C structure.
What the interviewer is testing
- Whether you distinguish rule domains, rule types, access rights, and process scope.
- Whether you probe the kernel ABI before constructing the supported permission set.
- Whether you know that file descriptors opened before restriction need separate auditing.
- Whether you reason about fork, exec, threads, and child-process inheritance.
- Whether failure handling, observability, rollback, and tests are part of the rollout.
Questions to clarify first
- Which paths need read, create, delete, execute, and network capabilities?
- Can a plugin fork, exec, create threads, or receive inherited file descriptors?
- What is the minimum kernel version and the acceptable security downgrade?
- Are logs, input files, sockets, or devices opened before the process is restricted?
- Is file access the only boundary, or are seccomp, containers, or MAC also required?
Thirty-second answer
“I would probe the Landlock ABI first, create a rule domain, grant only read access to the input tree and create/write access to the output tree, then restrict the current process so descendants inherit the policy. File descriptors opened before restriction need an explicit audit because they may remain usable. I would build the smallest common permission set for older ABIs; if a mandatory isolation capability is unavailable, the tool refuses to run or enters a clearly logged low-risk read-only mode instead of silently running unsandboxed.”
Step-by-step deep dive
Step 1: Define the threat model and minimum rights
List what a plugin could do: read host files, overwrite output, execute another program, delete directories, access the network, or abuse inherited descriptors. Map each action to the filesystem rights Landlock supports. Grant only the required reads under the input tree and writes or creates under the output tree. Leave every ungranted right denied rather than opening the root and relying on application checks.
Step 2: Probe the ABI
Landlock adds access rights across ABI versions. At startup, read the available ABI and divide the desired policy into mandatory and optional rights. Add optional rights only when supported. An unknown right can make rule creation fail, so the policy builder must be capability-aware. Log the detected ABI, policy version, and effective rights as structured fields.
Step 3: Build the rule domain and bind paths
Create a rule domain, open trusted directory descriptors during startup, and bind path rules with the smallest rights needed for each tree. Opening those descriptors before plugin code runs prevents the policy setup from resolving attacker-controlled paths. After composing the rules, restrict the current process and test the inheritance behavior of threads and later exec calls.
Step 4: Audit open resources and inheritance
Landlock constrains later access requests; descriptors opened before restriction may still be usable. Close descriptors that are not needed, mark required ones as controlled resources, and prevent unrelated descriptors from being passed on. Review standard input and output, logs, sockets, directory handles, and descriptors supplied to plugins. Test fork, exec, threads, and children separately.
Step 5: Define failure and defense in depth
Landlock does not automatically constrain every system call, network operation, or capability already held by the process. Add seccomp, containers, user namespaces, or a system MAC when the threat model requires them. If the mandatory rule domain cannot be created, choose refusal, a read-only mode, or an approval gate. Every downgrade must emit an alert with its reason; it must never silently execute an untrusted plugin without the boundary.
Step 6: Verify, observe, and roll back
Use CI fixtures to cover an allow/deny matrix: input reads succeed, output writes succeed, reads outside the allowed trees fail, and delete or execute operations fail as designed. Repeat the checks in child processes. Record ABI, policy hash, denied-operation counts, and exit reasons. During a canary, measure false denials; when a plugin needs another right, update the allowlist and tests instead of opening its parent directory. A rollback can disable the plugin or restore an older runner while retaining the sandbox-failure alert.
High-quality sample answer
I would start with a permission inventory for the plugin’s file, execution, and inheritance needs, then probe the target kernel’s Landlock ABI. The rule domain grants input-tree reads and output-tree creates and writes; optional rights are enabled one by one, while a missing mandatory capability makes the run unavailable. Before restriction I close unnecessary descriptors and audit standard streams, logs, sockets, and plugin-provided descriptors, then verify fork, exec, thread, and child behavior.
After restricting the process, I would run an allow/deny matrix with the real plugin and record the ABI, policy version, denied operations, and downgrade reason. Landlock supplies a stackable filesystem boundary, not a complete privilege or network sandbox, so seccomp, containers, user namespaces, or MAC may still be needed. If the core policy cannot be established, the runner refuses or enters an explicitly alerted read-only mode; it never silently bypasses the policy.
Common mistakes
- Treating Landlock as privilege isolation → It mainly constrains later controlled accesses → combine controls according to the threat model.
- Ignoring ABI differences → New rights may be unknown on older kernels → probe and build the smallest common policy.
- Opening everything before sandboxing → Existing descriptors may remain usable → close, audit, and stop unrelated descriptor inheritance first.
- Allowing a parent tree and trusting application checks → A plugin can traverse more paths → grant rights per tree and per operation.
- Silently continuing after setup failure → Operators cannot see that isolation is missing → refuse, use read-only mode, or require approval with an alert.
- Testing only the main process → fork, exec, and threads change the boundary → test every inheritance path with deny cases.
Follow-up questions
Can Landlock restrict a file that was already opened?
It should not be treated as an automatic close mechanism. A descriptor opened before restriction may remain usable, so close unnecessary descriptors before applying the policy, control descriptor passing, and include retained handles in the audit and tests.
What if the kernel lacks one requested access right?
Separate mandatory from optional rights. Probe the ABI, add supported optional rights, and refuse startup or enter an explicitly alerted safe mode when a mandatory right is missing. Do not ignore a rule-creation failure or write unknown rights into the rule.
Why add seccomp or a container?
Landlock’s strength is unprivileged, filesystem-scoped self-restriction. It does not cover every system call, network path, or host policy. Seccomp, user namespaces, containers, and MAC can fill those call, identity, and system-level boundaries; the combined design still needs inheritance and failure-path tests.