12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 | //go:build openbsd
package sandbox
import (
"errors"
"os"
"slices"
"golang.org/x/sys/unix"
)
// system lets the renderer run ssh, and git from OpenBSD's package (the
// renderer adds the git it runs itself): x on them, and /dev/null,
// which os/exec opens for every child's unset stdin. It also names files
// those programs read (the dynamic loader and its libraries, ssh's
// configuration and known_hosts, the resolver), but the programs do not
// need them here: execve(2) starts a program with no unveils (see
// unveil(2)), so git and ssh see the whole filesystem. This list confines
// the renderer itself, not what it runs.
var system = []Path{
{Path: "/dev/null", Perms: "rw"},
{Path: "/usr/local/libexec/git", Perms: "rx"},
{Path: "/usr/local/share/git-core", Perms: "r"},
{Path: "/bin/sh", Perms: "x"},
{Path: "/usr/bin/ssh", Perms: "x"},
{Path: "/usr/libexec/ld.so", Perms: "r"},
{Path: "/var/run/ld.so.hints", Perms: "r"},
{Path: "/usr/lib", Perms: "r"},
{Path: "/usr/local/lib", Perms: "r"},
{Path: "/etc/ssl", Perms: "r"},
{Path: "/etc/ssh", Perms: "r"},
{Path: "/etc/resolv.conf", Perms: "r"},
{Path: "/etc/hosts", Perms: "r"},
{Path: "/etc/pwd.db", Perms: "r"},
{Path: "/etc/localtime", Perms: "r"},
}
// Restrict limits the renderer's filesystem visibility to the given
// paths, plus system, then locks the unveil list. Each entry is a path and
// permission string ("r", "rwc", "x").
//
// An entry whose parent directory does not exist (a home directory of
// /nonexistent, say) is skipped: leaving it out only grants less, and
// whatever needed it fails later with an error that names the real path.
func Restrict(paths []Path) error {
for _, p := range slices.Concat(system, paths) {
if err := unix.Unveil(p.Path, p.Perms); err != nil && !errors.Is(err, unix.ENOENT) {
return err
}
}
return unix.UnveilBlock()
}
// Unveil adds exactly the given paths, without the renderer's system
// list and without locking, so more can follow. A path whose directory
// does not exist is an error here: a caller that names it means to use
// it.
func Unveil(paths []Path) error {
for _, p := range paths {
if err := unix.Unveil(p.Path, p.Perms); err != nil {
return &os.PathError{Op: "unveil " + p.Perms, Path: p.Path, Err: err}
}
}
return nil
}
// Lock forbids further unveil calls.
func Lock() error { return unix.UnveilBlock() }
// Pledge restricts the process to promises. Programs it executes start
// unpledged, as execpromises is left alone.
func Pledge(promises string) error { return unix.PledgePromises(promises) }
// Supported reports whether Unveil and Pledge do anything here.
const Supported = true
|