github.com/qichengzx/mattermost-server@v4.5.1-0.20180604164826-2c75247c97d0+incompatible/plugin/rpcplugin/sandbox/sandbox_linux_test.go (about) 1 // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package sandbox 5 6 import ( 7 "context" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "testing" 12 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 16 "github.com/mattermost/mattermost-server/plugin/rpcplugin/rpcplugintest" 17 ) 18 19 func TestNewProcess(t *testing.T) { 20 if err := CheckSupport(); err != nil { 21 t.Skip("sandboxing not supported:", err) 22 } 23 24 dir, err := ioutil.TempDir("", "") 25 require.NoError(t, err) 26 defer os.RemoveAll(dir) 27 28 ping := filepath.Join(dir, "ping.exe") 29 rpcplugintest.CompileGo(t, ` 30 package main 31 32 import ( 33 "crypto/rand" 34 "fmt" 35 "io/ioutil" 36 "net/http" 37 "os" 38 "os/exec" 39 "syscall" 40 41 "github.com/stretchr/testify/assert" 42 "github.com/stretchr/testify/require" 43 44 "github.com/mattermost/mattermost-server/plugin/rpcplugin" 45 ) 46 47 var failures int 48 49 type T struct {} 50 func (T) Errorf(format string, args ...interface{}) { 51 fmt.Printf(format, args...) 52 failures++ 53 } 54 func (T) FailNow() { 55 os.Exit(1) 56 } 57 58 func init() { 59 if len(os.Args) > 0 && os.Args[0] == "exitImmediately" { 60 os.Exit(0) 61 } 62 } 63 64 func main() { 65 t := &T{} 66 67 pwd, err := os.Getwd() 68 assert.NoError(t, err) 69 assert.Equal(t, "/dir", pwd) 70 71 assert.Equal(t, 0, os.Getgid(), "we should see ourselves as root") 72 assert.Equal(t, 0, os.Getuid(), "we should see ourselves as root") 73 74 f, err := ioutil.TempFile("", "") 75 require.NoError(t, err, "we should be able to create temporary files") 76 f.Close() 77 78 _, err = os.Stat("ping.exe") 79 assert.NoError(t, err, "we should be able to read files in the working directory") 80 81 buf := make([]byte, 20) 82 n, err := rand.Read(buf) 83 assert.Equal(t, 20, n) 84 assert.NoError(t, err, "we should be able to read from /dev/urandom") 85 86 f, err = os.Create("/dev/zero") 87 require.NoError(t, err, "we should be able to write to /dev/zero") 88 defer f.Close() 89 n, err = f.Write([]byte("foo")) 90 assert.Equal(t, 3, n) 91 require.NoError(t, err, "we should be able to write to /dev/zero") 92 93 f, err = os.Create("/dir/foo") 94 if f != nil { 95 defer f.Close() 96 } 97 assert.Error(t, err, "we shouldn't be able to write to this read-only mount point") 98 99 _, err = ioutil.ReadFile("/etc/resolv.conf") 100 require.NoError(t, err, "we should be able to read /etc/resolv.conf") 101 102 resp, err := http.Get("https://github.com") 103 require.NoError(t, err, "we should be able to use the network") 104 resp.Body.Close() 105 106 status, err := ioutil.ReadFile("/proc/self/status") 107 require.NoError(t, err, "we should be able to read from /proc") 108 assert.Regexp(t, status, "CapEff:\\s+0000000000000000", "we should have no effective capabilities") 109 110 require.NoError(t, os.MkdirAll("/tmp/dir2", 0755)) 111 err = syscall.Mount("/dir", "/tmp/dir2", "", syscall.MS_BIND, "") 112 assert.Equal(t, syscall.EPERM, err, "we shouldn't be allowed to mount things") 113 114 cmd := exec.Command("/proc/self/exe") 115 cmd.Args = []string{"exitImmediately"} 116 cmd.SysProcAttr = &syscall.SysProcAttr{ 117 Pdeathsig: syscall.SIGTERM, 118 } 119 assert.NoError(t, cmd.Run(), "we should be able to re-exec ourself") 120 121 cmd = exec.Command("/proc/self/exe") 122 cmd.Args = []string{"exitImmediately"} 123 cmd.SysProcAttr = &syscall.SysProcAttr{ 124 Cloneflags: syscall.CLONE_NEWNS | syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID | syscall.CLONE_NEWUSER, 125 Pdeathsig: syscall.SIGTERM, 126 } 127 assert.Error(t, cmd.Run(), "we shouldn't be able to create new namespaces anymore") 128 129 ipc, err := rpcplugin.InheritedProcessIPC() 130 require.NoError(t, err) 131 defer ipc.Close() 132 _, err = ipc.Write([]byte("ping")) 133 require.NoError(t, err) 134 135 if failures > 0 { 136 os.Exit(1) 137 } 138 } 139 `, ping) 140 141 p, ipc, err := NewProcess(context.Background(), &Configuration{ 142 MountPoints: []*MountPoint{ 143 { 144 Source: dir, 145 Destination: "/dir", 146 ReadOnly: true, 147 }, 148 }, 149 WorkingDirectory: "/dir", 150 }, "/dir/ping.exe") 151 require.NoError(t, err) 152 defer ipc.Close() 153 b := make([]byte, 10) 154 n, err := ipc.Read(b) 155 require.NoError(t, err) 156 assert.Equal(t, 4, n) 157 assert.Equal(t, "ping", string(b[:4])) 158 require.NoError(t, p.Wait()) 159 }