gitee.com/mysnapcore/mysnapd@v0.1.0/snap/container_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package snap_test 21 22 import ( 23 "io/ioutil" 24 "os" 25 "path/filepath" 26 "syscall" 27 28 . "gopkg.in/check.v1" 29 30 "gitee.com/mysnapcore/mysnapd/snap" 31 "gitee.com/mysnapcore/mysnapd/snap/snapdir" 32 "gitee.com/mysnapcore/mysnapd/testutil" 33 ) 34 35 type FileSuite struct{} 36 37 var _ = Suite(&FileSuite{}) 38 39 type validateSuite struct { 40 testutil.BaseTest 41 } 42 43 var _ = Suite(&validateSuite{}) 44 45 func discard(string, ...interface{}) {} 46 47 func (s *validateSuite) SetUpTest(c *C) { 48 s.BaseTest.SetUpTest(c) 49 s.BaseTest.AddCleanup(snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {})) 50 } 51 52 func (s *validateSuite) TearDownTest(c *C) { 53 s.BaseTest.TearDownTest(c) 54 } 55 56 func (s *validateSuite) TestValidateContainerReallyEmptyFails(c *C) { 57 const yaml = `name: empty-snap 58 version: 1 59 ` 60 d := c.MkDir() 61 // the snap dir is a 0700 directory with nothing in it 62 63 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 64 c.Assert(err, IsNil) 65 66 err = snap.ValidateContainer(snapdir.New(d), info, discard) 67 c.Check(err, Equals, snap.ErrMissingPaths) 68 } 69 70 func (s *validateSuite) TestValidateContainerEmptyButBadPermFails(c *C) { 71 const yaml = `name: empty-snap 72 version: 1 73 ` 74 d := c.MkDir() 75 76 stat, err := os.Stat(d) 77 c.Assert(err, IsNil) 78 c.Check(stat.Mode().Perm(), Equals, os.FileMode(0700)) // just to be sure 79 80 c.Assert(os.Mkdir(filepath.Join(d, "meta"), 0755), IsNil) 81 c.Assert(ioutil.WriteFile(filepath.Join(d, "meta", "snap.yaml"), nil, 0444), IsNil) 82 83 // snapdir has /meta/snap.yaml, but / is 0700 84 85 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 86 c.Assert(err, IsNil) 87 88 err = snap.ValidateContainer(snapdir.New(d), info, discard) 89 c.Check(err, Equals, snap.ErrBadModes) 90 } 91 92 func (s *validateSuite) TestValidateContainerMissingSnapYamlFails(c *C) { 93 const yaml = `name: empty-snap 94 version: 1 95 ` 96 d := c.MkDir() 97 c.Assert(os.Chmod(d, 0755), IsNil) 98 c.Assert(os.Mkdir(filepath.Join(d, "meta"), 0755), IsNil) 99 100 // snapdir's / and /meta are 0755 (i.e. OK), but no /meta/snap.yaml 101 102 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 103 c.Assert(err, IsNil) 104 105 err = snap.ValidateContainer(snapdir.New(d), info, discard) 106 c.Check(err, Equals, snap.ErrMissingPaths) 107 } 108 109 func (s *validateSuite) TestValidateContainerSnapYamlBadPermsFails(c *C) { 110 const yaml = `name: empty-snap 111 version: 1 112 ` 113 d := c.MkDir() 114 c.Assert(os.Chmod(d, 0755), IsNil) 115 c.Assert(os.Mkdir(filepath.Join(d, "meta"), 0755), IsNil) 116 c.Assert(ioutil.WriteFile(filepath.Join(d, "meta", "snap.yaml"), nil, 0), IsNil) 117 118 // snapdir's / and /meta are 0755 (i.e. OK), 119 // /meta/snap.yaml exists, but isn't readable 120 121 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 122 c.Assert(err, IsNil) 123 124 err = snap.ValidateContainer(snapdir.New(d), info, discard) 125 c.Check(err, Equals, snap.ErrBadModes) 126 } 127 128 func (s *validateSuite) TestValidateContainerSnapYamlNonRegularFails(c *C) { 129 const yaml = `name: empty-snap 130 version: 1 131 ` 132 d := c.MkDir() 133 c.Assert(os.Chmod(d, 0755), IsNil) 134 c.Assert(os.Mkdir(filepath.Join(d, "meta"), 0755), IsNil) 135 c.Assert(syscall.Mkfifo(filepath.Join(d, "meta", "snap.yaml"), 0444), IsNil) 136 137 // snapdir's / and /meta are 0755 (i.e. OK), 138 // /meta/snap.yaml exists, is readable, but isn't a file 139 140 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 141 c.Assert(err, IsNil) 142 143 err = snap.ValidateContainer(snapdir.New(d), info, discard) 144 c.Check(err, Equals, snap.ErrBadModes) 145 } 146 147 // emptyContainer returns a minimal container that passes 148 // ValidateContainer: / and /meta exist and are 0755, and 149 // /meta/snap.yaml is a regular world-readable file. 150 func emptyContainer(c *C) *snapdir.SnapDir { 151 d := c.MkDir() 152 c.Assert(os.Chmod(d, 0755), IsNil) 153 c.Assert(os.Mkdir(filepath.Join(d, "meta"), 0755), IsNil) 154 c.Assert(ioutil.WriteFile(filepath.Join(d, "meta", "snap.yaml"), nil, 0444), IsNil) 155 return snapdir.New(d) 156 } 157 158 func (s *validateSuite) TestValidateContainerMinimalOKPermWorks(c *C) { 159 const yaml = `name: empty-snap 160 version: 1 161 ` 162 d := emptyContainer(c) 163 // snapdir's / and /meta are 0755 (i.e. OK), 164 // /meta/snap.yaml exists, is readable regular file 165 // (this could be considered a test of emptyContainer) 166 167 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 168 c.Assert(err, IsNil) 169 170 err = snap.ValidateContainer(d, info, discard) 171 c.Check(err, IsNil) 172 } 173 174 func (s *validateSuite) TestValidateContainerMissingAppsFails(c *C) { 175 const yaml = `name: empty-snap 176 version: 1 177 apps: 178 foo: 179 command: foo 180 ` 181 d := emptyContainer(c) 182 // snapdir is empty: no apps 183 184 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 185 c.Assert(err, IsNil) 186 187 err = snap.ValidateContainer(d, info, discard) 188 c.Check(err, Equals, snap.ErrMissingPaths) 189 } 190 191 func (s *validateSuite) TestValidateContainerBadAppPermsFails(c *C) { 192 const yaml = `name: empty-snap 193 version: 1 194 apps: 195 foo: 196 command: foo 197 ` 198 d := emptyContainer(c) 199 c.Assert(ioutil.WriteFile(filepath.Join(d.Path(), "foo"), nil, 0444), IsNil) 200 201 // snapdir contains the app, but the app is not executable 202 203 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 204 c.Assert(err, IsNil) 205 206 err = snap.ValidateContainer(d, info, discard) 207 c.Check(err, Equals, snap.ErrBadModes) 208 } 209 210 func (s *validateSuite) TestValidateContainerBadAppDirPermsFails(c *C) { 211 const yaml = `name: empty-snap 212 version: 1 213 apps: 214 foo: 215 command: apps/foo 216 ` 217 d := emptyContainer(c) 218 c.Assert(os.Mkdir(filepath.Join(d.Path(), "apps"), 0700), IsNil) 219 c.Assert(ioutil.WriteFile(filepath.Join(d.Path(), "apps", "foo"), nil, 0555), IsNil) 220 221 // snapdir contains executable app, but path to executable isn't rx 222 223 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 224 c.Assert(err, IsNil) 225 226 err = snap.ValidateContainer(d, info, discard) 227 c.Check(err, Equals, snap.ErrBadModes) 228 } 229 230 func (s *validateSuite) TestValidateContainerBadSvcPermsFails(c *C) { 231 const yaml = `name: empty-snap 232 version: 1 233 apps: 234 bar: 235 command: svcs/bar 236 daemon: simple 237 ` 238 d := emptyContainer(c) 239 c.Assert(os.Mkdir(filepath.Join(d.Path(), "svcs"), 0755), IsNil) 240 c.Assert(ioutil.WriteFile(filepath.Join(d.Path(), "svcs", "bar"), nil, 0), IsNil) 241 242 // snapdir contains service, but it isn't executable 243 244 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 245 c.Assert(err, IsNil) 246 247 err = snap.ValidateContainer(d, info, discard) 248 c.Check(err, Equals, snap.ErrBadModes) 249 } 250 251 func (s *validateSuite) TestValidateContainerCompleterFails(c *C) { 252 const yaml = `name: empty-snap 253 version: 1 254 apps: 255 foo: 256 command: cmds/foo 257 completer: comp/foo.sh 258 ` 259 d := emptyContainer(c) 260 c.Assert(os.Mkdir(filepath.Join(d.Path(), "cmds"), 0755), IsNil) 261 c.Assert(ioutil.WriteFile(filepath.Join(d.Path(), "cmds", "foo"), nil, 0555), IsNil) 262 c.Assert(os.Mkdir(filepath.Join(d.Path(), "comp"), 0755), IsNil) 263 264 // snapdir contains executable app, in a rx path, but refers 265 // to a completer that doesn't exist 266 267 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 268 c.Assert(err, IsNil) 269 270 err = snap.ValidateContainer(d, info, discard) 271 c.Check(err, Equals, snap.ErrMissingPaths) 272 } 273 274 func (s *validateSuite) TestValidateContainerBadAppPathOK(c *C) { 275 // we actually support this, but don't validate it here 276 const yaml = `name: empty-snap 277 version: 1 278 apps: 279 foo: 280 command: ../../../bin/echo 281 ` 282 d := emptyContainer(c) 283 284 // snapdir does not contain the app, but the command is 285 // "outside" so it might be OK 286 287 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 288 c.Assert(err, IsNil) 289 290 err = snap.ValidateContainer(d, info, discard) 291 c.Check(err, IsNil) 292 } 293 294 func (s *validateSuite) TestValidateContainerSymlinksFails(c *C) { 295 c.Skip("checking symlink targets not implemented yet") 296 const yaml = `name: empty-snap 297 version: 1 298 apps: 299 foo: 300 command: foo 301 ` 302 d := emptyContainer(c) 303 fn := filepath.Join(d.Path(), "foo") 304 c.Assert(ioutil.WriteFile(fn+".real", nil, 0444), IsNil) 305 c.Assert(os.Symlink(fn+".real", fn), IsNil) 306 307 // snapdir contains a command that's a symlink to a file that's not world-rx 308 309 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 310 c.Assert(err, IsNil) 311 312 err = snap.ValidateContainer(d, info, discard) 313 c.Check(err, Equals, snap.ErrBadModes) 314 } 315 316 func (s *validateSuite) TestValidateContainerSymlinksOK(c *C) { 317 const yaml = `name: empty-snap 318 version: 1 319 apps: 320 foo: 321 command: foo 322 ` 323 d := emptyContainer(c) 324 fn := filepath.Join(d.Path(), "foo") 325 c.Assert(ioutil.WriteFile(fn+".real", nil, 0555), IsNil) 326 c.Assert(os.Symlink(fn+".real", fn), IsNil) 327 328 // snapdir contains a command that's a symlink to a file that's world-rx 329 330 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 331 c.Assert(err, IsNil) 332 333 err = snap.ValidateContainer(d, info, discard) 334 c.Check(err, IsNil) 335 } 336 337 func (s *validateSuite) TestValidateContainerAppsOK(c *C) { 338 const yaml = `name: empty-snap 339 version: 1 340 apps: 341 foo: 342 command: cmds/foo 343 completer: comp/foo.sh 344 bar: 345 command: svcs/bar 346 daemon: simple 347 baz: 348 command: cmds/foo --with=baz 349 quux: 350 command: cmds/foo 351 daemon: simple 352 meep: 353 command: comp/foo.sh 354 daemon: simple 355 ` 356 d := emptyContainer(c) 357 c.Assert(os.Mkdir(filepath.Join(d.Path(), "cmds"), 0755), IsNil) 358 c.Assert(ioutil.WriteFile(filepath.Join(d.Path(), "cmds", "foo"), nil, 0555), IsNil) 359 c.Assert(os.Mkdir(filepath.Join(d.Path(), "comp"), 0755), IsNil) 360 c.Assert(ioutil.WriteFile(filepath.Join(d.Path(), "comp", "foo.sh"), nil, 0555), IsNil) 361 362 c.Assert(os.Mkdir(filepath.Join(d.Path(), "svcs"), 0700), IsNil) 363 c.Assert(ioutil.WriteFile(filepath.Join(d.Path(), "svcs", "bar"), nil, 0500), IsNil) 364 365 c.Assert(os.Mkdir(filepath.Join(d.Path(), "garbage"), 0755), IsNil) 366 c.Assert(os.Mkdir(filepath.Join(d.Path(), "garbage", "zero"), 0), IsNil) 367 defer os.Chmod(filepath.Join(d.Path(), "garbage", "zero"), 0755) 368 369 // snapdir contains: 370 // * a command that's world-rx, and its directory is 371 // world-rx, and its completer is world-r in a world-rx 372 // directory 373 // * a service that's root-executable, and its directory is 374 // not readable nor searchable - and that's OK! (NOTE as 375 // this test should pass as non-rooot, the directory is 0700 376 // instead of 0000) 377 // * a command with arguments 378 // * a service that is also a command 379 // * a service that is also a completer (WAT) 380 // * an extra directory only root can look at (this would fail 381 // if not running the suite as root, and SkipDir didn't 382 // work) 383 384 info, err := snap.InfoFromSnapYaml([]byte(yaml)) 385 c.Assert(err, IsNil) 386 387 err = snap.ValidateContainer(d, info, discard) 388 c.Check(err, IsNil) 389 }