Landlocked Eio [weekly-2026-w16]
- April 18, 2026
- Patrick Ferris
I spent the start of last week wrapping up the "local" CI I mentioned the previous week. Unfortunately it was mostly a packaging nightmare, followed by missing features in ocaml-ci-local. It would be great to have a richer CLI tool for running tests on a directory of git repositories, but unfortunately most of the existing tooling has prioritised the Github/Gitlab etc. APIs.
After coming across minimal during the week, I took it as an opportunity to learn a little more about Linux's Landlock mechanism.
Landlocked Eio [landlocked-eio]
- April 18, 2026
- Patrick Ferris
Landlock is a sandboxing mechanism that has existed in the Linux kernel since 5.13. It allows unprivileged processes a means to restrict their ambient rights (e.g. creating a file or opening a network connection). These rights are ambient in the ambient authority sense, i.e., any process can attempt to perform an action without needing access to any particular capability to do so.
Ambient systems are often contrasted with capability-based ones. In terms of operating systems, this is most commonly illustrated with access-control-lists-as-columns and capabilities-as-rows in an access matrix.
Eio is a capability-based library in OCaml -- resources are provided at the start of the application and can be passed around wherever they are needed. The design is covered in Thomas Leonard's lambda capabilities blog post. Unfortunately, any application (willingly or via a third-party library) may ambiently access OS resources. In OCaml, this may be by using the standard library functions (e.g. Sys.readdir), things from the Unix module, a C FFI function or by spawning a subprocess.
I had a go at "landlocking" Eio applications last week after stumbling across minimal's hakoniwa library for process isolation (which is very reminiscent of void processes).
module Landlock = Eio_linux.Landlock
let ( / ) = Eio.Path.( / )
let run_eio file =
Eio.traceln "Writing to file";
Eio.Path.save ~create:(`Exclusive 0o644) file "hello, world!";
Eio.traceln "Reading file: %s" (Eio.Path.load file);
Eio.Path.unlink file
let bad_program () =
In_channel.with_open_bin "/etc/passwd" In_channel.input_all
|> Eio.traceln "/etc/passwd: %s"
let () =
Eio_linux.run @@ fun env ->
Eio.Path.with_open_dir (Eio.Stdenv.cwd env / ".") @@ fun dir ->
let parent_fd =
Eio_unix.Resource.fd_opt (fst dir) |> Option.get
in
let file = dir / "hello.txt" in
let rules =
Landlock.Rule.
[
path_beneath ~parent_fd
~flags:Flags.Fs.(
write_file + read_file + make_reg + remove_file
);
]
in
match Landlock.enter rules with
| Ok () ->
run_eio file;
bad_program ()
| Error `Not_supported -> Eio.traceln "Landlock not supported!"
Running this program (with the necessary privileges) prints the following.
+Writing to file
+Reading file: hello, world!
Fatal error: exception Sys_error("/etc/passwd: Permission denied")Eio already has a similar function for the BSDs using capsicum. In capsicum, processes enter a capability mode:
cap_enter()places the current process into capability mode, a mode of execution in which processes may only issue system calls operating on file descriptors or reading limited global system state.
This plays nicely with Eio's capabilities. Within the scope of Eio.Path.with_open_dir, the directory will remain usable after entering "cap" mode. This is not the case with landlock unless you add a specific path_beneath rule to the ruleset (like in the example above). However, you could imagine plumbing the necessary information throughout the Eio_linux backend for it to build a set of rules that can be applied at any given moment in order to mimic the capsicum semantics.
Self-hosting Music [self-host-music]
- April 18, 2026
- Patrick Ferris
After my friend, Greta, sent me some articles about music streaming services and their exploitation of artists, I decided enough was enough and setup navidrome. It is compatible with Subsonic and so far I'm very pleased to be streaming my own music to my devices. I am using substreamer on iOS. On my laptop, I tried out Andreas Rossberg's Camp
What you got here is an old-school music player heavily inspired by good old Winamp [1], with a focus on decent music library and playlist handling.
I took Anil's OCaml Installer tool for a spin with great success... after a few mishaps mostly related to system dependencies.
$ nix-shell -p pkg-config gcc pulseaudio miniaudio libxi libxrandr libxinerama libffi mesa libxcursor libGL $ oi-linux-x86_64 run --with=https://github.com/patricoferris/camp#nix -- camp
The fixes in my fork of Camp are just to install the assets using dune and also statically provide the -lpulse flag (which should probably be dynamically picked up). Otherwise, raylib or miniaudio selects the Null playback device. Roll-on cross-ecosystem package management.
