Documentation
¶
Overview ¶
Run embedded executables and scripts straight from anonymous memory on Linux and Android. emrun wraps memfd_create(2) so you can bundle auxiliary tooling and scripts inside a Go binary, execute them without touching disk in the common case, and keep the package fully self-contained even when hardened kernels restrict anonymous execution.
Index ¶
- Variables
- func CheckPolicy(ctx context.Context, digest [32]byte, hexDigest string) error
- func Do(ctx context.Context, payload string, arg ...string) ([]byte, error)
- func Run(ctx context.Context, executablePayload []byte, arg ...string) ([]byte, error)
- func RunCommand(runner port.CommandRunner, cmd *exec.Cmd, combinedOutput bool) ([]byte, error)
- func RunIO(ctx context.Context, r io.Reader, w io.Writer, executablePayload []byte, ...) error
- func RunIOE(ctx context.Context, r io.Reader, stdout io.Writer, stderr io.Writer, ...) error
- func StartCommand(runner port.CommandRunner, cmd *exec.Cmd, combinedOutput bool) (port.CommandCapture, error)
- func WithPolicy(ctx context.Context, verdict Verdict) context.Context
- func WithRule(ctx context.Context, rule Verdict, sha256Digests ...Digest) context.Context
- func WithRuleCatchError(ctx context.Context, rule Verdict, sha256Digests ...Digest) (context.Context, error)
- type Background
- func DoBG(ctx context.Context, payload string, arg ...string) (*Background, error)
- func RunBG(ctx context.Context, executablePayload []byte, arg ...string) (*Background, error)
- func RunIOBG(ctx context.Context, reader io.Reader, writer io.Writer, ...) (*Background, error)
- func RunIOEBG(ctx context.Context, reader io.Reader, stdout io.Writer, stderr io.Writer, ...) (*Background, error)
- func StartBackground(parentCtx context.Context, run port.BackgroundRunnable, args []string, ...) (*Background, error)
- type Digest
- type PolicyError
- type Result
- type Runnable
- type Verdict
Constants ¶
This section is empty.
Variables ¶
var ( ERR_PAYLOAD_IS_EMPTY error = errors.New("payload is empty") ERR_NOT_AN_INMEMORY_FD error = errors.New("not an in-memory file descriptor") )
var ErrDenied = errors.New("emrun: execution denied by policy")
Functions ¶
func CheckPolicy ¶
CheckPolicy inspects the context policy and returns ErrDenied if the digest violates the configured rules.
ctx := emrun.WithRule(context.Background(), emrun.DENY, "deadbeef...")
digest := sha256.Sum256(payload)
if err := emrun.CheckPolicy(ctx, digest, hex.EncodeToString(digest[:])); err != nil {
return err
}
func Do ¶
Do is intended to run shebang scripts inline or from string vars. Uses ctx in exec.CommandContext and returns (*exec.Cmd).CombinedOutput.
func Run ¶
Run executes the payload with ctx in exec.CommandContext with args using (*exec.Cmd).CombinedOutput, returns combined output or error. cmd.Stdin is nil, use RunIO if you want to pass data via stdin.
func RunCommand ¶
RunCommand executes cmd using the supplied runner. When combinedOutput is true the function captures stdout and stderr into a shared buffer and returns it as a copy to the caller. Otherwise RunCommand defers to the runner without altering the configured streams.
func RunIO ¶
func RunIO(ctx context.Context, r io.Reader, w io.Writer, executablePayload []byte, arg ...string) error
RunIO is similar to Run but uses r for stdin and w for stdout and stderr. Uses ctx for (*exec.Cmd).CommandContext.
func RunIOE ¶
func RunIOE(ctx context.Context, r io.Reader, stdout io.Writer, stderr io.Writer, executablePayload []byte, arg ...string) error
RunIOE is exactly like RunIO except with separate stdout and stderr writers.
func StartCommand ¶
func StartCommand(runner port.CommandRunner, cmd *exec.Cmd, combinedOutput bool) (port.CommandCapture, error)
StartCommand starts cmd using the supplied runner while optionally capturing combined stdout/stderr. The returned CommandCapture must later be passed to WaitCommand (or Restore via Finish) to release resources.
func WithPolicy ¶
WithPolicy returns a derived context that sets the default verdict consulted when no explicit allow/deny rule matches a payload digest.
ctx := emrun.WithPolicy(context.Background(), emrun.DENY) ctx = emrun.WithRule(ctx, emrun.ALLOW, sha256FileBytes) _ = emrun.CheckPolicy(ctx, digest, hexDigest)
func WithRule ¶
WithRule returns a derived context containing explicit allow/deny entries for SHA-256 digests. Each argument may be a raw digest type (string, []byte, [32]byte) or sha256sum-formatted content; filenames are ignored. WithRule must succeed - invalid input causes a panic.
ctx := emrun.WithPolicy(ctx, emrun.DENY)
ctx = emrun.WithRule(ctx, emrun.ALLOW, []byte("<digest> tool"))
ctx = emrun.WithRule(ctx, emrun.DENY, "deadbeef...deadbeef")
_ = emrun.CheckPolicy(ctx, digest, hexDigest)
Types ¶
type Background ¶
type Background struct {
Context context.Context
Cancel context.CancelFunc
Done <-chan Result
}
func DoBG ¶
DoBG runs the provided script string in the background, mirroring Do but returning a Background handle so callers can select on completion or cancel.
func RunBG ¶
RunBG launches the payload in the background and returns a Background handle that exposes the running context. Example usage:
bg, err := emrun.RunBG(ctx, payload, "--flag")
if err != nil {
return err
}
defer bg.Cancel()
select {
case res := <-bg.Done:
if res.Error != nil {
return res.Error
}
case <-ctx.Done():
return ctx.Err()
}
func RunIOBG ¶
func RunIOBG(ctx context.Context, reader io.Reader, writer io.Writer, executablePayload []byte, arg ...string) (*Background, error)
RunIOBG behaves like RunBG but wires the provided reader/writer to stdin and combined stdout/stderr. The returned Result has a nil CombinedOutput since output is streamed to writer.
func RunIOEBG ¶
func RunIOEBG(ctx context.Context, reader io.Reader, stdout io.Writer, stderr io.Writer, executablePayload []byte, arg ...string) (*Background, error)
RunIOEBG is the background variant of RunIOE, streaming stdout and stderr to separate writers while returning a Background handle for lifecycle control.
func StartBackground ¶
func StartBackground(parentCtx context.Context, run port.BackgroundRunnable, args []string, stdin io.Reader, stdout io.Writer, stderr io.Writer, combined bool) (*Background, error)
StartBackground launches cmd via the runnable, wiring optional stdio streams and returning a Background handle that reports completion through Done.
func (*Background) Wait ¶
func (bg *Background) Wait() Result
Wait blocks until the background command finishes or the stored context is cancelled. It returns the underlying Result; if the stored context is nil it behaves like WaitWithContext(context.Background()).
func (*Background) WaitWithContext ¶
func (bg *Background) WaitWithContext(ctx context.Context) Result
WaitWithContext blocks until the background command completes or ctx is cancelled. Cancellation returns a Result whose Error is ctx.Err().
type PolicyError ¶
func (*PolicyError) Error ¶
func (e *PolicyError) Error() string
func (*PolicyError) Is ¶
func (e *PolicyError) Is(target error) bool
type Result ¶
func WaitCommand ¶
func WaitCommand(cmd *exec.Cmd, capture port.CommandCapture) Result
WaitCommand waits for cmd to exit and returns a Result capturing the exit code, error, and any combined output buffered by StartCommand.
type Runnable ¶
func Open ¶
Open attempts to create a memory file descriptor using memfd_create(2), name will be a sha256 hash of the payload that will show up under /proc/<pid>/{fd,fdinfo}, running process will show up as /proc/self/fd/<int>. Returns an open file descriptor (or error) where Name() can be used to execute it. Close the fd when done. If unix.MemfdCreate() fails, Open will fall back to writing the payload as a temporary file with user execute bit set. When Close() is called, the temporary file will be deleted. Payload can be anything Linux/Android can execute (ELF and script shebang). Example:
//go:embed myapp
var elfOrShebangScript []byte
//...
f, err := emrun.Open("myapp", elfOrShebangScript)
if err != nil {
panic(err)
}
defer f.Close()
cmd := exec.Command(f.Name(), "--version")
//...
cmd.Run()
Directories
¶
| Path | Synopsis |
|---|---|
|
adapters
|
|
|
The emrun companion package efrun exposes the same API surface as emrun but always executes from a temporary file, which makes it portable to platforms where memfd_create is unavailable, but you have to explicitly choose that import.
|
The emrun companion package efrun exposes the same API surface as emrun but always executes from a temporary file, which makes it portable to platforms where memfd_create is unavailable, but you have to explicitly choose that import. |