mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
* update the go.sum Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com> * migrate most of the files to dry errors Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com> * update the rest of the files Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com> * fixs the review comments Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com> * chores Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com> --------- Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com> Co-authored-by: Abhisek Datta <abhisek.datta@gmail.com>
112 lines
3.8 KiB
Go
112 lines
3.8 KiB
Go
//go:build linux
|
|
// +build linux
|
|
|
|
package platform
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os/exec"
|
|
|
|
"github.com/safedep/dry/log"
|
|
"github.com/safedep/dry/usefulerror"
|
|
"github.com/safedep/pmg/errcodes"
|
|
"github.com/safedep/pmg/sandbox"
|
|
)
|
|
|
|
// bubblewrapSandbox implements the Sandbox interface using Bubblewrap (bwrap) on Linux.
|
|
// Bubblewrap is a low-level unprivileged sandboxing tool that uses Linux namespaces
|
|
// to isolate processes with controlled access to filesystem, network, and IPC resources.
|
|
//
|
|
// This implementation follows the CLI-wrapper pattern (like Seatbelt on macOS):
|
|
// - Modifies the cmd in place by wrapping it with `bwrap` CLI
|
|
// - Returns ExecutionResult with executed=false
|
|
// - Caller must call cmd.Run() to execute the sandboxed command
|
|
type bubblewrapSandbox struct {
|
|
config *bubblewrapConfig
|
|
translator *bubblewrapPolicyTranslator
|
|
}
|
|
|
|
// newBubblewrapSandbox creates a new Bubblewrap sandbox instance with default configuration.
|
|
func newBubblewrapSandbox() (*bubblewrapSandbox, error) {
|
|
config := newDefaultBubblewrapConfig()
|
|
translator := newBubblewrapPolicyTranslator(config)
|
|
|
|
return &bubblewrapSandbox{
|
|
config: config,
|
|
translator: translator,
|
|
}, nil
|
|
}
|
|
|
|
// Execute prepares a command to run in the Bubblewrap sandbox with the given policy.
|
|
// It translates the PMG policy to bwrap CLI arguments and wraps the command execution.
|
|
//
|
|
// This implementation modifies the cmd in place and does NOT execute it.
|
|
// Returns ExecutionResult with executed=false, indicating the caller must run cmd.Run().
|
|
func (b *bubblewrapSandbox) Execute(ctx context.Context, cmd *exec.Cmd, policy *sandbox.SandboxPolicy) (*sandbox.ExecutionResult, error) {
|
|
bwrapPath, err := exec.LookPath("bwrap")
|
|
if err != nil {
|
|
return nil, usefulerror.NewUsefulError().
|
|
WithCode(errcodes.BubblewrapNotFound).
|
|
WithHumanError("Bubblewrap binary not found").
|
|
WithHelp("See more at: https://github.com/safedep/pmg/blob/main/docs/sandbox.md").
|
|
Wrap(fmt.Errorf("bubblewrap binary not found: %w", err))
|
|
}
|
|
|
|
bwrapArgs, err := b.translator.translate(policy)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to translate sandbox policy to bubblewrap arguments: %w", err)
|
|
}
|
|
|
|
log.Debugf("Bubblewrap arguments: %v", bwrapArgs)
|
|
|
|
originalPath := cmd.Path
|
|
originalArgs := cmd.Args
|
|
|
|
// Build bwrap command: bwrap [bwrap-args] -- <original-command> <original-args>
|
|
// The "--" separator is important to distinguish bwrap args from command args
|
|
cmd.Path = bwrapPath
|
|
cmd.Args = []string{"bwrap"}
|
|
|
|
// Add all translated bwrap arguments
|
|
cmd.Args = append(cmd.Args, bwrapArgs...)
|
|
|
|
// Add separator
|
|
cmd.Args = append(cmd.Args, "--")
|
|
|
|
// Add original command
|
|
cmd.Args = append(cmd.Args, originalPath)
|
|
|
|
// Add original arguments (skip argv[0] which is the command itself)
|
|
if len(originalArgs) > 1 {
|
|
cmd.Args = append(cmd.Args, originalArgs[1:]...)
|
|
}
|
|
|
|
log.Debugf("Sandboxed command: %s %v", cmd.Path, cmd.Args)
|
|
|
|
return sandbox.NewExecutionResult(sandbox.WithExecutionResultSandbox(b)), nil
|
|
}
|
|
|
|
// Name returns the name of this sandbox implementation.
|
|
func (b *bubblewrapSandbox) Name() sandbox.DriverName {
|
|
return sandbox.DriverBubblewrap
|
|
}
|
|
|
|
// IsAvailable returns true if bubblewrap (bwrap) is available on this system.
|
|
// Checks by attempting to locate the bwrap binary in PATH.
|
|
func (b *bubblewrapSandbox) IsAvailable() bool {
|
|
_, err := exec.LookPath("bwrap")
|
|
return err == nil
|
|
}
|
|
|
|
// Close cleans up any resources allocated by the sandbox.
|
|
// For Bubblewrap, there are no temporary files to clean up (unlike Seatbelt),
|
|
// since all configuration is passed via CLI arguments.
|
|
//
|
|
// This method is idempotent and safe to call multiple times.
|
|
func (b *bubblewrapSandbox) Close() error {
|
|
// Bubblewrap doesn't create temporary files like Seatbelt does,
|
|
// so there's nothing to clean up. All isolation is via CLI args.
|
|
return nil
|
|
}
|