130 lines
3.1 KiB
Go
130 lines
3.1 KiB
Go
package sandbox
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"ollie/util"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// Sandbox prepares a command for restricted execution.
|
|
type Sandbox interface {
|
|
Command(originalCmd []string, cwd string, env map[string]string) ([]string, error)
|
|
}
|
|
|
|
// Config represents the sandbox configuration
|
|
type Config struct {
|
|
General GeneralConfig `yaml:"general"`
|
|
Filesystem FilesystemConfig `yaml:"filesystem"`
|
|
Network NetworkConfig `yaml:"network"`
|
|
Env []string `yaml:"env"`
|
|
Advanced AdvancedConfig `yaml:"advanced"`
|
|
}
|
|
|
|
// GeneralConfig contains general sandbox settings
|
|
type GeneralConfig struct {
|
|
BestEffort bool `yaml:"best_effort"`
|
|
LogLevel string `yaml:"log_level"`
|
|
}
|
|
|
|
// FilesystemConfig contains filesystem permission settings
|
|
type FilesystemConfig struct {
|
|
RO []string `yaml:"ro"` // Read-only
|
|
ROX []string `yaml:"rox"` // Read-only with execute
|
|
RW []string `yaml:"rw"` // Read-write
|
|
RWX []string `yaml:"rwx"` // Read-write with execute
|
|
}
|
|
|
|
// NetworkConfig contains network permission settings
|
|
type NetworkConfig struct {
|
|
Enabled bool `yaml:"enabled"`
|
|
Unrestricted bool `yaml:"unrestricted"`
|
|
BindTCP []string `yaml:"bind_tcp"`
|
|
ConnectTCP []string `yaml:"connect_tcp"`
|
|
}
|
|
|
|
// AdvancedConfig contains compatibility settings retained in the policy format.
|
|
type AdvancedConfig struct {
|
|
LDD bool `yaml:"ldd"`
|
|
AddExec bool `yaml:"add_exec"`
|
|
}
|
|
|
|
// EnvFunc looks up an environment variable by name.
|
|
type EnvFunc func(string) string
|
|
|
|
// expandPath replaces template variables with actual values using getenv for lookups.
|
|
func expandPath(pattern, cwd string, getenv EnvFunc) string {
|
|
s := pattern
|
|
s = strings.ReplaceAll(s, "{CWD}", cwd)
|
|
|
|
re := regexp.MustCompile(`\{([A-Z_][A-Z0-9_]*)\}`)
|
|
s = re.ReplaceAllStringFunc(s, func(match string) string {
|
|
varName := match[1 : len(match)-1]
|
|
|
|
home := getenv("HOME")
|
|
switch varName {
|
|
case "HOME":
|
|
if home != "" {
|
|
return home
|
|
}
|
|
case "TMPDIR":
|
|
if tmpdir := getenv("TMPDIR"); tmpdir != "" {
|
|
return tmpdir
|
|
}
|
|
return "/tmp"
|
|
case "XDG_CONFIG_HOME":
|
|
if xdg := getenv("XDG_CONFIG_HOME"); xdg != "" {
|
|
return xdg
|
|
}
|
|
return filepath.Join(home, ".config")
|
|
case "XDG_DATA_HOME":
|
|
if xdg := getenv("XDG_DATA_HOME"); xdg != "" {
|
|
return xdg
|
|
}
|
|
return filepath.Join(home, ".local/share")
|
|
case "XDG_CACHE_HOME":
|
|
if xdg := getenv("XDG_CACHE_HOME"); xdg != "" {
|
|
return xdg
|
|
}
|
|
return filepath.Join(home, ".cache")
|
|
case "XDG_STATE_HOME":
|
|
if xdg := getenv("XDG_STATE_HOME"); xdg != "" {
|
|
return xdg
|
|
}
|
|
return filepath.Join(home, ".local/state")
|
|
case "XDG_RUNTIME_DIR":
|
|
if xdg := getenv("XDG_RUNTIME_DIR"); xdg != "" {
|
|
return xdg
|
|
}
|
|
return fmt.Sprintf("/run/user/%d", os.Getuid())
|
|
}
|
|
|
|
if val := getenv(varName); val != "" {
|
|
return val
|
|
}
|
|
return match
|
|
})
|
|
|
|
s = util.ExpandHome(s)
|
|
return s
|
|
}
|
|
|
|
// LoadSandbox parses a sandbox config from r.
|
|
func LoadSandbox(r io.Reader) (*Config, error) {
|
|
data, err := io.ReadAll(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var cfg Config
|
|
if err := yaml.Unmarshal(data, &cfg); err != nil {
|
|
return nil, err
|
|
}
|
|
return &cfg, nil
|
|
}
|