fix: bound filesystem execution and preserve guarantees

This commit is contained in:
2026-09-30 09:09:09 +09:00
parent df51da3d03
commit f5034c0e4b
5 changed files with 263 additions and 56 deletions
+10 -4
View File
@@ -8,14 +8,19 @@ envelopes, batching, and HTTP status mapping.
## Security model
- The effective root is opened once as a directory capability. Every request is
resolved segment-by-segment with directory-relative, `O_NOFOLLOW` handles.
- The effective root is opened once as a directory capability. Root path
components must be real directories (symlink components are rejected), and the
displayed effective root is read back from that same pinned descriptor. Every
request is resolved segment-by-segment with directory-relative, `O_NOFOLLOW`
handles.
- Symlinks are projected as links and are never followed. Their stored target is
available only through the `SymlinkInspect.read_link` application operation.
- Regular files, directories, symlinks, and unsupported entry types have distinct
public descriptions and capability sets.
- WIP names are Unicode. Linux names that are not valid UTF-8 are deliberately
not published; valid UTF-8 names map byte-for-byte and therefore cannot collide.
Unicode paths containing backend-invalid NUL bytes are likewise treated as
unpublished rather than as backend failures.
- No object `ref` is issued. This avoids claiming representation identity for
hard links or path-specific names. Regular files and symlinks receive an opaque
validator containing filesystem identity plus protected metadata; replacing a
@@ -122,8 +127,9 @@ standard `POST /wip/v1/batch` route. `call_operation` is never batchable.
`ResourceLimits` bounds request/response bytes, JSON nesting, batch items, file
read/write bytes, tree depth/node count, pinned handles, concurrent requests, and
a cooperative deadline. Tree traversal is breadth-first and opens only requested
entries. Once a limit or depth boundary is reached it reads only far enough to
a cooperative deadline. Advisory file-lock acquisition uses a nonblocking loop and
checks that deadline/cancellation rather than allowing a contended lock to stall
a worker. Tree traversal is breadth-first and opens only requested entries. Once a limit or depth boundary is reached it reads only far enough to
prove whether an additional visible child exists, so `truncated` is true only
when something was actually omitted. I/O failure and cancellation remain errors,
not clean exhaustion.