Some checks are pending
Security Checks / security (push) Waiting to run
验证插件配置和可执行文件在目标文件关闭前完成权限处理,覆盖文件权限与复制流程。
103 lines
2.8 KiB
Go
103 lines
2.8 KiB
Go
//go:build linux
|
|
|
|
package hooks
|
|
|
|
import (
|
|
"net"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestCopyPluginFileRejectsGrowthPastLimit(t *testing.T) {
|
|
directory := t.TempDir()
|
|
sourcePath := filepath.Join(directory, "source.json")
|
|
targetPath := filepath.Join(directory, "target.json")
|
|
if err := os.WriteFile(sourcePath, []byte(strings.Repeat("a", int(maxPluginConfigBytes)+1)), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := copyPluginFile(sourcePath, targetPath, os.Getuid(), os.Getgid(), 0600); err == nil {
|
|
t.Fatal("oversized plugin configuration was copied")
|
|
}
|
|
if _, err := os.Lstat(targetPath); !os.IsNotExist(err) {
|
|
t.Fatalf("oversized target was not removed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestPluginCopiesApplySecurityBeforeClosingTargets(t *testing.T) {
|
|
directory := t.TempDir()
|
|
configSource := filepath.Join(directory, "source.json")
|
|
configTarget := filepath.Join(directory, "target.json")
|
|
if err := os.WriteFile(configSource, []byte(`{"enabled":true}`), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := copyPluginFile(configSource, configTarget, os.Getuid(), os.Getgid(), 0600); err != nil {
|
|
t.Fatalf("copy plugin configuration: %v", err)
|
|
}
|
|
configInfo, err := os.Stat(configTarget)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if configInfo.Mode().Perm() != 0600 {
|
|
t.Fatalf("configuration mode = %o, want 0600", configInfo.Mode().Perm())
|
|
}
|
|
|
|
executableSource := filepath.Join(directory, "source-plugin")
|
|
executableTarget := filepath.Join(directory, "target-plugin")
|
|
if err := os.WriteFile(executableSource, []byte("plugin"), 0700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := copyPluginExecutable(executableSource, executableTarget, os.Getuid(), os.Getgid()); err != nil {
|
|
t.Fatalf("copy plugin executable: %v", err)
|
|
}
|
|
executableInfo, err := os.Stat(executableTarget)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if executableInfo.Mode().Perm() != 0700 {
|
|
t.Fatalf("executable mode = %o, want 0700", executableInfo.Mode().Perm())
|
|
}
|
|
}
|
|
func TestInheritedAbstractSocketRemainsReachableAcrossListenerCopy(t *testing.T) {
|
|
socketName, err := newPluginSocketName(1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
address := "@" + socketName
|
|
listener, err := net.ListenUnix("unix", &net.UnixAddr{Name: address, Net: "unix"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
file, err := listener.File()
|
|
if closeErr := listener.Close(); closeErr != nil && err == nil {
|
|
err = closeErr
|
|
}
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer file.Close()
|
|
|
|
inherited, err := net.FileListener(file)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer inherited.Close()
|
|
accepted := make(chan error, 1)
|
|
go func() {
|
|
conn, acceptErr := inherited.Accept()
|
|
if acceptErr == nil {
|
|
_ = conn.Close()
|
|
}
|
|
accepted <- acceptErr
|
|
}()
|
|
conn, err := net.Dial("unix", address)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_ = conn.Close()
|
|
if err := <-accepted; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|