Skip to content

Grant an isolated child what it may reach - #84

Merged
benoitc merged 1 commit into
mainfrom
child-caps
Sep 1, 2026
Merged

Grant an isolated child what it may reach#84
benoitc merged 1 commit into
mainfrom
child-caps

Conversation

@benoitc

@benoitc benoitc commented Aug 31, 2026

Copy link
Copy Markdown
Owner

Isolated mode bounded what Python could consume: memory, CPU, time, a crash. It bounded nothing it could reach. The child ran as the node's user with the node's environment, could read and write every file that user could, dial anywhere, spawn processes, and truncate the shared memory regions it was handed, which turns the mapping the VM holds into a SIGBUS.

caps names what a child may reach and refuses the rest: directories with an access level, environment variables, network rules. Leaving a key out grants none of it, and omitting the option leaves today's behaviour alone.

{ok, Ctx} = py_context:new(#{
    mode => isolated,
    caps => #{dirs => [{"/srv/models", read}, {"/var/data/job42", write}],
              env  => #{<<"MODEL_DIR">> => <<"/srv/models">>},
              net  => #{connect => [{tcp, <<"10.0.0.0/8">>, {5432, 5432}}],
                        resolve => deny}}}).

The model, the option shape, the refusal semantics and the test list come from erlang_wasm's WASI implementation rather than being invented, so a grant means the same thing in both: rules name addresses and never host names, resolution is its own capability, binding is checked against listen and not connect, IPv4-mapped addresses are folded before matching, and a malformed rule is an error where the grant is written rather than a connection refused later. Path containment is that project's native backend, which needed a C NIF there because Erlang has no openat and needs none here because Python has one.

It is a policy over Python, not a kernel boundary, and the guide says so in those words: a C extension calling open(2) is not stopped, nor is a thread that swaps a path between the check and the kernel's resolution. Landlock takes the same table and is the next step.

Isolated mode bounded what Python could consume but nothing it could
reach: the child held every authority the node's user held. The caps
option names its directories, environment and addresses, and refuses
the rest. The model and its vocabulary come from erlang_wasm's WASI
implementation, so a grant means the same thing in both.

It is a cooperative policy over Python, not a boundary: built on an
audit hook, it binds Python and not a C extension, and covers only
what CPython announces. The guide says what holds and what does not,
and names the kernel work that would change the answer.
@benoitc
benoitc merged commit 58f0d11 into main Sep 1, 2026
20 checks passed
@benoitc
benoitc deleted the child-caps branch September 1, 2026 06:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant