allowedpaths

package
v0.0.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 30, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package allowedpaths implements a filesystem sandbox that restricts access to a set of allowed directories using os.Root (Go 1.24+).

Index

Constants

View Source
const MaxGlobEntries = 10_000

MaxGlobEntries is the maximum number of directory entries read per single glob expansion step. ReadDirForGlob returns an error for directories that exceed this limit to prevent memory exhaustion during pattern matching.

Variables

This section is empty.

Functions

func CollectDirEntries

func CollectDirEntries(readBatch func(n int) ([]fs.DirEntry, error), batchSize, offset, maxRead int) ([]fs.DirEntry, bool, error)

CollectDirEntries reads directory entries in batches using readBatch, skipping the first offset entries and collecting up to maxRead entries. Returns (entries, truncated, lastErr). Entries are sorted by name.

NOTE: We intentionally truncate before reading all entries. For directories larger than maxRead, the returned entries are sorted within the read window but may not be the globally-smallest names. Reading all entries to get globally-correct sorting would defeat the DoS protection — a directory with millions of files would OOM or stall. The truncation warning communicates that output is incomplete.

func FileIdentity

func FileIdentity(_ string, info fs.FileInfo, _ *Sandbox) (uint64, uint64, bool)

FileIdentity extracts canonical file identity (dev+inode) from FileInfo. On Unix, this is extracted directly from Stat_t via info.Sys().

func IsDevNull

func IsDevNull(path string) bool

IsDevNull reports whether path refers to the platform's null device.

func IsErrIsDirectory

func IsErrIsDirectory(err error) bool

IsErrIsDirectory reports whether err is an "is a directory" error.

func PortableErrMsg

func PortableErrMsg(err error) string

PortableErrMsg returns a POSIX-style error message for the given error, normalizing platform-specific syscall messages to consistent strings. This ensures shell error output is identical across Linux, macOS, and Windows.

func PortablePathError

func PortablePathError(err error) error

PortablePathError returns a *os.PathError with a normalized error message. If the error is not a *os.PathError, it is returned as-is. Only the Err field is normalized; the Path and Op fields are preserved as-is.

func WithContextClose added in v0.0.8

func WithContextClose(ctx context.Context, f io.ReadWriteCloser) io.ReadWriteCloser

WithContextClose wraps f so that f.Close() is guaranteed to be called when ctx is done, in addition to any explicit Close calls made by the caller. The underlying file is closed at most once.

A background goroutine waits for either ctx cancellation or an explicit Close call. If the context expires first the file is closed immediately and the goroutine exits. If Close is called first the goroutine is signalled to stop and exits without touching the file again.

Types

type Sandbox

type Sandbox struct {
	// contains filtered or unexported fields
}

Sandbox restricts filesystem access to a set of allowed directories. The restriction is enforced using os.Root (Go 1.24+), which uses openat syscalls for atomic path validation — immune to symlink and ".." traversal attacks.

func New

func New(paths []string) (sb *Sandbox, warnings []byte, err error)

New creates a sandbox from an allowlist of directory paths. Paths that do not exist or cannot be opened are silently skipped — the sandbox operates with whatever paths are available at construction time.

Diagnostic messages about skipped paths are collected into warnings. The caller is responsible for writing them to the appropriate output stream.

func (*Sandbox) Access

func (s *Sandbox) Access(path string, cwd string, mode uint32) error

Access checks whether the resolved path is accessible with the given mode. All operations go through os.Root to stay within the sandbox. Mode: 0x04 = read, 0x02 = write, 0x01 = execute.

On Unix, read permission for regular files is verified by attempting to open through os.Root with O_NONBLOCK (fd-relative openat, respects POSIX ACLs, never blocks on FIFOs). Metadata is obtained from the opened fd via fstat to eliminate TOCTOU between open and stat. For special files where open fails (e.g. sockets), and for write and execute checks, mode-bit inspection is used on the fd-relative Stat result. On Windows, the same OpenFile approach is used for read checks; write and execute checks are not performed.

All operations are fd-relative through os.Root — no filesystem path is re-resolved through the mutable namespace after initial validation.

func (*Sandbox) Close

func (s *Sandbox) Close() error

Close releases all os.Root file descriptors. It is safe to call multiple times.

func (*Sandbox) IsDirEmpty

func (s *Sandbox) IsDirEmpty(path string, cwd string) (bool, error)

IsDirEmpty checks whether a directory is empty by reading at most one entry. More efficient than reading all entries when only emptiness needs to be determined.

func (*Sandbox) Lstat

func (s *Sandbox) Lstat(path string, cwd string) (fs.FileInfo, error)

Lstat implements the restricted lstat policy. Like stat, it uses a metadata-only call, but does not follow symbolic links — the returned FileInfo describes the link itself rather than its target.

func (*Sandbox) Open

func (s *Sandbox) Open(path string, cwd string, flag int, perm os.FileMode) (io.ReadWriteCloser, error)

Open implements the restricted file-open policy. The file is opened through os.Root for atomic path validation. Only read-only access is permitted; any write flags are rejected as a defense-in-depth measure.

func (*Sandbox) OpenDir

func (s *Sandbox) OpenDir(path string, cwd string) (fs.ReadDirFile, error)

OpenDir opens a directory within the sandbox for incremental reading via ReadDir(n). The caller must close the returned handle when done. Returns fs.ReadDirFile to expose only read-only directory methods.

func (*Sandbox) ReadDir

func (s *Sandbox) ReadDir(path string, cwd string) ([]fs.DirEntry, error)

ReadDir implements the restricted directory-read policy.

func (*Sandbox) ReadDirForGlob

func (s *Sandbox) ReadDirForGlob(path string, cwd string) ([]fs.DirEntry, error)

ReadDirForGlob reads directory entries for glob expansion, capped at MaxGlobEntries. The underlying ReadDir call is limited to MaxGlobEntries+1 so the kernel never materialises more entries than needed. If the directory exceeds the limit an error is returned before any pattern matching or sorting can occur, making the failure explicit rather than silently returning a partial listing that could miss valid matches.

func (*Sandbox) ReadDirLimited

func (s *Sandbox) ReadDirLimited(path string, cwd string, offset, maxRead int) ([]fs.DirEntry, bool, error)

ReadDirLimited reads directory entries, skipping the first offset entries and returning up to maxRead entries sorted by name within the read window. Returns (entries, truncated, error). When truncated is true, the directory contained more entries beyond the returned set.

The offset skips raw directory entries during reading (before sorting). This means offset does NOT correspond to positions in a sorted listing — pages may overlap or miss entries. This is an acceptable tradeoff to achieve O(n) memory regardless of offset value, where n = min(maxRead, entries).

func (*Sandbox) Stat

func (s *Sandbox) Stat(path string, cwd string) (fs.FileInfo, error)

Stat implements the restricted stat policy. It uses os.Root.Stat for metadata-only access — no file descriptor is opened, so it works on unreadable files and does not block on special files (e.g. FIFOs).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL