small fix
This commit is contained in:
13
README.md
13
README.md
@@ -58,14 +58,19 @@ GLoom will also use a config file in the `GLOOM_DIR` to configure plugins and ot
|
||||
```toml
|
||||
[[plugins]]
|
||||
file = "gloomi.so"
|
||||
name = "GLoomI"
|
||||
domains = ["localhost"]
|
||||
```
|
||||
|
||||
The `[[plugins]]` array is a list of plugins to preload. Each plugin is an object with the following fields:
|
||||
|
||||
- `file` - The path to the plugin file. This is a string value.
|
||||
- `domains` - An array of domains to forward requests to this plugin. This is an array of strings.
|
||||
The config is in TOML and has the following keys:
|
||||
|
||||
- `plugins` - An array of plugins to load. Each plugin is an object with the following keys:
|
||||
- `file` - The name of the plugin file.
|
||||
- `name` - The name of the plugin. Can only contain alphanumeric characters and `-` and `_`.
|
||||
- `domains` - An array of domains to load the plugin on.
|
||||
- `pluginDir` - The directory to store plugins in relative to `GLOOM_DIR`. Defaults to `plugs`.
|
||||
- `enableChroot` - Whether to enable chroot, this forces plugins to a specific directory that they cannot escape.
|
||||
Defaults to `false`.
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
@@ -11,5 +11,6 @@ var embeddedAssets embed.FS
|
||||
var defaultConfig = []byte(`
|
||||
[[plugins]]
|
||||
file = "gloomi.so"
|
||||
name = "GLoomI"
|
||||
domains = ["localhost"]
|
||||
`)
|
||||
|
||||
@@ -16,13 +16,13 @@ type GLoomI struct {
|
||||
|
||||
func (p *GLoomI) Init() (*fiber.Config, error) {
|
||||
// Connect to the RPC server
|
||||
client, err := rpc.Dial("tcp", "localhost:7143")
|
||||
client, err := rpc.Dial("tcp", "127.0.0.1:7143")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect to Gloom RPC server: %w", err)
|
||||
}
|
||||
p.client = client
|
||||
return &fiber.Config{
|
||||
BodyLimit: 1024 * 1024 * 1024 * 5, // 5GB
|
||||
BodyLimit: 1024 * 1024 * 1024 * 5, // 5GiB
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -94,10 +94,12 @@ func (p *GLoomI) RegisterRoutes(router fiber.Router) {
|
||||
}
|
||||
|
||||
var pluginUploadStruct struct {
|
||||
Domains []string `json:"domains"`
|
||||
Name string `json:"name"`
|
||||
Data []byte `json:"data"`
|
||||
FileName string `json:"fileName"`
|
||||
Name string `json:"name"`
|
||||
Domains []string `json:"domains"`
|
||||
Data []byte `json:"data"`
|
||||
}
|
||||
pluginUploadStruct.FileName = pluginFile.Filename
|
||||
pluginUploadStruct.Name = pluginUpload.Name
|
||||
pluginUploadStruct.Domains = domains
|
||||
pluginUploadStruct.Data, err = io.ReadAll(pluginData)
|
||||
|
||||
2
go.mod
2
go.mod
@@ -7,6 +7,8 @@ require (
|
||||
github.com/mattn/go-sqlite3 v1.14.24
|
||||
)
|
||||
|
||||
require github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.5.0
|
||||
golang.org/x/sync v0.14.0 // indirect
|
||||
|
||||
2
go.sum
2
go.sum
@@ -4,5 +4,7 @@ github.com/juls0730/sentinel v0.0.0-20250515154110-2e7e6586cacd h1:JNazPdlAs307G
|
||||
github.com/juls0730/sentinel v0.0.0-20250515154110-2e7e6586cacd/go.mod h1:CnRvcleiS2kvK1N2PeQmeoRP5EXpBDpHPkg72vAUaSg=
|
||||
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
|
||||
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
|
||||
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
|
||||
174
main.go
174
main.go
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"math/rand/v2"
|
||||
"net"
|
||||
@@ -23,8 +24,50 @@ import (
|
||||
"github.com/juls0730/gloom/libs"
|
||||
"github.com/juls0730/sentinel"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/syndtr/gocapability/capability"
|
||||
)
|
||||
|
||||
func hasChrootAbility() bool {
|
||||
cap, err := capability.NewPid2(0)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
err = cap.Load()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return cap.Get(capability.EFFECTIVE, capability.CAP_SYS_CHROOT) || cap.Get(capability.PERMITTED, capability.CAP_SYS_CHROOT)
|
||||
}
|
||||
|
||||
func hasChangeUserAbility() bool {
|
||||
cap, err := capability.NewPid2(0)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
err = cap.Load()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
permitted := true
|
||||
for _, permission := range []capability.Cap{
|
||||
capability.CAP_SETUID,
|
||||
capability.CAP_SETGID,
|
||||
capability.CAP_SETFCAP,
|
||||
} {
|
||||
if cap.Get(capability.EFFECTIVE, permission) || cap.Get(capability.PERMITTED, permission) {
|
||||
continue
|
||||
}
|
||||
permitted = false
|
||||
break
|
||||
}
|
||||
|
||||
return permitted
|
||||
}
|
||||
|
||||
type PluginHost struct {
|
||||
UnixSocket string
|
||||
Process *os.Process
|
||||
@@ -37,13 +80,16 @@ type PluginConfig struct {
|
||||
|
||||
type PreloadPlugin struct {
|
||||
File string
|
||||
Name string
|
||||
Domains []string
|
||||
}
|
||||
|
||||
// might change this later
|
||||
const DEFAULT_PLUGIN_DIR = "plugs"
|
||||
const DEFAULT_CHROOT_DIR = "plugData"
|
||||
|
||||
type GLoomConfig struct {
|
||||
EnableChroot bool `toml:"enableChroot"`
|
||||
PluginDir string `toml:"pluginDir"`
|
||||
PreloadPlugins []PreloadPlugin `toml:"plugins"`
|
||||
}
|
||||
@@ -51,8 +97,6 @@ type GLoomConfig struct {
|
||||
type GLoom struct {
|
||||
config GLoomConfig
|
||||
|
||||
// path to the /tmp directory where the pluginHost sockets are created
|
||||
tmpDir string
|
||||
gloomDir string
|
||||
|
||||
// maps plugin names to plugins
|
||||
@@ -65,6 +109,8 @@ type GLoom struct {
|
||||
}
|
||||
|
||||
func NewGloom(proxyManager *sentinel.ProxyManager) (*GLoom, error) {
|
||||
log.SetOutput(os.Stderr)
|
||||
|
||||
gloomDir := os.Getenv("GLOOM_DIR")
|
||||
if gloomDir == "" {
|
||||
if os.Getenv("XDG_DATA_HOME") != "" {
|
||||
@@ -106,11 +152,6 @@ func NewGloom(proxyManager *sentinel.ProxyManager) (*GLoom, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tmpDir, err := os.MkdirTemp(os.TempDir(), "gloom")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := os.Stat(filepath.Join(gloomDir, "pluginHost")); os.IsNotExist(err) {
|
||||
if err := os.WriteFile(filepath.Join(gloomDir, "pluginHost"), pluginHost, 0755); err != nil {
|
||||
return nil, err
|
||||
@@ -120,7 +161,6 @@ func NewGloom(proxyManager *sentinel.ProxyManager) (*GLoom, error) {
|
||||
}
|
||||
|
||||
gloom := &GLoom{
|
||||
tmpDir: tmpDir,
|
||||
gloomDir: gloomDir,
|
||||
plugins: libs.SyncMap[string, *PluginHost]{},
|
||||
DB: db,
|
||||
@@ -132,6 +172,17 @@ func NewGloom(proxyManager *sentinel.ProxyManager) (*GLoom, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if gloom.config.EnableChroot {
|
||||
// make sure we have super user privileges
|
||||
if !hasChrootAbility() {
|
||||
return nil, fmt.Errorf("chroot is enabled, but you do not have the required privileges to use it")
|
||||
}
|
||||
|
||||
if !hasChangeUserAbility() {
|
||||
return nil, fmt.Errorf("chroot is enabled, but you do not have the required privileges to use it")
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(gloom.config.PluginDir, 0755); err != nil {
|
||||
slog.Error("Failed to create pluginDir", "dir", gloom.config.PluginDir, "error", err)
|
||||
return nil, err
|
||||
@@ -141,13 +192,17 @@ func NewGloom(proxyManager *sentinel.ProxyManager) (*GLoom, error) {
|
||||
if _, err := embeddedAssets.Open("dist/gloomi.so"); err == nil {
|
||||
// and if the plugin doesn't exist, copy it over
|
||||
// TODO: instead, check if the plugin doesnt exist OR the binary has a newer timestamp than the current version
|
||||
if _, err := os.Stat(filepath.Join(gloom.config.PluginDir, "gloomi.so")); os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(path.Join(gloom.config.PluginDir, "GLoomI"), 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := os.Stat(path.Join(gloom.config.PluginDir, "GLoomI", "gloomi.so")); os.IsNotExist(err) {
|
||||
gloomiData, err := embeddedAssets.ReadFile("dist/gloomi.so")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := os.WriteFile(filepath.Join(gloom.config.PluginDir, "gloomi.so"), gloomiData, 0755); err != nil {
|
||||
if err := os.WriteFile(path.Join(gloom.config.PluginDir, "GLoomI", "gloomi.so"), gloomiData, 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -172,23 +227,31 @@ func (gloom *GLoom) loadConfig() error {
|
||||
return err
|
||||
}
|
||||
|
||||
slog.Debug("Loaded config", "config", gloom.config)
|
||||
|
||||
if gloom.config.PluginDir == "" {
|
||||
gloom.config.PluginDir = DEFAULT_PLUGIN_DIR
|
||||
}
|
||||
|
||||
gloom.config.PluginDir = filepath.Join(gloom.gloomDir, gloom.config.PluginDir)
|
||||
|
||||
slog.Debug("Loaded config", "config", gloom.config)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gloom *GLoom) Cleanup() error {
|
||||
for _, plugin := range gloom.plugins.Keys() {
|
||||
gloom.StopPlugin(plugin)
|
||||
}
|
||||
|
||||
// return nil
|
||||
}
|
||||
|
||||
func (gloom *GLoom) LoadInitialPlugins() error {
|
||||
slog.Info("Loading initial plugins")
|
||||
|
||||
for _, plugin := range gloom.config.PreloadPlugins {
|
||||
if err := gloom.RegisterPlugin(filepath.Join(gloom.config.PluginDir, plugin.File), plugin.File, plugin.Domains); err != nil {
|
||||
panic(fmt.Errorf("failed to load preload plugin %s: %w (make sure its in %s)", plugin.File, err, gloom.config.PluginDir))
|
||||
if err := gloom.RegisterPlugin(filepath.Join(gloom.config.PluginDir, plugin.Name, plugin.File), plugin.Name, plugin.Domains); err != nil {
|
||||
panic(fmt.Errorf("failed to load preload plugin %s: %w (make sure its in %s)", plugin.Name, err, path.Join(gloom.config.PluginDir, plugin.Name)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,30 +332,65 @@ func (dt *MutexLock[T]) Unlock(id T) {
|
||||
var deploymentLock = NewMutexLock[string]()
|
||||
|
||||
func (gloom *GLoom) RegisterPlugin(pluginPath string, name string, domains []string) (err error) {
|
||||
for _, char := range name {
|
||||
if !((char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || (char >= '0' && char <= '9') || char == '-' || char == '_') {
|
||||
return fmt.Errorf("invalid plugin name")
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info("Registering plugin", "pluginPath", pluginPath, "domains", domains)
|
||||
|
||||
pathStr := strconv.FormatUint(uint64(rand.Uint64()), 16)
|
||||
socketPath := path.Join(gloom.tmpDir, pathStr+".sock")
|
||||
socketPath := path.Join(gloom.config.PluginDir, name, pathStr+".sock")
|
||||
|
||||
slog.Debug("Starting pluginHost", "pluginPath", pluginPath)
|
||||
|
||||
processPath := path.Join(gloom.gloomDir, "pluginHost")
|
||||
args := []string{"--plugin-path", pluginPath, "--socket-path", socketPath}
|
||||
|
||||
if gloom.config.EnableChroot {
|
||||
if err := os.MkdirAll(path.Join(gloom.config.PluginDir, name), 0755); err != nil {
|
||||
return fmt.Errorf("failed to create chroot directory: %w", err)
|
||||
}
|
||||
|
||||
args = append(args, "--chroot-dir", path.Join(gloom.config.PluginDir, name))
|
||||
}
|
||||
|
||||
files, err := os.ReadDir(path.Join(gloom.config.PluginDir, name))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read pluginDir: %w", err)
|
||||
}
|
||||
|
||||
slog.Debug("Removing dead sockets", "pluginDir", path.Join(gloom.config.PluginDir, name))
|
||||
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
// remove all dead sockets
|
||||
if strings.HasSuffix(file.Name(), ".sock") {
|
||||
if err := os.Remove(path.Join(gloom.config.PluginDir, name, file.Name())); err != nil {
|
||||
return fmt.Errorf("failed to remove socket: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cmd := exec.Command(processPath, args...)
|
||||
|
||||
stderrPipe, err := cmd.StderrPipe()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get stderr pipe: %w", err)
|
||||
}
|
||||
|
||||
reader := bufio.NewReader(stderrPipe)
|
||||
readTimeout := time.After(30 * time.Second)
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
return fmt.Errorf("failed to start pluginHost: %w", err)
|
||||
}
|
||||
process := cmd.Process
|
||||
|
||||
reader := bufio.NewReader(stderrPipe)
|
||||
readTimeout := time.After(30 * time.Second)
|
||||
|
||||
select {
|
||||
case <-readTimeout:
|
||||
_ = process.Signal(os.Interrupt)
|
||||
@@ -318,6 +416,8 @@ func (gloom *GLoom) RegisterPlugin(pluginPath string, name string, domains []str
|
||||
}
|
||||
}
|
||||
|
||||
slog.Debug("Creating proxy", "socketPath", socketPath)
|
||||
|
||||
proxy, err := sentinel.NewDeploymentProxy(socketPath, NewUnixSocketTransport)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -368,10 +468,7 @@ func (gloom *GLoom) RegisterPlugin(pluginPath string, name string, domains []str
|
||||
return nil
|
||||
}
|
||||
|
||||
// removes plugin from proxy and kills the process
|
||||
func (gloom *GLoom) DeletePlugin(pluginName string) error {
|
||||
slog.Debug("Deleting plugin", "pluginName", pluginName)
|
||||
|
||||
func (gloom *GLoom) StopPlugin(pluginName string) error {
|
||||
pluginHost, ok := gloom.plugins.Load(pluginName)
|
||||
if !ok {
|
||||
return fmt.Errorf("plugin not found")
|
||||
@@ -389,6 +486,17 @@ func (gloom *GLoom) DeletePlugin(pluginName string) error {
|
||||
|
||||
gloom.plugins.Delete(pluginName)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// removes plugin from proxy and kills the process
|
||||
func (gloom *GLoom) DeletePlugin(pluginName string) error {
|
||||
slog.Debug("Deleting plugin", "pluginName", pluginName)
|
||||
|
||||
if err := gloom.StopPlugin(pluginName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pluginPath string
|
||||
if err := gloom.DB.QueryRow("SELECT path FROM plugins WHERE name = ?", pluginName).Scan(&pluginPath); err != nil {
|
||||
return fmt.Errorf("failed to get plugin path: %w", err)
|
||||
@@ -457,14 +565,15 @@ func (rpc *GloomRPC) ListPlugins(_ struct{}, reply *[]PluginData) error {
|
||||
}
|
||||
|
||||
type PluginUpload struct {
|
||||
Name string `json:"name"`
|
||||
Domains []string `json:"domains"`
|
||||
Data []byte `json:"data"`
|
||||
FileName string `json:"fileName"`
|
||||
Name string `json:"name"`
|
||||
Domains []string `json:"domains"`
|
||||
Data []byte `json:"data"`
|
||||
}
|
||||
|
||||
func (rpc *GloomRPC) UploadPlugin(plugin PluginUpload, reply *string) error {
|
||||
for _, preloadPlugin := range rpc.gloom.config.PreloadPlugins {
|
||||
if plugin.Name == preloadPlugin.File {
|
||||
if plugin.Name == preloadPlugin.Name {
|
||||
*reply = "Plugin is preloaded"
|
||||
return nil
|
||||
}
|
||||
@@ -497,7 +606,7 @@ func (rpc *GloomRPC) UploadPlugin(plugin PluginUpload, reply *string) error {
|
||||
defer deploymentLock.Unlock(plugin.Name)
|
||||
|
||||
slog.Info("Uploading plugin", "plugin", plugin.Name, "domains", plugin.Domains)
|
||||
pluginPath, err := filepath.Abs(filepath.Join(rpc.gloom.config.PluginDir, (plugin.Name + ".so")))
|
||||
pluginPath, err := filepath.Abs(filepath.Join(rpc.gloom.config.PluginDir, plugin.Name, plugin.FileName))
|
||||
if err != nil {
|
||||
*reply = "Plugin upload failed"
|
||||
return err
|
||||
@@ -567,6 +676,11 @@ func (rpc *GloomRPC) UploadPlugin(plugin PluginUpload, reply *string) error {
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Join(rpc.gloom.config.PluginDir, plugin.Name), 0755); err != nil {
|
||||
*reply = "Plugin upload failed"
|
||||
return err
|
||||
}
|
||||
|
||||
// regardless of if plugin exists or not, we'll upload the file since this could be an update to an existing plugin
|
||||
if err := os.WriteFile(pluginPath, plugin.Data, 0644); err != nil {
|
||||
*reply = "Plugin upload failed"
|
||||
@@ -605,7 +719,7 @@ func (rpc *GloomRPC) UploadPlugin(plugin PluginUpload, reply *string) error {
|
||||
|
||||
func (rpc *GloomRPC) DeletePlugin(pluginName string, reply *string) error {
|
||||
for _, preloadPlugin := range rpc.gloom.config.PreloadPlugins {
|
||||
if pluginName == preloadPlugin.File {
|
||||
if pluginName == preloadPlugin.Name {
|
||||
*reply = "Plugin is preloaded"
|
||||
return nil
|
||||
}
|
||||
@@ -644,8 +758,10 @@ func main() {
|
||||
|
||||
gloom, err := NewGloom(proxyManager)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
fmt.Printf("Failed to create GLoom: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer gloom.Cleanup()
|
||||
|
||||
if err := gloom.StartRPCServer(); err != nil {
|
||||
panic("Failed to start RPC server: " + err.Error())
|
||||
|
||||
@@ -10,12 +10,15 @@ import (
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"plugin"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/gofiber/fiber/v3"
|
||||
)
|
||||
|
||||
var pluginPath string
|
||||
var socketPath string
|
||||
var chrootDir string
|
||||
|
||||
// Idk why I originally wrote this solution when stderr is literally just the best solution for me, but this
|
||||
// makes the pluginHost more generally useful outside of GLoom, so I'm keeping it
|
||||
@@ -47,13 +50,13 @@ func main() {
|
||||
|
||||
if router != nil {
|
||||
if err := router.Shutdown(); err != nil {
|
||||
log.Printf("Error shutting down router: %v", err)
|
||||
log.Printf("Error: error shutting down router: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if listener != nil {
|
||||
if err := listener.Close(); err != nil {
|
||||
log.Printf("Error closing listener: %v", err)
|
||||
log.Printf("Error: error closing listener: %v", err)
|
||||
}
|
||||
|
||||
os.Remove(socketPath)
|
||||
@@ -70,10 +73,11 @@ func main() {
|
||||
fs.StringVar(&pluginPath, "plugin-path", "", "Path to the plugin")
|
||||
fs.StringVar(&socketPath, "socket-path", "", "Path to the socket")
|
||||
fs.StringVar(&controlPath, "control-path", "", "Path to the control socket")
|
||||
fs.StringVar(&chrootDir, "chroot-dir", "", "Path to the chroot directory")
|
||||
|
||||
err := fs.Parse(os.Args[1:])
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error parsing arguments: %v", err)
|
||||
fmt.Fprintf(os.Stderr, "Error: error parsing arguments: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Args = fs.Args()
|
||||
@@ -98,13 +102,13 @@ func main() {
|
||||
|
||||
controlListener, err := net.Listen("unix", controlPath)
|
||||
if err != nil {
|
||||
log.Fatalf("Error listening on control socket: %v", err)
|
||||
log.Fatalf("Error: error listening on control socket: %v", err)
|
||||
}
|
||||
defer controlListener.Close()
|
||||
|
||||
conn, err := controlListener.Accept()
|
||||
if err != nil {
|
||||
log.Printf("Error accepting control connection: %v", err)
|
||||
log.Printf("Error: error accepting control connection: %v", err)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
@@ -120,13 +124,13 @@ func main() {
|
||||
os.Remove(controlPath)
|
||||
}
|
||||
if !ok {
|
||||
log.Printf("Control connection is not a writer")
|
||||
log.Printf("Error: control connection is not a writer")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := os.Stat(socketPath); err == nil {
|
||||
Print("Error: Socket %s already exists", socketPath)
|
||||
Print("Error: socket %s already exists", socketPath)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -136,6 +140,60 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if chrootDir != "" {
|
||||
if !strings.HasPrefix(socketPath, chrootDir) {
|
||||
Print("Error: socket path is not in the chroot directory, but chroot is enabled, and therefore the socket cannot be used by the plugin. This is a GLoom bug, please report it.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// we are chrooting and changing to nobody to "sandbox" the plugin
|
||||
// nobodyUser, err := user.Lookup("nobody")
|
||||
// if err != nil {
|
||||
// Print("Error: failed to get nobody user: %w", err)
|
||||
// }
|
||||
|
||||
// nobodyUid, err := strconv.Atoi(nobodyUser.Uid)
|
||||
// if err != nil {
|
||||
// Print("Error: failed to parse nobody uid: %w", err)
|
||||
// }
|
||||
|
||||
// nobodyGid, err := strconv.Atoi(nobodyUser.Gid)
|
||||
// if err != nil {
|
||||
// Print("Error: failed to parse nobody gid: %w", err)
|
||||
// }
|
||||
|
||||
pluginData, err := os.ReadFile(realPluginPath)
|
||||
if err != nil {
|
||||
Print("Error: failed to read plugin: %w", err)
|
||||
}
|
||||
|
||||
pluginFileName := filepath.Base(realPluginPath)
|
||||
|
||||
// copy the plugin to the chroot directory
|
||||
if err := os.WriteFile(filepath.Join(chrootDir, pluginFileName), pluginData, 0644); err != nil {
|
||||
Print("Error: failed to copy plugin to chroot: %w", err)
|
||||
}
|
||||
|
||||
// if err := os.Chown(chrootDir, nobodyUid, nobodyGid); err != nil {
|
||||
// Print("Error: failed to chown chroot directory: %w", err)
|
||||
// }
|
||||
|
||||
realPluginPath = "/" + pluginFileName
|
||||
socketPath = "/" + filepath.Base(socketPath)
|
||||
|
||||
if err := syscall.Chroot(chrootDir); err != nil {
|
||||
Print("Error: failed to chroot: %w", err)
|
||||
}
|
||||
|
||||
// if err := syscall.Setgid(nobodyGid); err != nil {
|
||||
// Print("Error: failed to setgid: %w", err)
|
||||
// }
|
||||
|
||||
// if err := syscall.Setuid(nobodyUid); err != nil {
|
||||
// Print("Error: failed to setuid: %w", err)
|
||||
// }
|
||||
}
|
||||
|
||||
p, err := plugin.Open(realPluginPath)
|
||||
if err != nil {
|
||||
Print("Error: could not open plugin %s: %v", realPluginPath, err)
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "zqdgr build:gloomi && zqdgr build:gloom",
|
||||
"build:pluginHost": "sh -c \"cd pluginHost; go build -ldflags '-w -s' -o ../dist/host main.go\"",
|
||||
"build:gloomi": "sh -c \"cd gloomi; zqdgr build\"",
|
||||
"build:pluginHost": "cd pluginHost; go build -ldflags '-w -s' -o ../dist/host main.go",
|
||||
"build:gloomi": "cd gloomi; zqdgr build",
|
||||
"build:gloom": "zqdgr build:pluginHost && go build -tags=gloomi -o dist/gloom",
|
||||
"build:nogloomi": "zqdgr build:pluginHost && go build -tags=!gloomi -o dist/gloom",
|
||||
"clean": "rm -rf dist && rm -rf plugin/plugin.so",
|
||||
|
||||
Reference in New Issue
Block a user