Skip to content

Commit 581f3fa

Browse files
authored
Revert the capability set, and say what isolated mode bounds (#85)
Enforcing what a child may reach from inside CPython does not work: an audit hook never sees a C extension, and the open event does not say which directory a relative path resolves against, so the containment could be walked around with documented calls. The tree returns to 5.0.0 and the guides say plainly that the child holds every authority the node's user holds, with the operating system mechanisms that do bound it.
1 parent 58f0d11 commit 581f3fa

20 files changed

Lines changed: 49 additions & 2409 deletions

‎CHANGELOG.md‎

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,5 @@
11
# Changelog
22

3-
## 5.1.0 (unreleased)
4-
5-
### Added
6-
7-
- **Capabilities for isolated children** - `py_context:new(#{mode => isolated,
8-
caps => ...})` names the directories, environment variables and network
9-
addresses a child may reach; anything not named is refused. Leaving a key
10-
out grants none of it, and omitting `caps` leaves existing behaviour
11-
unchanged. Paths are resolved a component at a time with `openat` and
12-
`O_NOFOLLOW` from the descriptor of the grant, so `..`, absolute paths,
13-
symlinks out of a grant and symlinked directory prefixes are all refused,
14-
and refusals are `PermissionError` rather than `FileNotFoundError` so they
15-
disclose nothing about what exists outside. Network rules name addresses
16-
and never host names, resolution is its own capability covering every
17-
resolver, and binding is checked against `listen` rather than `connect`.
18-
Process creation, `ctypes`, signals to another process and Unix-socket
19-
addresses are refused outright. The model and its vocabulary come from
20-
erlang_wasm's WASI implementation.
21-
22-
This is a cooperative policy over Python and not a boundary: it is built
23-
on a CPython audit hook, so it binds Python and not a C extension, and it
24-
covers only what CPython announces. `docs/capabilities.md` says what holds
25-
and what does not. Shared memory and capability sets do not combine yet,
26-
because a region reaches the child as a path.
27-
283
## 5.0.0 (2026-08-29)
294

305
### Added

‎README.md‎

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -622,21 +622,14 @@ When creating Python contexts, you can choose the execution mode:
622622
%% segfault only takes the child down, rlimits bound memory and CPU.
623623
{ok, Ctx} = py_context:new(#{mode => isolated, kill_after => 1000,
624624
rlimits => #{as => 512 * 1024 * 1024}}).
625-
626-
%% Name what the child may reach, and it reaches nothing else.
627-
{ok, Ctx} = py_context:new(#{mode => isolated,
628-
caps => #{dirs => [{"/srv/models", read}],
629-
net => #{connect => [{tcp, <<"10.0.0.0/8">>, 5432}]}}}).
630625
```
631626

632627
**Isolated mode** is the only mode with a hard bound: `py_context:interrupt/1`
633628
stops a blocking C call, and `SIGKILL` is the backstop. It costs a process per
634629
context (about 16 MB and 40 ms to start) and roughly twice the call latency.
635630
Bulk data crosses through shared memory (`py_shm`, with the optional
636-
[iommap](https://hex.pm/packages/iommap) dependency), and the `caps` option
637-
names the files, addresses and environment the child may reach, as a
638-
cooperative policy over Python rather than a kernel boundary. See
639-
[Isolated Contexts](docs/isolated.md) and [Capabilities](docs/capabilities.md).
631+
[iommap](https://hex.pm/packages/iommap) dependency). See
632+
[Isolated Contexts](docs/isolated.md).
640633

641634
**Worker mode is recommended** because it works with any Python version and automatically benefits from free-threaded Python (3.13t+) when available. Each context owns a dedicated pthread, providing stable thread affinity for libraries with thread-local state (numpy, torch, tensorflow).
642635

‎docs/capabilities.md‎

Lines changed: 0 additions & 238 deletions
This file was deleted.

‎docs/code-map.md‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ exercised by suites). Guides are in `docs/`, suites in `test/`. Start with
2929
| `py_channel`, `py_byte_channel` | Term and byte queues between Erlang and Python coroutines (NIF resources) | live | channel | `py_channel_SUITE`, `py_byte_channel_SUITE` |
3030
| `py_buffer` | Native streaming input buffer; shared variant delegates to `py_shm` | live | buffer, isolated | `py_buffer_SUITE`, `py_isolated_buffer_SUITE` |
3131
| `py_shm` | Shared memory regions over iommap and the ring behind shared buffers | live | isolated | `py_isolated_shm_SUITE` |
32-
| `py_caps` | The `caps' option: what an isolated child may reach, and its wire form | live | capabilities | `py_isolated_caps_SUITE` |
3332
| `py_import` | Registry of imports and `sys.path` entries applied to every interpreter | live | imports | `py_import_SUITE` |
3433
| `py_preload` | Code run once per interpreter at start | live | preload | `py_preload_SUITE` |
3534
| `py_state` | Shared key/value store visible from Python as `erlang.state_get/set/delete/keys` | live | README (shared state) | `py_state_SUITE` |
@@ -81,7 +80,6 @@ loop, channels and servers.
8180
| `_erlang_impl/_etf.py` | Pure-Python ETF codec with the `py_convert.c` mapping | isolated child |
8281
| `_erlang_impl/_isolated.py` | Child runtime: socket frames, reader thread, re-entrant main loop, interrupt signal, asyncio loop, the `erlang` shim | isolated child |
8382
| `_erlang_impl/_shm.py` | `SharedMemory` and `SharedBuffer` wrappers over mmap | all |
84-
| `_erlang_impl/_caps.py` | Capability enforcement in the child: path containment, address matching, the audit hook | isolated child |
8583
| `py_isolated_child.py` | Child launcher: rlimits, parent-death signal, cgroup join, connect | isolated child |
8684
| `test_erlang_loop.py`, `test_async_task.py`, `test_channel_ref.py`, `tests/` | Python-side tests of the loop, tasks and channels | test |
8785

0 commit comments

Comments
 (0)