Landlock Convert Example
The convert
tool reads from an input file (by default stdin),
converts the data into a different format,
and writes the result to an output file (by default stdout).
Analysis
Risk: The main complexity in this kind of tool is that it might use large libraries for processing file formats. Such libraries, particularly for media processing, often have performance as a primary goal, which can be at odds with secure coding conventions. The size of these libraries can make it more difficult to assess whether they are safe.
(For our example code, we won’t use an actual media processing library though.)
Untrusted input: A media conversion tool might be run with input files from untrusted sources. (In fact, the sanitization of untrusted input is a common use case for such tools.)
Trusted input: The flags provided to the tool are assumed to be safe.
Conclusion: The convert tool is written with Landlock ABI version 3 in mind. Just before starting to process the input to be converted, it will restrict itself so that it can’t open new files from the file system.
Implementation
Let’s break down the main()
function:
💚 Initialization phase
In the initialization phase of main()
, we parse the command line flags and care about assigning infd
and outfd
to the right file descriptors. parse_flags()
interprets the explicit command line arguments for input and output files, opens them if needed, and stores the resulting file descriptors in infd
and outfd
.
int main(int argc, char *argv[]) {
/* Initialization phase: Parse flags. */
int infd = STDIN_FILENO;
int outfd = STDOUT_FILENO;
parse_flags(argc, argv, &infd, &outfd);
🛡️ Enabling the sandbox
After the initialization phase, everything is ready to process the input file. This is the time when we enable our sandbox and forbid further accesses to the file system.
Forbidding all further file accesses is a common case, so we use a helper function for it, which implements the LandlockRulesetEnforcement.
/* Enable the sandbox. */
if (promise_no_further_file_access() < 0)
err(1, "landlock");
The helper function promise_no_further_file_access()
enables the sandbox
so that no further files from the file system can be accessed
if they are not opened already.
It follows the general LandlockRulesetEnforcement scheme, with the following differences:
- In
struct landlock_ruleset_attr
, onlyhandled_fs_access
is populated, restricting the biggest set of access rights that are possible to restrict running on the current kernel. - No rules are added to the Landlock ruleset. (There are no exceptions.)
🔴 Process untrusted input
Now that the Landlock policy is enabled, we start processing the untrusted input from the input file.
While we have already opened the untrusted file during the initialization phase, we do not start reading from the untrusted file descriptor until we have sandboxed ourselves.
/* Start processing untrusted input: Convert. */
convert(infd, outfd);
}
And that’s it. The sandbox stays enabled until the program exits.