You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

7.7 KiB

G-003 Configurable resource limits and sandboxing on subshell interps

Status: proposed Scope: src/modules/punk/repl-999999.0a1.0.tm, src/modules/punk/repl/codethread-999999.0a1.0.tm Goal: a subshell's code interp can be launched with configurable resource limits (command-count, time) and sandboxing features, building on the resolved first-subshell asymmetry from G-002. Acceptance: a subshell can be launched with at least one resource limit (command-count via interp limit -command, or time via interp limit -time) and one sandboxing feature (e.g. interp hide of a command, or full safe-interp restrictions) applied to its code interp, enforceable regardless of subshell nesting depth; a subshell can be configured anywhere on the spectrum from unrestricted to fully safe via expose/hide of commands; the existing default subshell behaviour (no limits, no extra sandbox beyond the existing safe/safebase/punksafe types) is preserved when no limits are configured.

Context

The subshell's user code runs in a child Tcl interpreter named code (created in repl::init at src/modules/punk/repl-999999.0a1.0.tm:3575-3620). The existing TODO at repl:3130-3132 is explicit that resolving the "first subshell asymmetry" is a prerequisite for this goal:

"This will be important later for us to control aspects of the code interp such as cpu/memory resource limits and sandboxing."

Tcl provides the primitives this goal needs:

  • Resource limits: interp limit supports two dimensions — command-count (-command, restricts the total number of Tcl commands that may be executed in the interp) and time (-seconds/-millis). Both are nestable per-interp. These are the only interp-level resource limits Tcl exposes; this goal covers exactly those two.
  • Sandboxing spectrum: Tcl supports a continuum from unrestricted to fully sandboxed via interp hide/interp expose/interp alias. At one end, a plain interp create is unrestricted. At the other, safe::interpCreate produces a fully safe interpreter with hidden dangerous commands and restricted file/path access. In between, interp hide <command> removes specific commands, interp expose <command> brings them back, and interp alias can redirect them to restricted wrappers — so a subshell can be configured to any point on the spectrum. The existing subshell safe/safebase/punksafe ensemble procs (repl-999999.0a1.0.tm:3530-3560) already create safe interps; this goal generalises that to be configurable on the punk-type subshell too, and exposes the in-between sandboxing points.

The goal is downstream of G-002 because:

  1. The "first subshell asymmetry" fix (G-002) ensures all subshells — including the first — run through the same code-interp creation path, so limits/sandbox applied at creation time are uniform regardless of nesting depth.
  2. G-002's canonical launch API design (section 0 of G-002's approach) makes the dispatch — running in the parent via interp alias — the single owner of code-interp creation. This is the property that makes limits/sandbox uniform: the dispatch applies -limits/-sandbox at creation time for every launch, at every nesting depth, because there is no other code path that creates a code interp.
  3. Resource limits are only meaningful if the subshell actually runs code in the code interp; if the asymmetry persists, the first subshell's limits would need a separate code path, defeating the goal.

The existing safe-interp variants already prove the sandboxing primitive works; this goal is about making it configurable and adding resource limits, not inventing new sandboxing technology.

Approach

  1. Limit configuration surface. Add a -limits option to the subshell launch (and to repl::init where the code interp is created) accepting a dict of limit specs: {command <count>} for command-count and {time <seconds>} for time limits (millisecond granularity to be decided during implementation). Apply via interp limit code ... immediately after interp create code.

  2. Sandbox configuration surface. Add a -sandbox option accepting a spec that places the subshell anywhere on the spectrum from unrestricted to fully safe. Mechanisms: interp hide <command> to remove specific commands, interp expose <command> to bring them back, interp alias to redirect to restricted wrappers, and safe::interpCreate for the fully-safe endpoint. The existing safe/safebase/punksafe launch types become presets that set -sandbox to their respective defaults, proving the general mechanism covers the existing cases.

  3. Nesting-depth independence. Apply limits/sandbox at code-interp creation time, which (after G-002's asymmetry fix) is uniform for all nesting depths. Confirm that nested subshells inherit or re-apply the configured limits rather than silently dropping them — the exact inheritance rule (do limits cascade to nested code interps, or must each level specify its own?) is to be decided during implementation and documented in the subshell command's help text.

  4. Default preserved. When neither -limits nor -sandbox is specified, the subshell launches with no limits and no extra sandbox beyond what the existing launch type already applies (e.g. punk type = no sandbox; safe type = full safe sandbox). This preserves backward compatibility.

Alternatives considered

  • Always-safe subshells, drop the punk type. Rejected: the punk-type subshell exists for trusted code that needs full Tcl access. Sandboxing should be opt-in, not mandatory.
  • OS-level limits only (process/thread, not interp). Rejected: interp limit covers command-count and time at the interp level, which is finer-grained and doesn't require process boundaries. These two dimensions are what Tcl exposes; pursuing OS-level limits (e.g. memory) would be a separate goal if ever needed.
  • A new launch type (e.g. subshell limited) instead of options on existing types. Rejected: options compose better than proliferating launch types. A user should be able to say subshell punk -limits {command 100000} without choosing a different subcommand.
  • Fold this into G-002. Considered and rejected: resource limits + sandboxing is a distinct deliverable with its own acceptance, and the existing code comment at repl:3130-3132 already frames it as "important later" — explicitly downstream. Bundling it into G-002 would make G-002's acceptance uncheckable until this work is also done, and would grow G-002 past a one-line-safe summary.

Notes

  • Depends on G-002's "first subshell asymmetry" fix being complete. Sequence G-002 before G-003.
  • The two interp-level resource limits Tcl exposes are command-count (interp limit -command) and time (interp limit -time). No other interp-level resource limits are in scope; if OS-level limits (e.g. memory via rlimit/job objects) are wanted later, that's a separate goal.
  • The existing safe/safebase/punksafe ensemble procs (repl-999999.0a1.0.tm:3530-3560) are the natural testbed for the sandboxing configuration surface: they should be reimplemented as presets that set -sandbox to their current behaviour, proving the general mechanism covers the existing cases.
  • The sandboxing spectrum is a continuum via interp hide/interp expose/interp alias/safe::interpCreate; the -sandbox option should expose enough of that continuum to let a user say "hide command X and Y, leave the rest" without choosing a different subcommand.
  • interp limit with -command counts commands in the interp; nested interps may or may not count against the parent's limit depending on Tcl's implementation. Confirm during implementation and document in the subshell help text.
  • No persisted prior chat on this topic was found in project sessions; the motivation comes from the existing TODO at repl:3130-3132 and the user's stated intent.