safeexec

package
v0.22.2 Latest Latest
Warning

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

Go to latest
Published: Jun 22, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package safeexec provides drop-in replacements for selected os/exec helpers whose implementation in Go's standard library uses the faccessat2(2) Linux syscall (number 439, introduced in kernel 5.8).

Android's seccomp filter on devices that still ship a 4.x kernel (a common combination — Android 13 userland on top of a 4.14 kernel, for example) rejects faccessat2 with SIGSYS instead of the ENOSYS that Go's runtime expects to trigger its faccessat fallback. SIGSYS kills the process, so Go's fallback never fires.

The crash signature in the wild looks like:

SIGSYS: bad system call
internal/syscall/unix.faccessat2(...)
internal/syscall/unix.Eaccess(...)
os/exec.findExecutable(...)
os/exec.LookPath(...)

Use LookPath in this package instead of os/exec.LookPath anywhere the result will run on Termux/Android phones. The implementation here checks executability using os.Stat + the file's mode bits, which only goes through the fstatat(2) syscall family that Android seccomp does allow.

The .golangci.yml in this repo bans direct calls to exec.LookPath via forbidigo. If you have a genuine reason to use the stdlib version (e.g. you need euid-based AT_EACCESS semantics in a setuid context), add a //nolint:forbidigo comment with a justification.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Command added in v0.14.16

func Command(name string, args ...string) *exec.Cmd

Command wraps exec.Command but pre-resolves a bare executable name via LookPath so the returned *exec.Cmd carries an absolute path. This prevents Go's internal LookPath (which calls faccessat2(2), rejected by Android/Termux seccomp on kernel < 5.8 with SIGSYS) from firing when the caller later invokes cmd.Start.

Names already containing a path separator (absolute or workspace-relative) bypass LookPath inside exec.Command anyway, so they are passed through unchanged. Resolution failures are swallowed: the returned Cmd keeps the original name, and the error surfaces at cmd.Start / cmd.Run — matching upstream semantics.

func CommandContext added in v0.14.16

func CommandContext(ctx context.Context, name string, args ...string) *exec.Cmd

CommandContext is the context-aware sibling of Command. Same pre-resolution semantics.

func LookPath

func LookPath(file string) (string, error)

LookPath searches PATH for an executable named file, mirroring os/exec.LookPath's semantics but without the faccessat2 syscall. If file contains a slash it is checked directly. On Windows, bare names without an extension are resolved against PATHEXT so "cmd" finds "cmd.exe". Returns an *exec.Error so callers can use errors.Is(err, exec.ErrNotFound).

func ResolveBin

func ResolveBin(name string) (string, error)

ResolveBin returns the absolute path to name. If name already contains a slash it is returned unchanged (caller is assumed to have given an absolute or workspace-relative path); otherwise the name is resolved via LookPath. Use this before passing name to exec.CommandContext to prevent Go's internal LookPath from firing during exec.Command construction — that path triggers faccessat2, which Android's seccomp on kernel < 5.8 rejects with SIGSYS.

Types

This section is empty.

Jump to

Keyboard shortcuts

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