Skip to content

Latest commit

 

History

39 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

#+TITLE: cl-exec-sandbox

=cl-exec-sandbox= is a policy-driven process sandboxing library for Common
Lisp. Its policy model provides:

- read, write, and deny filesystem rules
- literal paths, deny globs, and portable special roots
- more-specific nested policy overrides
- read-only host and workspace-write presets
- protected project metadata such as =.git=
- full, isolated, and managed proxy-only network modes
- process, user, IPC, UTS, and network namespace isolation on Linux
- fresh =/proc= and minimal =/dev= mounts
- child timeouts and optionally bounded captured output
- explicit capability discovery

One policy is translated by a per-host backend. A policy a backend cannot
enforce signals =sandbox-unavailable= naming the missing capability. Query
=sandbox-capabilities= or =sandbox-supported-p= before relying on a capability.

The policy surface and Linux enforcement model were checked against OpenAI
Codex commit =2e1607ee2fa8099a233df7437adee5f16a741905=. Codex is a reference.

* Linux backend

The Linux backend targets x86-64 and SBCL. It uses the system =bwrap= binary
for filesystem and namespace isolation, plus a private helper for
=no_new_privs=, seccomp, and managed proxy routing. The helper lives beside
the Lisp sources.

* macOS backend

The macOS backend runs commands under Seatbelt through =/usr/bin/sandbox-exec=,
generating a profile from the same policy. Resolved rules are emitted from the
broadest to the most specific, so Seatbelt's last-match-wins resolution
reproduces nested overrides and protected metadata. Whole-root rules are
emitted before device access, so a read-only root still permits =/dev=. A
rule naming a single file becomes a =literal= filter.

On macOS:

- =:enabled= and =:isolated= networking work
- =sandbox-capabilities= reports =:process-namespaces= as false
- process separation is an accidental-damage boundary

Deny globs need =rg= on either host. Seatbelt installations outside =/usr/bin=
can set =CL_EXEC_SANDBOX_SEATBELT= to an absolute executable path.

* Windows backend

The experimental Windows backend combines a fresh AppContainer identity with
an invocation-specific restricted-token SID for deny rules and a kill-on-close
Job Object for descendants. Run it as a standard Windows user. Build
=scripts/build-windows-helper.ps1= from a Visual Studio SDK developer shell
with Clang installed, then ship
=build/cl-exec-sandbox-windows.exe= beside the Lisp sources. Alternatively, set
=CL_EXEC_SANDBOX_WINDOWS_HELPER= to its absolute path outside writable scopes.

Use =appcontainer-sandbox-policy= with explicit existing =:read-roots= and
=:workspace-roots=. Include the command's binaries and dependencies in the read
scopes. Windows also supplies its normal AppContainer system-resource access
and private profile storage. Networking is isolated, including loopback.

#+BEGIN_SRC lisp
(let ((policy
        (cl-exec-sandbox:appcontainer-sandbox-policy
         :workspace-roots (list #P"C:/work/project/")
         :read-roots (list #P"C:/tools/"))))
  (cl-exec-sandbox:run-sandboxed
   "C:/tools/tool.exe" '("--version")
   :policy policy :working-directory #P"C:/work/project/" :timeout 30))
#+END_SRC

The backend rejects whole-host policies, network modes other than =:isolated=,
proc mounts, PID namespaces, globs, drive roots, UNC/device paths, reparse
points, hard-linked files, and paths of 240 characters
or more. The default protected metadata names are =.git=, =.agents=, and =.codex=.
This backend is not policy-equivalent to the Linux whole-host presets.

Filesystem grants are temporary SID-specific ACL entries. Native execution
and ACL changes are serialized within a Windows session. Serialize calls with
overlapping roots as well, including plan construction and cleanup of missing
metadata directories. Keep the trees and ACLs free of concurrent changes by
other host processes during a run.
Normal completion and =run-sandboxed= cancellation remove the grants and profile;
cleanup failures are reported. Terminating both the Lisp supervisor and helper
can leave stale SID entries and a profile. This prototype has no persistent
crash-recovery journal. When launching a plan yourself, call
=sandbox-plan-cleanup= after terminating and waiting for its helper.

Run =(asdf:test-system :cl-exec-sandbox/windows-tests)= after compiling
=tests/windows-child.c= to =build/windows-child.exe=. CI runs these enforcement
tests under a disposable non-administrator account.

* Example

#+BEGIN_SRC lisp
(let ((policy
        (cl-exec-sandbox:workspace-write-sandbox-policy
         :workspace-roots (list #P"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/work/project/")
         :network :isolated)))
  (cl-exec-sandbox:run-sandboxed
   "/bin/sh"
   '("-c" "git status --short")
   :policy policy
   :working-directory #P"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/work/project/"
   :output-limit 65536
   :error-output-limit 65536))
#+END_SRC

When a limit is exceeded, the returned prefix is available through
=sandbox-result-output= or =sandbox-result-error-output=. Inspect
=sandbox-result-output-truncated-p= and
=sandbox-result-error-output-truncated-p= before presenting captured output.

* Checks

Build the private Linux helper and run the complete test suite:

#+BEGIN_SRC sh
./check
#+END_SRC

Seatbelt profile translation is a pure function of a policy, so its tests run
on any host. They assert the generated profile text.

Applications which vendor this system should run =scripts/build-helper= during
their build and ship =build/cl-exec-sandbox-process-group= beside the Lisp
sources. Linux applications using restricted networking must also ship
=build/cl-exec-sandbox-helper=. Set =CL_EXEC_SANDBOX_PROCESS_GROUP_HELPER= or
=CL_EXEC_SANDBOX_HELPER= to alternate absolute helper paths when the installed
layout differs. Packaged Bubblewrap installations outside =/usr/bin= and =/bin=
can set =CL_EXEC_SANDBOX_BWRAP= to its absolute executable path.

Part of the [[https://www.lambda-symbolics.com/libraries][Lambda Symbolics library shelf]].

About

A policy-driven process sandboxing library for Common Lisp

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages