Skip to main content

Exposing a listener

Simple Story

The work answers the door.

Phobos decides which socket in the wall the work may plug into, and puts a doorkeeper in front of it. Who can reach the door at all is the building's business.

The situation​

The command starts a server that something outside has to reach: a web service under test, a protocol implementation, a task that is graded by talking to it.

The policy fragment​

exercise.cfg
[bind]
allow 8080

[accept]
expose 18080 to 8080 from 198.51.100.0/24

Two ports, with different jobs. 8080 is the command's own listening port, and Landlock refuses it a listener on any other, unless the base policy names port 0, as the shipped Java policy does. 18080 is the port the container exposes, which the inbound filter binds and which the command may not bind itself.

What this still forbids​

  • a listener on any port [bind] does not name, refused in the kernel and against raw system calls, and a listen() on a socket that never bound, which the connect guard refuses
  • an inbound connection from any source outside 198.51.100.0/24
  • an outbound connection, unless [connect] names one
  • a datagram listener, which needs allow 5353 udp and Landlock version 10

The tempting wrong version​

wrong.cfg
[bind]
allow 8080

[accept]
expose 8080 to 8080 from 198.51.100.0/24

Fronting a port the command can itself bind lets it compete with the filter for that port and receive connections the filter was meant to screen. Phobos refuses this with PHB-EPOLICY.

Three more are refused for related reasons: a public port below 1024, which cannot be bound without a capability the run does not have; a backend port [bind] does not name, which would leave the filter forwarding to a listener that never comes up; and two rules fronting one public port with different backends.

A fourth passes and serves nobody:

also-wrong.cfg
[bind]
allow 8080

[accept]
expose 18080 to 8080 from

A rule with no source admits nobody. That is the fail-closed direction, and Phobos warns that the service is unreachable rather than failing. The literal word from stays even where no source follows it; a line without it is not an [accept] rule at all.

Notes​

warning
An [accept] rule changes the run's posture

It removes --network none, because an external client cannot reach a container that has no network. Phobos locks the listening port, and the connect guard keeps the listener on loopback. Landlock's bind right is per port rather than per address, so the command may bind its backend port on every interface. The guard pins every listener to the loopback device, so only this host reaches the backend, through the filter. The container publishes the public port and nothing else. A source address is a filter, never an identity.

  • A [bind] rule takes a bare port. A rule that names an address is refused, because Landlock cannot narrow a bind to a local address.
  • With --no-networksystem-restriction, the [accept] rule starts no filter and the port is not locked either. phobos.sh reports that rather than leaving it silent.