github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/cmd/snap/cmd_userd_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 // +build !darwin 3 4 /* 5 * Copyright (C) 2016-2019 Canonical Ltd 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 3 as 9 * published by the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 package main_test 22 23 import ( 24 "fmt" 25 "net" 26 "net/http" 27 "os" 28 "os/user" 29 "path" 30 "path/filepath" 31 "strings" 32 "syscall" 33 "time" 34 35 . "gopkg.in/check.v1" 36 37 snap "github.com/snapcore/snapd/cmd/snap" 38 "github.com/snapcore/snapd/dirs" 39 "github.com/snapcore/snapd/logger" 40 "github.com/snapcore/snapd/osutil" 41 "github.com/snapcore/snapd/testutil" 42 "github.com/snapcore/snapd/usersession/autostart" 43 ) 44 45 type userdSuite struct { 46 BaseSnapSuite 47 testutil.DBusTest 48 49 agentSocketPath string 50 } 51 52 var _ = Suite(&userdSuite{}) 53 54 func (s *userdSuite) SetUpTest(c *C) { 55 s.BaseSnapSuite.SetUpTest(c) 56 s.DBusTest.SetUpTest(c) 57 58 _, restore := logger.MockLogger() 59 s.AddCleanup(restore) 60 61 xdgRuntimeDir := fmt.Sprintf("%s/%d", dirs.XdgRuntimeDirBase, os.Getuid()) 62 c.Assert(os.MkdirAll(xdgRuntimeDir, 0700), IsNil) 63 s.agentSocketPath = fmt.Sprintf("%s/snapd-session-agent.socket", xdgRuntimeDir) 64 } 65 66 func (s *userdSuite) TearDownTest(c *C) { 67 s.BaseSnapSuite.TearDownTest(c) 68 s.DBusTest.TearDownTest(c) 69 } 70 71 func (s *userdSuite) TestUserdBadCommandline(c *C) { 72 _, err := snap.Parser(snap.Client()).ParseArgs([]string{"userd", "extra-arg"}) 73 c.Assert(err, ErrorMatches, "too many arguments for command") 74 } 75 76 type mockSignal struct{} 77 78 func (m *mockSignal) String() string { 79 return "<test signal>" 80 } 81 82 func (m *mockSignal) Signal() {} 83 84 func (s *userdSuite) TestUserdDBus(c *C) { 85 sigCh := make(chan os.Signal, 1) 86 sigStopCalls := 0 87 88 restore := snap.MockSignalNotify(func(sig ...os.Signal) (chan os.Signal, func()) { 89 c.Assert(sig, DeepEquals, []os.Signal{syscall.SIGINT, syscall.SIGTERM}) 90 return sigCh, func() { sigStopCalls++ } 91 }) 92 defer restore() 93 94 go func() { 95 myPid := os.Getpid() 96 97 defer func() { 98 sigCh <- &mockSignal{} 99 }() 100 101 names := map[string]bool{ 102 "io.snapcraft.Launcher": false, 103 "io.snapcraft.Settings": false, 104 } 105 for i := 0; i < 1000; i++ { 106 seenCount := 0 107 for name, seen := range names { 108 if seen { 109 seenCount++ 110 continue 111 } 112 pid, err := testutil.DBusGetConnectionUnixProcessID(s.SessionBus, name) 113 c.Logf("name: %v pid: %v err: %v", name, pid, err) 114 if pid == myPid { 115 names[name] = true 116 seenCount++ 117 } 118 } 119 if seenCount == len(names) { 120 return 121 } 122 time.Sleep(10 * time.Millisecond) 123 } 124 c.Fatalf("not all names have appeared on the bus: %v", names) 125 }() 126 127 rest, err := snap.Parser(snap.Client()).ParseArgs([]string{"userd"}) 128 c.Assert(err, IsNil) 129 c.Check(rest, DeepEquals, []string{}) 130 c.Check(strings.ToLower(s.Stdout()), Equals, "exiting on <test signal>.\n") 131 c.Check(sigStopCalls, Equals, 1) 132 } 133 134 func (s *userdSuite) makeAgentClient() *http.Client { 135 transport := &http.Transport{ 136 Dial: func(_, _ string) (net.Conn, error) { 137 return net.Dial("unix", s.agentSocketPath) 138 }, 139 DisableKeepAlives: true, 140 } 141 return &http.Client{Transport: transport} 142 } 143 144 func (s *userdSuite) TestSessionAgentSocket(c *C) { 145 sigCh := make(chan os.Signal, 1) 146 sigStopCalls := 0 147 148 restore := snap.MockSignalNotify(func(sig ...os.Signal) (chan os.Signal, func()) { 149 c.Assert(sig, DeepEquals, []os.Signal{syscall.SIGINT, syscall.SIGTERM}) 150 return sigCh, func() { sigStopCalls++ } 151 }) 152 defer restore() 153 154 go func() { 155 defer func() { 156 sigCh <- &mockSignal{} 157 }() 158 159 // Wait for command to create socket file 160 for i := 0; i < 1000; i++ { 161 if osutil.FileExists(s.agentSocketPath) { 162 break 163 } 164 time.Sleep(10 * time.Millisecond) 165 } 166 167 // Check that agent functions 168 client := s.makeAgentClient() 169 response, err := client.Get("http://localhost/v1/session-info") 170 c.Assert(err, IsNil) 171 defer response.Body.Close() 172 c.Check(response.StatusCode, Equals, 200) 173 }() 174 175 rest, err := snap.Parser(snap.Client()).ParseArgs([]string{"userd", "--agent"}) 176 c.Assert(err, IsNil) 177 c.Check(rest, DeepEquals, []string{}) 178 c.Check(strings.ToLower(s.Stdout()), Equals, "exiting on <test signal>.\n") 179 c.Check(sigStopCalls, Equals, 1) 180 } 181 182 func (s *userdSuite) TestSignalNotify(c *C) { 183 ch, stop := snap.SignalNotify(syscall.SIGUSR1) 184 defer stop() 185 go func() { 186 myPid := os.Getpid() 187 me, err := os.FindProcess(myPid) 188 c.Assert(err, IsNil) 189 err = me.Signal(syscall.SIGUSR1) 190 c.Assert(err, IsNil) 191 }() 192 select { 193 case sig := <-ch: 194 c.Assert(sig, Equals, syscall.SIGUSR1) 195 case <-time.After(5 * time.Second): 196 c.Fatal("signal not received within 5s") 197 } 198 } 199 200 func (s *userdSuite) TestAutostartSessionAppsRestrictsPermissions(c *C) { 201 userDir := path.Join(c.MkDir(), "home") 202 mockUserCurrent := func() (*user.User, error) { 203 return &user.User{HomeDir: userDir}, nil 204 } 205 r := snap.MockUserCurrent(mockUserCurrent) 206 defer r() 207 208 r = autostart.MockUserCurrent(mockUserCurrent) 209 defer r() 210 211 // first make the "snap" dir permissive with 0755 perms 212 err := os.MkdirAll(filepath.Join(userDir, "snap"), 0755) 213 c.Assert(err, IsNil) 214 215 // make sure the perms are as we expect them if somehow the dir already 216 // existed, MkdirAll wouldn't have changed the perms 217 st, err := os.Stat(filepath.Join(userDir, "snap")) 218 c.Assert(err, IsNil) 219 c.Assert(st.Mode()&os.ModePerm, Equals, os.FileMode(0755)) 220 221 // run autostart 222 args, err := snap.Parser(snap.Client()).ParseArgs([]string{"userd", "--autostart"}) 223 c.Assert(err, IsNil) 224 c.Assert(args, DeepEquals, []string{}) 225 226 // make sure that the directory was restricted 227 st, err = os.Stat(filepath.Join(userDir, "snap")) 228 c.Assert(err, IsNil) 229 c.Assert(st.Mode()&os.ModePerm, Equals, os.FileMode(0700)) 230 } 231 232 func (s *userdSuite) TestAutostartSessionAppsLogsWhenItCannotRestrictPermissions(c *C) { 233 userDir := path.Join(c.MkDir(), "home") 234 mockUserCurrent := func() (*user.User, error) { 235 return &user.User{HomeDir: userDir}, nil 236 } 237 r := snap.MockUserCurrent(mockUserCurrent) 238 defer r() 239 240 r = autostart.MockUserCurrent(mockUserCurrent) 241 defer r() 242 243 r = snap.MockOsChmod(func(name string, mode os.FileMode) error { 244 c.Assert(name, Equals, filepath.Join(userDir, "snap")) 245 c.Assert(mode, Equals, os.FileMode(0700)) 246 247 return fmt.Errorf("cannot os.Chmod because the test says so") 248 }) 249 defer r() 250 251 // run autostart 252 args, err := snap.Parser(snap.Client()).ParseArgs([]string{"userd", "--autostart"}) 253 c.Assert(err, IsNil) 254 c.Assert(args, DeepEquals, []string{}) 255 256 c.Assert(s.stderr.String(), testutil.Contains, "cannot os.Chmod because the test says so") 257 } 258 259 func (s *userdSuite) TestAutostartSessionAppsRestrictsPermissionsNoCreateSnapDir(c *C) { 260 userDir := path.Join(c.MkDir(), "home") 261 mockUserCurrent := func() (*user.User, error) { 262 return &user.User{HomeDir: userDir}, nil 263 } 264 r := snap.MockUserCurrent(mockUserCurrent) 265 defer r() 266 267 r = autostart.MockUserCurrent(mockUserCurrent) 268 defer r() 269 270 // ensure that the "snap" dir doesn't already exist 271 c.Assert(filepath.Join(userDir, "snap"), testutil.FileAbsent) 272 273 // run autostart 274 args, err := snap.Parser(snap.Client()).ParseArgs([]string{"userd", "--autostart"}) 275 c.Assert(err, IsNil) 276 c.Assert(args, DeepEquals, []string{}) 277 278 // make sure that the directory was not created 279 c.Assert(filepath.Join(userDir, "snap"), testutil.FileAbsent) 280 }