From 1e5c432e1029601a664454388ae366ef69618d62 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Mon, 25 Jun 2018 12:33:13 -0700 Subject: MM-10702 Moving plugins to use hashicorp go-plugin. (#8978) * Moving plugins to use hashicorp go-plugin. * Tweaks from feedback. --- plugin/rpcplugin/sandbox/main_test.go | 18 - plugin/rpcplugin/sandbox/sandbox.go | 34 -- plugin/rpcplugin/sandbox/sandbox_linux.go | 488 ------------------------ plugin/rpcplugin/sandbox/sandbox_linux_test.go | 159 -------- plugin/rpcplugin/sandbox/sandbox_other.go | 22 -- plugin/rpcplugin/sandbox/sandbox_test.go | 25 -- plugin/rpcplugin/sandbox/seccomp_linux.go | 178 --------- plugin/rpcplugin/sandbox/seccomp_linux_amd64.go | 301 --------------- plugin/rpcplugin/sandbox/seccomp_linux_other.go | 10 - plugin/rpcplugin/sandbox/seccomp_linux_test.go | 210 ---------- plugin/rpcplugin/sandbox/supervisor.go | 33 -- plugin/rpcplugin/sandbox/supervisor_test.go | 18 - 12 files changed, 1496 deletions(-) delete mode 100644 plugin/rpcplugin/sandbox/main_test.go delete mode 100644 plugin/rpcplugin/sandbox/sandbox.go delete mode 100644 plugin/rpcplugin/sandbox/sandbox_linux.go delete mode 100644 plugin/rpcplugin/sandbox/sandbox_linux_test.go delete mode 100644 plugin/rpcplugin/sandbox/sandbox_other.go delete mode 100644 plugin/rpcplugin/sandbox/sandbox_test.go delete mode 100644 plugin/rpcplugin/sandbox/seccomp_linux.go delete mode 100644 plugin/rpcplugin/sandbox/seccomp_linux_amd64.go delete mode 100644 plugin/rpcplugin/sandbox/seccomp_linux_other.go delete mode 100644 plugin/rpcplugin/sandbox/seccomp_linux_test.go delete mode 100644 plugin/rpcplugin/sandbox/supervisor.go delete mode 100644 plugin/rpcplugin/sandbox/supervisor_test.go (limited to 'plugin/rpcplugin/sandbox') diff --git a/plugin/rpcplugin/sandbox/main_test.go b/plugin/rpcplugin/sandbox/main_test.go deleted file mode 100644 index 4be4a42af..000000000 --- a/plugin/rpcplugin/sandbox/main_test.go +++ /dev/null @@ -1,18 +0,0 @@ -package sandbox - -import ( - "testing" - - "github.com/mattermost/mattermost-server/mlog" -) - -func TestMain(t *testing.T) { - // Setup a global logger to catch tests logging outside of app context - // The global logger will be stomped by apps initalizing but that's fine for testing. Ideally this won't happen. - mlog.InitGlobalLogger(mlog.NewLogger(&mlog.LoggerConfiguration{ - EnableConsole: true, - ConsoleJson: true, - ConsoleLevel: "error", - EnableFile: false, - })) -} diff --git a/plugin/rpcplugin/sandbox/sandbox.go b/plugin/rpcplugin/sandbox/sandbox.go deleted file mode 100644 index 96eff02dd..000000000 --- a/plugin/rpcplugin/sandbox/sandbox.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package sandbox - -import ( - "context" - "io" - - "github.com/mattermost/mattermost-server/plugin/rpcplugin" -) - -type MountPoint struct { - Source string - Destination string - Type string - ReadOnly bool -} - -type Configuration struct { - MountPoints []*MountPoint - WorkingDirectory string -} - -// NewProcess is like rpcplugin.NewProcess, but launches the process in a sandbox. -func NewProcess(ctx context.Context, config *Configuration, path string) (rpcplugin.Process, io.ReadWriteCloser, error) { - return newProcess(ctx, config, path) -} - -// CheckSupport inspects the platform and environment to determine whether or not there are any -// expected issues with sandboxing. If nil is returned, sandboxing should be used. -func CheckSupport() error { - return checkSupport() -} diff --git a/plugin/rpcplugin/sandbox/sandbox_linux.go b/plugin/rpcplugin/sandbox/sandbox_linux.go deleted file mode 100644 index beb00995d..000000000 --- a/plugin/rpcplugin/sandbox/sandbox_linux.go +++ /dev/null @@ -1,488 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package sandbox - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "os" - "os/exec" - "path/filepath" - "syscall" - "unsafe" - - "github.com/pkg/errors" - "golang.org/x/sys/unix" - - "github.com/mattermost/mattermost-server/plugin/rpcplugin" -) - -func init() { - if len(os.Args) < 4 || os.Args[0] != "sandbox.runProcess" { - return - } - - var config Configuration - if err := json.Unmarshal([]byte(os.Args[1]), &config); err != nil { - fmt.Println(err.Error()) - os.Exit(1) - } - if err := runProcess(&config, os.Args[2], os.Args[3]); err != nil { - if eerr, ok := err.(*exec.ExitError); ok { - if status, ok := eerr.Sys().(syscall.WaitStatus); ok { - os.Exit(status.ExitStatus()) - } - } - fmt.Println(err.Error()) - os.Exit(1) - } - os.Exit(0) -} - -func systemMountPoints() (points []*MountPoint) { - points = append(points, &MountPoint{ - Source: "proc", - Destination: "/proc", - Type: "proc", - }, &MountPoint{ - Source: "/dev/null", - Destination: "/dev/null", - }, &MountPoint{ - Source: "/dev/zero", - Destination: "/dev/zero", - }, &MountPoint{ - Source: "/dev/full", - Destination: "/dev/full", - }) - - readOnly := []string{ - "/dev/random", - "/dev/urandom", - "/etc/resolv.conf", - "/lib", - "/lib32", - "/lib64", - "/usr/lib", - "/usr/lib32", - "/usr/lib64", - "/etc/ca-certificates", - "/etc/ssl/certs", - "/system/etc/security/cacerts", - "/usr/local/share/certs", - "/etc/pki/tls/certs", - "/etc/openssl/certs", - "/etc/ssl/ca-bundle.pem", - "/etc/pki/tls/cacert.pem", - "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", - } - - for _, v := range []string{"SSL_CERT_FILE", "SSL_CERT_DIR"} { - if path := os.Getenv(v); path != "" { - readOnly = append(readOnly, path) - } - } - - for _, point := range readOnly { - points = append(points, &MountPoint{ - Source: point, - Destination: point, - ReadOnly: true, - }) - } - - return -} - -func runProcess(config *Configuration, path, root string) error { - if err := syscall.Mount("", "/", "", syscall.MS_PRIVATE|syscall.MS_REC, ""); err != nil { - return errors.Wrapf(err, "unable to make root private") - } - - if err := mountMountPoints(root, systemMountPoints()); err != nil { - return errors.Wrapf(err, "unable to mount sandbox system mount points") - } - - if err := mountMountPoints(root, config.MountPoints); err != nil { - return errors.Wrapf(err, "unable to mount sandbox config mount points") - } - - if err := pivotRoot(root); err != nil { - return errors.Wrapf(err, "unable to pivot sandbox root") - } - - if err := os.Mkdir("/tmp", 0755); err != nil { - return errors.Wrapf(err, "unable to create /tmp") - } - - if config.WorkingDirectory != "" { - if err := os.Chdir(config.WorkingDirectory); err != nil { - return errors.Wrapf(err, "unable to set working directory") - } - } - - if err := dropInheritableCapabilities(); err != nil { - return errors.Wrapf(err, "unable to drop inheritable capabilities") - } - - if err := enableSeccompFilter(); err != nil { - return errors.Wrapf(err, "unable to enable seccomp filter") - } - - return runExecutable(path) -} - -func mountMountPoint(root string, mountPoint *MountPoint) error { - isDir := true - if mountPoint.Type == "" { - stat, err := os.Lstat(mountPoint.Source) - if err != nil { - return nil - } - if (stat.Mode() & os.ModeSymlink) != 0 { - if path, err := filepath.EvalSymlinks(mountPoint.Source); err == nil { - newMountPoint := *mountPoint - newMountPoint.Source = path - if err := mountMountPoint(root, &newMountPoint); err != nil { - return errors.Wrapf(err, "unable to mount symbolic link target: "+mountPoint.Source) - } - return nil - } - } - isDir = stat.IsDir() - } - - target := filepath.Join(root, mountPoint.Destination) - - if isDir { - if err := os.MkdirAll(target, 0755); err != nil { - return errors.Wrapf(err, "unable to create directory: "+target) - } - } else { - if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil { - return errors.Wrapf(err, "unable to create directory: "+target) - } - f, err := os.Create(target) - if err != nil { - return errors.Wrapf(err, "unable to create file: "+target) - } - f.Close() - } - - flags := uintptr(syscall.MS_NOSUID | syscall.MS_NODEV) - if mountPoint.Type == "" { - flags |= syscall.MS_BIND - } - if mountPoint.ReadOnly { - flags |= syscall.MS_RDONLY - } - - if err := syscall.Mount(mountPoint.Source, target, mountPoint.Type, flags, ""); err != nil { - return errors.Wrapf(err, "unable to mount "+mountPoint.Source) - } - - if (flags & syscall.MS_BIND) != 0 { - // If this was a bind mount, our other flags actually got silently ignored during the above syscall: - // - // If mountflags includes MS_BIND [...] The remaining bits in the mountflags argument are - // also ignored, with the exception of MS_REC. - // - // Furthermore, remounting will fail if we attempt to unset a bit that was inherited from - // the mount's parent: - // - // The mount(2) flags MS_RDONLY, MS_NOSUID, MS_NOEXEC, and the "atime" flags - // (MS_NOATIME, MS_NODIRATIME, MS_RELATIME) settings become locked when propagated from - // a more privileged to a less privileged mount namespace, and may not be changed in the - // less privileged mount namespace. - // - // So we need to get the actual flags, add our new ones, then do a remount if needed. - var stats syscall.Statfs_t - if err := syscall.Statfs(target, &stats); err != nil { - return errors.Wrap(err, "unable to get mount flags for target: "+target) - } - const lockedFlagsMask = unix.MS_RDONLY | unix.MS_NOSUID | unix.MS_NOEXEC | unix.MS_NOATIME | unix.MS_NODIRATIME | unix.MS_RELATIME - lockedFlags := uintptr(stats.Flags & lockedFlagsMask) - if lockedFlags != ((flags | lockedFlags) & lockedFlagsMask) { - if err := syscall.Mount("", target, "", flags|lockedFlags|syscall.MS_REMOUNT, ""); err != nil { - return errors.Wrapf(err, "unable to remount "+mountPoint.Source) - } - } - } - - return nil -} - -func mountMountPoints(root string, mountPoints []*MountPoint) error { - for _, mountPoint := range mountPoints { - if err := mountMountPoint(root, mountPoint); err != nil { - return err - } - } - - return nil -} - -func pivotRoot(newRoot string) error { - if err := syscall.Mount(newRoot, newRoot, "", syscall.MS_BIND|syscall.MS_REC, ""); err != nil { - return errors.Wrapf(err, "unable to mount new root") - } - - prevRoot := filepath.Join(newRoot, ".prev_root") - - if err := os.MkdirAll(prevRoot, 0700); err != nil { - return errors.Wrapf(err, "unable to create directory for previous root") - } - - if err := syscall.PivotRoot(newRoot, prevRoot); err != nil { - return errors.Wrapf(err, "syscall error") - } - - if err := os.Chdir("/"); err != nil { - return errors.Wrapf(err, "unable to change directory") - } - - prevRoot = "/.prev_root" - - if err := syscall.Unmount(prevRoot, syscall.MNT_DETACH); err != nil { - return errors.Wrapf(err, "unable to unmount previous root") - } - - if err := os.RemoveAll(prevRoot); err != nil { - return errors.Wrapf(err, "unable to remove previous root directory") - } - - return nil -} - -func dropInheritableCapabilities() error { - type capHeader struct { - version uint32 - pid int32 - } - - type capData struct { - effective uint32 - permitted uint32 - inheritable uint32 - } - - var hdr capHeader - var data [2]capData - - if _, _, errno := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(&hdr)), 0, 0); errno != 0 { - return errors.Wrapf(syscall.Errno(errno), "unable to get capabilities version") - } - - if _, _, errno := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(&hdr)), uintptr(unsafe.Pointer(&data[0])), 0); errno != 0 { - return errors.Wrapf(syscall.Errno(errno), "unable to get capabilities") - } - - data[0].inheritable = 0 - data[1].inheritable = 0 - if _, _, errno := syscall.Syscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(&hdr)), uintptr(unsafe.Pointer(&data[0])), 0); errno != 0 { - return errors.Wrapf(syscall.Errno(errno), "unable to set inheritable capabilities") - } - - for i := 0; i < 64; i++ { - if _, _, errno := syscall.Syscall(syscall.SYS_PRCTL, syscall.PR_CAPBSET_DROP, uintptr(i), 0); errno != 0 && errno != syscall.EINVAL { - return errors.Wrapf(syscall.Errno(errno), "unable to drop bounding set capability") - } - } - - return nil -} - -func enableSeccompFilter() error { - return EnableSeccompFilter(SeccompFilter(NATIVE_AUDIT_ARCH, AllowedSyscalls)) -} - -func runExecutable(path string) error { - childFiles := []*os.File{ - os.NewFile(3, ""), os.NewFile(4, ""), - } - defer childFiles[0].Close() - defer childFiles[1].Close() - - cmd := exec.Command(path) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.ExtraFiles = childFiles - cmd.SysProcAttr = &syscall.SysProcAttr{ - Pdeathsig: syscall.SIGTERM, - } - - if err := cmd.Run(); err != nil { - return err - } - - return nil -} - -type process struct { - command *exec.Cmd - root string -} - -func newProcess(ctx context.Context, config *Configuration, path string) (pOut rpcplugin.Process, rwcOut io.ReadWriteCloser, errOut error) { - configJSON, err := json.Marshal(config) - if err != nil { - return nil, nil, err - } - - ipc, childFiles, err := rpcplugin.NewIPC() - if err != nil { - return nil, nil, err - } - defer childFiles[0].Close() - defer childFiles[1].Close() - - root, err := ioutil.TempDir("", "") - if err != nil { - return nil, nil, err - } - defer func() { - if errOut != nil { - os.RemoveAll(root) - } - }() - - cmd := exec.CommandContext(ctx, "/proc/self/exe") - cmd.Args = []string{"sandbox.runProcess", string(configJSON), path, root} - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.ExtraFiles = childFiles - - cmd.SysProcAttr = &syscall.SysProcAttr{ - Cloneflags: syscall.CLONE_NEWNS | syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID | syscall.CLONE_NEWUSER, - Pdeathsig: syscall.SIGTERM, - GidMappings: []syscall.SysProcIDMap{ - { - ContainerID: 0, - HostID: os.Getgid(), - Size: 1, - }, - }, - UidMappings: []syscall.SysProcIDMap{ - { - ContainerID: 0, - HostID: os.Getuid(), - Size: 1, - }, - }, - } - - err = cmd.Start() - if err != nil { - ipc.Close() - return nil, nil, err - } - - return &process{ - command: cmd, - root: root, - }, ipc, nil -} - -func (p *process) Wait() error { - defer os.RemoveAll(p.root) - return p.command.Wait() -} - -func init() { - if len(os.Args) < 2 || os.Args[0] != "sandbox.checkSupportInNamespace" { - return - } - - if err := checkSupportInNamespace(os.Args[1]); err != nil { - fmt.Fprintf(os.Stderr, "%v", err.Error()) - os.Exit(1) - } - - os.Exit(0) -} - -func checkSupportInNamespace(root string) error { - if err := syscall.Mount("", "/", "", syscall.MS_PRIVATE|syscall.MS_REC, ""); err != nil { - return errors.Wrapf(err, "unable to make root private") - } - - if err := mountMountPoints(root, systemMountPoints()); err != nil { - return errors.Wrapf(err, "unable to mount sandbox system mount points") - } - - if err := pivotRoot(root); err != nil { - return errors.Wrapf(err, "unable to pivot sandbox root") - } - - if err := dropInheritableCapabilities(); err != nil { - return errors.Wrapf(err, "unable to drop inheritable capabilities") - } - - if err := enableSeccompFilter(); err != nil { - return errors.Wrapf(err, "unable to enable seccomp filter") - } - - if f, err := os.Create(os.DevNull); err != nil { - return errors.Wrapf(err, "unable to open os.DevNull") - } else { - defer f.Close() - if _, err = f.Write([]byte("foo")); err != nil { - return errors.Wrapf(err, "unable to write to os.DevNull") - } - } - - return nil -} - -func checkSupport() error { - if AllowedSyscalls == nil { - return fmt.Errorf("unsupported architecture") - } - - stderr := &bytes.Buffer{} - - root, err := ioutil.TempDir("", "") - if err != nil { - return err - } - defer os.RemoveAll(root) - - cmd := exec.Command("/proc/self/exe") - cmd.Args = []string{"sandbox.checkSupportInNamespace", root} - cmd.Stderr = stderr - cmd.SysProcAttr = &syscall.SysProcAttr{ - Cloneflags: syscall.CLONE_NEWNS | syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID | syscall.CLONE_NEWUSER, - Pdeathsig: syscall.SIGTERM, - GidMappings: []syscall.SysProcIDMap{ - { - ContainerID: 0, - HostID: os.Getgid(), - Size: 1, - }, - }, - UidMappings: []syscall.SysProcIDMap{ - { - ContainerID: 0, - HostID: os.Getuid(), - Size: 1, - }, - }, - } - - if err := cmd.Start(); err != nil { - return errors.Wrapf(err, "unable to create user namespace") - } - - if err := cmd.Wait(); err != nil { - if _, ok := err.(*exec.ExitError); ok { - return errors.Wrapf(fmt.Errorf("%v", stderr.String()), "unable to prepare namespace") - } - return errors.Wrapf(err, "unable to prepare namespace") - } - - return nil -} diff --git a/plugin/rpcplugin/sandbox/sandbox_linux_test.go b/plugin/rpcplugin/sandbox/sandbox_linux_test.go deleted file mode 100644 index 2bcbf0c57..000000000 --- a/plugin/rpcplugin/sandbox/sandbox_linux_test.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package sandbox - -import ( - "context" - "io/ioutil" - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/mattermost/mattermost-server/plugin/rpcplugin/rpcplugintest" -) - -func TestNewProcess(t *testing.T) { - if err := CheckSupport(); err != nil { - t.Skip("sandboxing not supported:", err) - } - - dir, err := ioutil.TempDir("", "") - require.NoError(t, err) - defer os.RemoveAll(dir) - - ping := filepath.Join(dir, "ping.exe") - rpcplugintest.CompileGo(t, ` - package main - - import ( - "crypto/rand" - "fmt" - "io/ioutil" - "net/http" - "os" - "os/exec" - "syscall" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/mattermost/mattermost-server/plugin/rpcplugin" - ) - - var failures int - - type T struct {} - func (T) Errorf(format string, args ...interface{}) { - fmt.Printf(format, args...) - failures++ - } - func (T) FailNow() { - os.Exit(1) - } - - func init() { - if len(os.Args) > 0 && os.Args[0] == "exitImmediately" { - os.Exit(0) - } - } - - func main() { - t := &T{} - - pwd, err := os.Getwd() - assert.NoError(t, err) - assert.Equal(t, "/dir", pwd) - - assert.Equal(t, 0, os.Getgid(), "we should see ourselves as root") - assert.Equal(t, 0, os.Getuid(), "we should see ourselves as root") - - f, err := ioutil.TempFile("", "") - require.NoError(t, err, "we should be able to create temporary files") - f.Close() - - _, err = os.Stat("ping.exe") - assert.NoError(t, err, "we should be able to read files in the working directory") - - buf := make([]byte, 20) - n, err := rand.Read(buf) - assert.Equal(t, 20, n) - assert.NoError(t, err, "we should be able to read from /dev/urandom") - - f, err = os.Create("/dev/zero") - require.NoError(t, err, "we should be able to write to /dev/zero") - defer f.Close() - n, err = f.Write([]byte("foo")) - assert.Equal(t, 3, n) - require.NoError(t, err, "we should be able to write to /dev/zero") - - f, err = os.Create("/dir/foo") - if f != nil { - defer f.Close() - } - assert.Error(t, err, "we shouldn't be able to write to this read-only mount point") - - _, err = ioutil.ReadFile("/etc/resolv.conf") - require.NoError(t, err, "we should be able to read /etc/resolv.conf") - - resp, err := http.Get("https://github.com") - require.NoError(t, err, "we should be able to use the network") - resp.Body.Close() - - status, err := ioutil.ReadFile("/proc/self/status") - require.NoError(t, err, "we should be able to read from /proc") - assert.Regexp(t, status, "CapEff:\\s+0000000000000000", "we should have no effective capabilities") - - require.NoError(t, os.MkdirAll("/tmp/dir2", 0755)) - err = syscall.Mount("/dir", "/tmp/dir2", "", syscall.MS_BIND, "") - assert.Equal(t, syscall.EPERM, err, "we shouldn't be allowed to mount things") - - cmd := exec.Command("/proc/self/exe") - cmd.Args = []string{"exitImmediately"} - cmd.SysProcAttr = &syscall.SysProcAttr{ - Pdeathsig: syscall.SIGTERM, - } - assert.NoError(t, cmd.Run(), "we should be able to re-exec ourself") - - cmd = exec.Command("/proc/self/exe") - cmd.Args = []string{"exitImmediately"} - cmd.SysProcAttr = &syscall.SysProcAttr{ - Cloneflags: syscall.CLONE_NEWNS | syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID | syscall.CLONE_NEWUSER, - Pdeathsig: syscall.SIGTERM, - } - assert.Error(t, cmd.Run(), "we shouldn't be able to create new namespaces anymore") - - ipc, err := rpcplugin.InheritedProcessIPC() - require.NoError(t, err) - defer ipc.Close() - _, err = ipc.Write([]byte("ping")) - require.NoError(t, err) - - if failures > 0 { - os.Exit(1) - } - } - `, ping) - - p, ipc, err := NewProcess(context.Background(), &Configuration{ - MountPoints: []*MountPoint{ - { - Source: dir, - Destination: "/dir", - ReadOnly: true, - }, - }, - WorkingDirectory: "/dir", - }, "/dir/ping.exe") - require.NoError(t, err) - defer ipc.Close() - b := make([]byte, 10) - n, err := ipc.Read(b) - require.NoError(t, err) - assert.Equal(t, 4, n) - assert.Equal(t, "ping", string(b[:4])) - require.NoError(t, p.Wait()) -} diff --git a/plugin/rpcplugin/sandbox/sandbox_other.go b/plugin/rpcplugin/sandbox/sandbox_other.go deleted file mode 100644 index 3889ecdcc..000000000 --- a/plugin/rpcplugin/sandbox/sandbox_other.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -// +build !linux - -package sandbox - -import ( - "context" - "fmt" - "io" - - "github.com/mattermost/mattermost-server/plugin/rpcplugin" -) - -func newProcess(ctx context.Context, config *Configuration, path string) (rpcplugin.Process, io.ReadWriteCloser, error) { - return nil, nil, checkSupport() -} - -func checkSupport() error { - return fmt.Errorf("sandboxing is not supported on this platform") -} diff --git a/plugin/rpcplugin/sandbox/sandbox_test.go b/plugin/rpcplugin/sandbox/sandbox_test.go deleted file mode 100644 index e0149e28d..000000000 --- a/plugin/rpcplugin/sandbox/sandbox_test.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package sandbox - -import ( - "testing" -) - -// TestCheckSupport is here for debugging purposes and has no assertions. You can quickly test -// sandboxing support with various systems by compiling the test executable and running this test on -// your target systems. For example, with docker, executed from the root of the repo: -// -// docker run --rm -it -w /go/src/github.com/mattermost/mattermost-server -// -v $(pwd):/go/src/github.com/mattermost/mattermost-server golang:1.9 -// go test -c ./plugin/rpcplugin -// -// docker run --rm -it --privileged -w /opt/mattermost -// -v $(pwd):/opt/mattermost centos:6 -// ./rpcplugin.test --test.v --test.run TestCheckSupport -func TestCheckSupport(t *testing.T) { - if err := CheckSupport(); err != nil { - t.Log(err.Error()) - } -} diff --git a/plugin/rpcplugin/sandbox/seccomp_linux.go b/plugin/rpcplugin/sandbox/seccomp_linux.go deleted file mode 100644 index afe86e90a..000000000 --- a/plugin/rpcplugin/sandbox/seccomp_linux.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package sandbox - -import ( - "syscall" - "unsafe" - - "github.com/pkg/errors" - "golang.org/x/net/bpf" - "golang.org/x/sys/unix" -) - -const ( - SECCOMP_RET_ALLOW = 0x7fff0000 - SECCOMP_RET_ERRNO = 0x00050000 -) - -const ( - EM_X86_64 = 62 - - __AUDIT_ARCH_64BIT = 0x80000000 - __AUDIT_ARCH_LE = 0x40000000 - - AUDIT_ARCH_X86_64 = EM_X86_64 | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE - - nrSize = 4 - archOffset = nrSize - ipOffset = archOffset + 4 - argsOffset = ipOffset + 8 -) - -type SeccompCondition interface { - Filter(littleEndian bool, skipFalseSentinel uint8) []bpf.Instruction -} - -func seccompArgLowWord(arg int, littleEndian bool) uint32 { - offset := uint32(argsOffset + arg*8) - if !littleEndian { - offset += 4 - } - return offset -} - -func seccompArgHighWord(arg int, littleEndian bool) uint32 { - offset := uint32(argsOffset + arg*8) - if littleEndian { - offset += 4 - } - return offset -} - -type SeccompArgHasNoBits struct { - Arg int - Mask uint64 -} - -func (c SeccompArgHasNoBits) Filter(littleEndian bool, skipFalseSentinel uint8) []bpf.Instruction { - return []bpf.Instruction{ - bpf.LoadAbsolute{Off: seccompArgHighWord(c.Arg, littleEndian), Size: 4}, - bpf.JumpIf{Cond: bpf.JumpBitsSet, Val: uint32(c.Mask >> 32), SkipTrue: skipFalseSentinel}, - bpf.LoadAbsolute{Off: seccompArgLowWord(c.Arg, littleEndian), Size: 4}, - bpf.JumpIf{Cond: bpf.JumpBitsSet, Val: uint32(c.Mask), SkipTrue: skipFalseSentinel}, - } -} - -type SeccompArgHasAnyBit struct { - Arg int - Mask uint64 -} - -func (c SeccompArgHasAnyBit) Filter(littleEndian bool, skipFalseSentinel uint8) []bpf.Instruction { - return []bpf.Instruction{ - bpf.LoadAbsolute{Off: seccompArgHighWord(c.Arg, littleEndian), Size: 4}, - bpf.JumpIf{Cond: bpf.JumpBitsSet, Val: uint32(c.Mask >> 32), SkipTrue: 2}, - bpf.LoadAbsolute{Off: seccompArgLowWord(c.Arg, littleEndian), Size: 4}, - bpf.JumpIf{Cond: bpf.JumpBitsSet, Val: uint32(c.Mask), SkipFalse: skipFalseSentinel}, - } -} - -type SeccompArgEquals struct { - Arg int - Value uint64 -} - -func (c SeccompArgEquals) Filter(littleEndian bool, skipFalseSentinel uint8) []bpf.Instruction { - return []bpf.Instruction{ - bpf.LoadAbsolute{Off: seccompArgHighWord(c.Arg, littleEndian), Size: 4}, - bpf.JumpIf{Cond: bpf.JumpEqual, Val: uint32(c.Value >> 32), SkipFalse: skipFalseSentinel}, - bpf.LoadAbsolute{Off: seccompArgLowWord(c.Arg, littleEndian), Size: 4}, - bpf.JumpIf{Cond: bpf.JumpEqual, Val: uint32(c.Value), SkipFalse: skipFalseSentinel}, - } -} - -type SeccompConditions struct { - All []SeccompCondition -} - -type SeccompSyscall struct { - Syscall uint32 - Any []SeccompConditions -} - -func SeccompFilter(arch uint32, allowedSyscalls []SeccompSyscall) (filter []bpf.Instruction) { - filter = append(filter, - bpf.LoadAbsolute{Off: archOffset, Size: 4}, - bpf.JumpIf{Cond: bpf.JumpEqual, Val: arch, SkipTrue: 1}, - bpf.RetConstant{Val: uint32(SECCOMP_RET_ERRNO | unix.EPERM)}, - ) - - filter = append(filter, bpf.LoadAbsolute{Off: 0, Size: nrSize}) - for _, s := range allowedSyscalls { - if s.Any != nil { - syscallStart := len(filter) - filter = append(filter, bpf.Instruction(nil)) - for _, cs := range s.Any { - anyStart := len(filter) - for _, c := range cs.All { - filter = append(filter, c.Filter((arch&__AUDIT_ARCH_LE) != 0, 255)...) - } - filter = append(filter, bpf.RetConstant{Val: SECCOMP_RET_ALLOW}) - for i := anyStart; i < len(filter); i++ { - if jump, ok := filter[i].(bpf.JumpIf); ok { - if len(filter)-i-1 > 255 { - panic("condition too long") - } - if jump.SkipFalse == 255 { - jump.SkipFalse = uint8(len(filter) - i - 1) - } - if jump.SkipTrue == 255 { - jump.SkipTrue = uint8(len(filter) - i - 1) - } - filter[i] = jump - } - } - } - filter = append(filter, bpf.RetConstant{Val: uint32(SECCOMP_RET_ERRNO | unix.EPERM)}) - if len(filter)-syscallStart-1 > 255 { - panic("conditions too long") - } - filter[syscallStart] = bpf.JumpIf{Cond: bpf.JumpEqual, Val: uint32(s.Syscall), SkipFalse: uint8(len(filter) - syscallStart - 1)} - } else { - filter = append(filter, - bpf.JumpIf{Cond: bpf.JumpEqual, Val: uint32(s.Syscall), SkipFalse: 1}, - bpf.RetConstant{Val: SECCOMP_RET_ALLOW}, - ) - } - } - - return append(filter, bpf.RetConstant{Val: uint32(SECCOMP_RET_ERRNO | unix.EPERM)}) -} - -func EnableSeccompFilter(filter []bpf.Instruction) error { - assembled, err := bpf.Assemble(filter) - if err != nil { - return errors.Wrapf(err, "unable to assemble filter") - } - - sockFilter := make([]unix.SockFilter, len(filter)) - for i, instruction := range assembled { - sockFilter[i].Code = instruction.Op - sockFilter[i].Jt = instruction.Jt - sockFilter[i].Jf = instruction.Jf - sockFilter[i].K = instruction.K - } - - prog := unix.SockFprog{ - Len: uint16(len(sockFilter)), - Filter: &sockFilter[0], - } - - if _, _, errno := syscall.Syscall(syscall.SYS_PRCTL, unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, uintptr(unsafe.Pointer(&prog))); errno != 0 { - return errors.Wrapf(syscall.Errno(errno), "syscall error") - } - - return nil -} diff --git a/plugin/rpcplugin/sandbox/seccomp_linux_amd64.go b/plugin/rpcplugin/sandbox/seccomp_linux_amd64.go deleted file mode 100644 index 7338ebbe0..000000000 --- a/plugin/rpcplugin/sandbox/seccomp_linux_amd64.go +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package sandbox - -import ( - "golang.org/x/sys/unix" -) - -const NATIVE_AUDIT_ARCH = AUDIT_ARCH_X86_64 - -var AllowedSyscalls = []SeccompSyscall{ - {Syscall: unix.SYS_ACCEPT}, - {Syscall: unix.SYS_ACCEPT4}, - {Syscall: unix.SYS_ACCESS}, - {Syscall: unix.SYS_ADJTIMEX}, - {Syscall: unix.SYS_ALARM}, - {Syscall: unix.SYS_ARCH_PRCTL}, - {Syscall: unix.SYS_BIND}, - {Syscall: unix.SYS_BRK}, - {Syscall: unix.SYS_CAPGET}, - {Syscall: unix.SYS_CAPSET}, - {Syscall: unix.SYS_CHDIR}, - {Syscall: unix.SYS_CHMOD}, - {Syscall: unix.SYS_CHOWN}, - {Syscall: unix.SYS_CLOCK_GETRES}, - {Syscall: unix.SYS_CLOCK_GETTIME}, - {Syscall: unix.SYS_CLOCK_NANOSLEEP}, - { - Syscall: unix.SYS_CLONE, - Any: []SeccompConditions{{ - All: []SeccompCondition{SeccompArgHasNoBits{ - Arg: 0, - Mask: unix.CLONE_NEWCGROUP | unix.CLONE_NEWIPC | unix.CLONE_NEWNET | unix.CLONE_NEWNS | unix.CLONE_NEWPID | unix.CLONE_NEWUSER | unix.CLONE_NEWUTS, - }}, - }}, - }, - {Syscall: unix.SYS_CLOSE}, - {Syscall: unix.SYS_CONNECT}, - {Syscall: unix.SYS_COPY_FILE_RANGE}, - {Syscall: unix.SYS_CREAT}, - {Syscall: unix.SYS_DUP}, - {Syscall: unix.SYS_DUP2}, - {Syscall: unix.SYS_DUP3}, - {Syscall: unix.SYS_EPOLL_CREATE}, - {Syscall: unix.SYS_EPOLL_CREATE1}, - {Syscall: unix.SYS_EPOLL_CTL}, - {Syscall: unix.SYS_EPOLL_CTL_OLD}, - {Syscall: unix.SYS_EPOLL_PWAIT}, - {Syscall: unix.SYS_EPOLL_WAIT}, - {Syscall: unix.SYS_EPOLL_WAIT_OLD}, - {Syscall: unix.SYS_EVENTFD}, - {Syscall: unix.SYS_EVENTFD2}, - {Syscall: unix.SYS_EXECVE}, - {Syscall: unix.SYS_EXECVEAT}, - {Syscall: unix.SYS_EXIT}, - {Syscall: unix.SYS_EXIT_GROUP}, - {Syscall: unix.SYS_FACCESSAT}, - {Syscall: unix.SYS_FADVISE64}, - {Syscall: unix.SYS_FALLOCATE}, - {Syscall: unix.SYS_FANOTIFY_MARK}, - {Syscall: unix.SYS_FCHDIR}, - {Syscall: unix.SYS_FCHMOD}, - {Syscall: unix.SYS_FCHMODAT}, - {Syscall: unix.SYS_FCHOWN}, - {Syscall: unix.SYS_FCHOWNAT}, - {Syscall: unix.SYS_FCNTL}, - {Syscall: unix.SYS_FDATASYNC}, - {Syscall: unix.SYS_FGETXATTR}, - {Syscall: unix.SYS_FLISTXATTR}, - {Syscall: unix.SYS_FLOCK}, - {Syscall: unix.SYS_FORK}, - {Syscall: unix.SYS_FREMOVEXATTR}, - {Syscall: unix.SYS_FSETXATTR}, - {Syscall: unix.SYS_FSTAT}, - {Syscall: unix.SYS_FSTATFS}, - {Syscall: unix.SYS_FSYNC}, - {Syscall: unix.SYS_FTRUNCATE}, - {Syscall: unix.SYS_FUTEX}, - {Syscall: unix.SYS_FUTIMESAT}, - {Syscall: unix.SYS_GETCPU}, - {Syscall: unix.SYS_GETCWD}, - {Syscall: unix.SYS_GETDENTS}, - {Syscall: unix.SYS_GETDENTS64}, - {Syscall: unix.SYS_GETEGID}, - {Syscall: unix.SYS_GETEUID}, - {Syscall: unix.SYS_GETGID}, - {Syscall: unix.SYS_GETGROUPS}, - {Syscall: unix.SYS_GETITIMER}, - {Syscall: unix.SYS_GETPEERNAME}, - {Syscall: unix.SYS_GETPGID}, - {Syscall: unix.SYS_GETPGRP}, - {Syscall: unix.SYS_GETPID}, - {Syscall: unix.SYS_GETPPID}, - {Syscall: unix.SYS_GETPRIORITY}, - {Syscall: unix.SYS_GETRANDOM}, - {Syscall: unix.SYS_GETRESGID}, - {Syscall: unix.SYS_GETRESUID}, - {Syscall: unix.SYS_GETRLIMIT}, - {Syscall: unix.SYS_GET_ROBUST_LIST}, - {Syscall: unix.SYS_GETRUSAGE}, - {Syscall: unix.SYS_GETSID}, - {Syscall: unix.SYS_GETSOCKNAME}, - {Syscall: unix.SYS_GETSOCKOPT}, - {Syscall: unix.SYS_GET_THREAD_AREA}, - {Syscall: unix.SYS_GETTID}, - {Syscall: unix.SYS_GETTIMEOFDAY}, - {Syscall: unix.SYS_GETUID}, - {Syscall: unix.SYS_GETXATTR}, - {Syscall: unix.SYS_INOTIFY_ADD_WATCH}, - {Syscall: unix.SYS_INOTIFY_INIT}, - {Syscall: unix.SYS_INOTIFY_INIT1}, - {Syscall: unix.SYS_INOTIFY_RM_WATCH}, - {Syscall: unix.SYS_IO_CANCEL}, - {Syscall: unix.SYS_IOCTL}, - {Syscall: unix.SYS_IO_DESTROY}, - {Syscall: unix.SYS_IO_GETEVENTS}, - {Syscall: unix.SYS_IOPRIO_GET}, - {Syscall: unix.SYS_IOPRIO_SET}, - {Syscall: unix.SYS_IO_SETUP}, - {Syscall: unix.SYS_IO_SUBMIT}, - {Syscall: unix.SYS_KILL}, - {Syscall: unix.SYS_LCHOWN}, - {Syscall: unix.SYS_LGETXATTR}, - {Syscall: unix.SYS_LINK}, - {Syscall: unix.SYS_LINKAT}, - {Syscall: unix.SYS_LISTEN}, - {Syscall: unix.SYS_LISTXATTR}, - {Syscall: unix.SYS_LLISTXATTR}, - {Syscall: unix.SYS_LREMOVEXATTR}, - {Syscall: unix.SYS_LSEEK}, - {Syscall: unix.SYS_LSETXATTR}, - {Syscall: unix.SYS_LSTAT}, - {Syscall: unix.SYS_MADVISE}, - {Syscall: unix.SYS_MEMFD_CREATE}, - {Syscall: unix.SYS_MINCORE}, - {Syscall: unix.SYS_MKDIR}, - {Syscall: unix.SYS_MKDIRAT}, - {Syscall: unix.SYS_MKNOD}, - {Syscall: unix.SYS_MKNODAT}, - {Syscall: unix.SYS_MLOCK}, - {Syscall: unix.SYS_MLOCK2}, - {Syscall: unix.SYS_MLOCKALL}, - {Syscall: unix.SYS_MMAP}, - {Syscall: unix.SYS_MODIFY_LDT}, - {Syscall: unix.SYS_MPROTECT}, - {Syscall: unix.SYS_MQ_GETSETATTR}, - {Syscall: unix.SYS_MQ_NOTIFY}, - {Syscall: unix.SYS_MQ_OPEN}, - {Syscall: unix.SYS_MQ_TIMEDRECEIVE}, - {Syscall: unix.SYS_MQ_TIMEDSEND}, - {Syscall: unix.SYS_MQ_UNLINK}, - {Syscall: unix.SYS_MREMAP}, - {Syscall: unix.SYS_MSGCTL}, - {Syscall: unix.SYS_MSGGET}, - {Syscall: unix.SYS_MSGRCV}, - {Syscall: unix.SYS_MSGSND}, - {Syscall: unix.SYS_MSYNC}, - {Syscall: unix.SYS_MUNLOCK}, - {Syscall: unix.SYS_MUNLOCKALL}, - {Syscall: unix.SYS_MUNMAP}, - {Syscall: unix.SYS_NANOSLEEP}, - {Syscall: unix.SYS_NEWFSTATAT}, - {Syscall: unix.SYS_OPEN}, - {Syscall: unix.SYS_OPENAT}, - {Syscall: unix.SYS_PAUSE}, - { - Syscall: unix.SYS_PERSONALITY, - Any: []SeccompConditions{ - {All: []SeccompCondition{SeccompArgEquals{Arg: 0, Value: 0}}}, - {All: []SeccompCondition{SeccompArgEquals{Arg: 0, Value: 8}}}, - {All: []SeccompCondition{SeccompArgEquals{Arg: 0, Value: 0x20000}}}, - {All: []SeccompCondition{SeccompArgEquals{Arg: 0, Value: 0x20008}}}, - {All: []SeccompCondition{SeccompArgEquals{Arg: 0, Value: 0xffffffff}}}, - }, - }, - {Syscall: unix.SYS_PIPE}, - {Syscall: unix.SYS_PIPE2}, - {Syscall: unix.SYS_POLL}, - {Syscall: unix.SYS_PPOLL}, - {Syscall: unix.SYS_PRCTL}, - {Syscall: unix.SYS_PREAD64}, - {Syscall: unix.SYS_PREADV}, - {Syscall: unix.SYS_PREADV2}, - {Syscall: unix.SYS_PRLIMIT64}, - {Syscall: unix.SYS_PSELECT6}, - {Syscall: unix.SYS_PWRITE64}, - {Syscall: unix.SYS_PWRITEV}, - {Syscall: unix.SYS_PWRITEV2}, - {Syscall: unix.SYS_READ}, - {Syscall: unix.SYS_READAHEAD}, - {Syscall: unix.SYS_READLINK}, - {Syscall: unix.SYS_READLINKAT}, - {Syscall: unix.SYS_READV}, - {Syscall: unix.SYS_RECVFROM}, - {Syscall: unix.SYS_RECVMMSG}, - {Syscall: unix.SYS_RECVMSG}, - {Syscall: unix.SYS_REMAP_FILE_PAGES}, - {Syscall: unix.SYS_REMOVEXATTR}, - {Syscall: unix.SYS_RENAME}, - {Syscall: unix.SYS_RENAMEAT}, - {Syscall: unix.SYS_RENAMEAT2}, - {Syscall: unix.SYS_RESTART_SYSCALL}, - {Syscall: unix.SYS_RMDIR}, - {Syscall: unix.SYS_RT_SIGACTION}, - {Syscall: unix.SYS_RT_SIGPENDING}, - {Syscall: unix.SYS_RT_SIGPROCMASK}, - {Syscall: unix.SYS_RT_SIGQUEUEINFO}, - {Syscall: unix.SYS_RT_SIGRETURN}, - {Syscall: unix.SYS_RT_SIGSUSPEND}, - {Syscall: unix.SYS_RT_SIGTIMEDWAIT}, - {Syscall: unix.SYS_RT_TGSIGQUEUEINFO}, - {Syscall: unix.SYS_SCHED_GETAFFINITY}, - {Syscall: unix.SYS_SCHED_GETATTR}, - {Syscall: unix.SYS_SCHED_GETPARAM}, - {Syscall: unix.SYS_SCHED_GET_PRIORITY_MAX}, - {Syscall: unix.SYS_SCHED_GET_PRIORITY_MIN}, - {Syscall: unix.SYS_SCHED_GETSCHEDULER}, - {Syscall: unix.SYS_SCHED_RR_GET_INTERVAL}, - {Syscall: unix.SYS_SCHED_SETAFFINITY}, - {Syscall: unix.SYS_SCHED_SETATTR}, - {Syscall: unix.SYS_SCHED_SETPARAM}, - {Syscall: unix.SYS_SCHED_SETSCHEDULER}, - {Syscall: unix.SYS_SCHED_YIELD}, - {Syscall: unix.SYS_SECCOMP}, - {Syscall: unix.SYS_SELECT}, - {Syscall: unix.SYS_SEMCTL}, - {Syscall: unix.SYS_SEMGET}, - {Syscall: unix.SYS_SEMOP}, - {Syscall: unix.SYS_SEMTIMEDOP}, - {Syscall: unix.SYS_SENDFILE}, - {Syscall: unix.SYS_SENDMMSG}, - {Syscall: unix.SYS_SENDMSG}, - {Syscall: unix.SYS_SENDTO}, - {Syscall: unix.SYS_SETFSGID}, - {Syscall: unix.SYS_SETFSUID}, - {Syscall: unix.SYS_SETGID}, - {Syscall: unix.SYS_SETGROUPS}, - {Syscall: unix.SYS_SETITIMER}, - {Syscall: unix.SYS_SETPGID}, - {Syscall: unix.SYS_SETPRIORITY}, - {Syscall: unix.SYS_SETREGID}, - {Syscall: unix.SYS_SETRESGID}, - {Syscall: unix.SYS_SETRESUID}, - {Syscall: unix.SYS_SETREUID}, - {Syscall: unix.SYS_SETRLIMIT}, - {Syscall: unix.SYS_SET_ROBUST_LIST}, - {Syscall: unix.SYS_SETSID}, - {Syscall: unix.SYS_SETSOCKOPT}, - {Syscall: unix.SYS_SET_THREAD_AREA}, - {Syscall: unix.SYS_SET_TID_ADDRESS}, - {Syscall: unix.SYS_SETUID}, - {Syscall: unix.SYS_SETXATTR}, - {Syscall: unix.SYS_SHMAT}, - {Syscall: unix.SYS_SHMCTL}, - {Syscall: unix.SYS_SHMDT}, - {Syscall: unix.SYS_SHMGET}, - {Syscall: unix.SYS_SHUTDOWN}, - {Syscall: unix.SYS_SIGALTSTACK}, - {Syscall: unix.SYS_SIGNALFD}, - {Syscall: unix.SYS_SIGNALFD4}, - {Syscall: unix.SYS_SOCKET}, - {Syscall: unix.SYS_SOCKETPAIR}, - {Syscall: unix.SYS_SPLICE}, - {Syscall: unix.SYS_STAT}, - {Syscall: unix.SYS_STATFS}, - {Syscall: unix.SYS_SYMLINK}, - {Syscall: unix.SYS_SYMLINKAT}, - {Syscall: unix.SYS_SYNC}, - {Syscall: unix.SYS_SYNC_FILE_RANGE}, - {Syscall: unix.SYS_SYNCFS}, - {Syscall: unix.SYS_SYSINFO}, - {Syscall: unix.SYS_SYSLOG}, - {Syscall: unix.SYS_TEE}, - {Syscall: unix.SYS_TGKILL}, - {Syscall: unix.SYS_TIME}, - {Syscall: unix.SYS_TIMER_CREATE}, - {Syscall: unix.SYS_TIMER_DELETE}, - {Syscall: unix.SYS_TIMERFD_CREATE}, - {Syscall: unix.SYS_TIMERFD_GETTIME}, - {Syscall: unix.SYS_TIMERFD_SETTIME}, - {Syscall: unix.SYS_TIMER_GETOVERRUN}, - {Syscall: unix.SYS_TIMER_GETTIME}, - {Syscall: unix.SYS_TIMER_SETTIME}, - {Syscall: unix.SYS_TIMES}, - {Syscall: unix.SYS_TKILL}, - {Syscall: unix.SYS_TRUNCATE}, - {Syscall: unix.SYS_UMASK}, - {Syscall: unix.SYS_UNAME}, - {Syscall: unix.SYS_UNLINK}, - {Syscall: unix.SYS_UNLINKAT}, - {Syscall: unix.SYS_UTIME}, - {Syscall: unix.SYS_UTIMENSAT}, - {Syscall: unix.SYS_UTIMES}, - {Syscall: unix.SYS_VFORK}, - {Syscall: unix.SYS_VMSPLICE}, - {Syscall: unix.SYS_WAIT4}, - {Syscall: unix.SYS_WAITID}, - {Syscall: unix.SYS_WRITE}, - {Syscall: unix.SYS_WRITEV}, -} diff --git a/plugin/rpcplugin/sandbox/seccomp_linux_other.go b/plugin/rpcplugin/sandbox/seccomp_linux_other.go deleted file mode 100644 index 5573943cd..000000000 --- a/plugin/rpcplugin/sandbox/seccomp_linux_other.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -// +build linux,!amd64 - -package sandbox - -const NATIVE_AUDIT_ARCH = 0 - -var AllowedSyscalls []SeccompSyscall diff --git a/plugin/rpcplugin/sandbox/seccomp_linux_test.go b/plugin/rpcplugin/sandbox/seccomp_linux_test.go deleted file mode 100644 index 46fe38fe0..000000000 --- a/plugin/rpcplugin/sandbox/seccomp_linux_test.go +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package sandbox - -import ( - "encoding/binary" - "syscall" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "golang.org/x/net/bpf" -) - -func seccompData(nr int32, arch uint32, ip uint64, args ...uint64) []byte { - var buf [64]byte - binary.BigEndian.PutUint32(buf[0:], uint32(nr)) - binary.BigEndian.PutUint32(buf[4:], arch) - binary.BigEndian.PutUint64(buf[8:], ip) - for i := 0; i < 6 && i < len(args); i++ { - binary.BigEndian.PutUint64(buf[16+i*8:], args[i]) - } - return buf[:] -} - -func TestSeccompFilter(t *testing.T) { - for name, tc := range map[string]struct { - Filter []bpf.Instruction - Data []byte - Expected bool - }{ - "Allowed": { - Filter: SeccompFilter(0xf00, []SeccompSyscall{ - {Syscall: syscall.SYS_READ}, - {Syscall: syscall.SYS_WRITE}, - }), - Data: seccompData(syscall.SYS_READ, 0xf00, 0), - Expected: true, - }, - "AllFail": { - Filter: SeccompFilter(0xf00, []SeccompSyscall{ - { - Syscall: syscall.SYS_READ, - Any: []SeccompConditions{ - {All: []SeccompCondition{ - &SeccompArgHasAnyBit{Arg: 0, Mask: 2}, - &SeccompArgHasAnyBit{Arg: 1, Mask: 2}, - &SeccompArgHasAnyBit{Arg: 2, Mask: 2}, - &SeccompArgHasAnyBit{Arg: 3, Mask: 2}, - }}, - }, - }, - {Syscall: syscall.SYS_WRITE}, - }), - Data: seccompData(syscall.SYS_READ, 0xf00, 0, 1, 2, 3, 4), - Expected: false, - }, - "AllPass": { - Filter: SeccompFilter(0xf00, []SeccompSyscall{ - { - Syscall: syscall.SYS_READ, - Any: []SeccompConditions{ - {All: []SeccompCondition{ - &SeccompArgHasAnyBit{Arg: 0, Mask: 7}, - &SeccompArgHasAnyBit{Arg: 1, Mask: 7}, - &SeccompArgHasAnyBit{Arg: 2, Mask: 7}, - &SeccompArgHasAnyBit{Arg: 3, Mask: 7}, - }}, - }, - }, - {Syscall: syscall.SYS_WRITE}, - }), - Data: seccompData(syscall.SYS_READ, 0xf00, 0, 1, 2, 3, 4), - Expected: true, - }, - "AnyFail": { - Filter: SeccompFilter(0xf00, []SeccompSyscall{ - { - Syscall: syscall.SYS_READ, - Any: []SeccompConditions{ - {All: []SeccompCondition{&SeccompArgHasAnyBit{Arg: 0, Mask: 8}}}, - {All: []SeccompCondition{&SeccompArgHasAnyBit{Arg: 1, Mask: 8}}}, - {All: []SeccompCondition{&SeccompArgHasAnyBit{Arg: 2, Mask: 8}}}, - {All: []SeccompCondition{&SeccompArgHasAnyBit{Arg: 3, Mask: 8}}}, - }, - }, - {Syscall: syscall.SYS_WRITE}, - }), - Data: seccompData(syscall.SYS_READ, 0xf00, 0, 1, 2, 3, 4), - Expected: false, - }, - "AnyPass": { - Filter: SeccompFilter(0xf00, []SeccompSyscall{ - { - Syscall: syscall.SYS_READ, - Any: []SeccompConditions{ - {All: []SeccompCondition{&SeccompArgHasAnyBit{Arg: 0, Mask: 2}}}, - {All: []SeccompCondition{&SeccompArgHasAnyBit{Arg: 1, Mask: 2}}}, - {All: []SeccompCondition{&SeccompArgHasAnyBit{Arg: 2, Mask: 2}}}, - {All: []SeccompCondition{&SeccompArgHasAnyBit{Arg: 3, Mask: 2}}}, - }, - }, - {Syscall: syscall.SYS_WRITE}, - }), - Data: seccompData(syscall.SYS_READ, 0xf00, 0, 1, 2, 3, 4), - Expected: true, - }, - "BadArch": { - Filter: SeccompFilter(0xf00, []SeccompSyscall{ - {Syscall: syscall.SYS_READ}, - {Syscall: syscall.SYS_WRITE}, - }), - Data: seccompData(syscall.SYS_MOUNT, 0xf01, 0), - Expected: false, - }, - "BadSyscall": { - Filter: SeccompFilter(0xf00, []SeccompSyscall{ - {Syscall: syscall.SYS_READ}, - {Syscall: syscall.SYS_WRITE}, - }), - Data: seccompData(syscall.SYS_MOUNT, 0xf00, 0), - Expected: false, - }, - } { - t.Run(name, func(t *testing.T) { - vm, err := bpf.NewVM(tc.Filter) - require.NoError(t, err) - result, err := vm.Run(tc.Data) - require.NoError(t, err) - if tc.Expected { - assert.Equal(t, SECCOMP_RET_ALLOW, result) - } else { - assert.Equal(t, int(SECCOMP_RET_ERRNO|syscall.EPERM), result) - } - }) - } -} - -func TestSeccompFilter_Conditions(t *testing.T) { - for name, tc := range map[string]struct { - Condition SeccompCondition - Args []uint64 - Expected bool - }{ - "ArgHasAnyBitFail": { - Condition: SeccompArgHasAnyBit{Arg: 0, Mask: 0x0004}, - Args: []uint64{0x0400008000}, - Expected: false, - }, - "ArgHasAnyBitPass1": { - Condition: SeccompArgHasAnyBit{Arg: 0, Mask: 0x400000004}, - Args: []uint64{0x8000008004}, - Expected: true, - }, - "ArgHasAnyBitPass2": { - Condition: SeccompArgHasAnyBit{Arg: 0, Mask: 0x400000004}, - Args: []uint64{0x8400008000}, - Expected: true, - }, - "ArgHasNoBitsFail1": { - Condition: SeccompArgHasNoBits{Arg: 0, Mask: 0x1100000011}, - Args: []uint64{0x0000008007}, - Expected: false, - }, - "ArgHasNoBitsFail2": { - Condition: SeccompArgHasNoBits{Arg: 0, Mask: 0x1100000011}, - Args: []uint64{0x0700008000}, - Expected: false, - }, - "ArgHasNoBitsPass": { - Condition: SeccompArgHasNoBits{Arg: 0, Mask: 0x400000004}, - Args: []uint64{0x8000008000}, - Expected: true, - }, - "ArgEqualsPass": { - Condition: SeccompArgEquals{Arg: 0, Value: 0x123456789ABCDEF}, - Args: []uint64{0x123456789ABCDEF}, - Expected: true, - }, - "ArgEqualsFail1": { - Condition: SeccompArgEquals{Arg: 0, Value: 0x123456789ABCDEF}, - Args: []uint64{0x023456789ABCDEF}, - Expected: false, - }, - "ArgEqualsFail2": { - Condition: SeccompArgEquals{Arg: 0, Value: 0x123456789ABCDEF}, - Args: []uint64{0x123456789ABCDE0}, - Expected: false, - }, - } { - t.Run(name, func(t *testing.T) { - filter := SeccompFilter(0xf00, []SeccompSyscall{ - { - Syscall: 1, - Any: []SeccompConditions{{All: []SeccompCondition{tc.Condition}}}, - }, - }) - vm, err := bpf.NewVM(filter) - require.NoError(t, err) - result, err := vm.Run(seccompData(1, 0xf00, 0, tc.Args...)) - require.NoError(t, err) - if tc.Expected { - assert.Equal(t, SECCOMP_RET_ALLOW, result) - } else { - assert.Equal(t, int(SECCOMP_RET_ERRNO|syscall.EPERM), result) - } - }) - } -} diff --git a/plugin/rpcplugin/sandbox/supervisor.go b/plugin/rpcplugin/sandbox/supervisor.go deleted file mode 100644 index 0e63954fd..000000000 --- a/plugin/rpcplugin/sandbox/supervisor.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package sandbox - -import ( - "context" - "fmt" - "io" - "path/filepath" - "strings" - - "github.com/mattermost/mattermost-server/model" - "github.com/mattermost/mattermost-server/plugin" - "github.com/mattermost/mattermost-server/plugin/rpcplugin" -) - -func SupervisorProvider(bundle *model.BundleInfo) (plugin.Supervisor, error) { - return rpcplugin.SupervisorWithNewProcessFunc(bundle, func(ctx context.Context) (rpcplugin.Process, io.ReadWriteCloser, error) { - executable := filepath.Clean(filepath.Join(".", bundle.Manifest.Backend.Executable)) - if strings.HasPrefix(executable, "..") { - return nil, nil, fmt.Errorf("invalid backend executable") - } - return NewProcess(ctx, &Configuration{ - MountPoints: []*MountPoint{{ - Source: bundle.Path, - Destination: "/plugin", - ReadOnly: true, - }}, - WorkingDirectory: "/plugin", - }, filepath.Join("/plugin", executable)) - }) -} diff --git a/plugin/rpcplugin/sandbox/supervisor_test.go b/plugin/rpcplugin/sandbox/supervisor_test.go deleted file mode 100644 index 245185dd5..000000000 --- a/plugin/rpcplugin/sandbox/supervisor_test.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package sandbox - -import ( - "testing" - - "github.com/mattermost/mattermost-server/plugin/rpcplugin/rpcplugintest" -) - -func TestSupervisorProvider(t *testing.T) { - if err := CheckSupport(); err != nil { - t.Skip("sandboxing not supported:", err) - } - - rpcplugintest.TestSupervisorProvider(t, SupervisorProvider) -} -- cgit v1.2.3-1-g7c22