diff options
| author | Paweł Stołowski <stolowski@gmail.com> | 2020-08-05 17:14:06 +0200 |
|---|---|---|
| committer | Paweł Stołowski <stolowski@gmail.com> | 2020-08-06 11:26:41 +0200 |
| commit | e1df8047fb72fed3c5d9aad8b3af7144271f1061 (patch) | |
| tree | c2c5bae8390f67f849d6f03fc23fec4b8fca8219 | |
| parent | d4c159fa49206ea2f485dff27721c8ace6ca9ee1 (diff) | |
Use emulation mode and skip daemon-reload / starting / stopping of services in systemd security backend if preseeding.preseed/fix-systemd-backend
| -rw-r--r-- | interfaces/systemd/backend.go | 47 | ||||
| -rw-r--r-- | interfaces/systemd/backend_test.go | 50 |
2 files changed, 82 insertions, 15 deletions
diff --git a/interfaces/systemd/backend.go b/interfaces/systemd/backend.go index 7163f6be1b..09affdd0be 100644 --- a/interfaces/systemd/backend.go +++ b/interfaces/systemd/backend.go @@ -37,10 +37,15 @@ import ( ) // Backend is responsible for maintaining apparmor profiles for ubuntu-core-launcher. -type Backend struct{} +type Backend struct { + preseed bool +} // Initialize does nothing. -func (b *Backend) Initialize(*interfaces.SecurityBackendOptions) error { +func (b *Backend) Initialize(opts *interfaces.SecurityBackendOptions) error { + if opts != nil && opts.Preseed { + b.preseed = true + } return nil } @@ -69,16 +74,22 @@ func (b *Backend) Setup(snapInfo *snap.Info, confinement interfaces.ConfinementO } glob := interfaces.InterfaceServiceName(snapName, "*") - systemd := sysd.New(dirs.GlobalRootDir, sysd.SystemMode, &dummyReporter{}) + var systemd sysd.Systemd + if b.preseed { + systemd = sysd.NewEmulationMode(dirs.GlobalRootDir) + } else { + systemd = sysd.New(dirs.GlobalRootDir, sysd.SystemMode, &dummyReporter{}) + } + // We need to be carefully here and stop all removed service units before // we remove their files as otherwise systemd is not able to disable/stop // them anymore. - if err := disableRemovedServices(systemd, dir, glob, content); err != nil { + if err := b.disableRemovedServices(systemd, dir, glob, content); err != nil { logger.Noticef("cannot stop removed services: %s", err) } changed, removed, errEnsure := osutil.EnsureDirState(dir, glob, content) // Reload systemd whenever something is added or removed - if len(changed) > 0 || len(removed) > 0 { + if (len(changed) > 0 || len(removed) > 0) && !b.preseed { err := systemd.DaemonReload() if err != nil { logger.Noticef("cannot reload systemd state: %s", err) @@ -89,10 +100,12 @@ func (b *Backend) Setup(snapInfo *snap.Info, confinement interfaces.ConfinementO if err := systemd.Enable(service); err != nil { logger.Noticef("cannot enable service %q: %s", service, err) } - // If we have a new service here which isn't started yet the restart - // operation will start it. - if err := systemd.Restart(service, 10*time.Second); err != nil { - logger.Noticef("cannot restart service %q: %s", service, err) + if !b.preseed { + // If we have a new service here which isn't started yet the restart + // operation will start it. + if err := systemd.Restart(service, 10*time.Second); err != nil { + logger.Noticef("cannot restart service %q: %s", service, err) + } } } return errEnsure @@ -108,12 +121,14 @@ func (b *Backend) Remove(snapName string) error { if err := systemd.Disable(service); err != nil { logger.Noticef("cannot disable service %q: %s", service, err) } - if err := systemd.Stop(service, 5*time.Second); err != nil { - logger.Noticef("cannot stop service %q: %s", service, err) + if !b.preseed { + if err := systemd.Stop(service, 5*time.Second); err != nil { + logger.Noticef("cannot stop service %q: %s", service, err) + } } } // Reload systemd whenever something is removed - if len(removed) > 0 { + if len(removed) > 0 && !b.preseed { err := systemd.DaemonReload() if err != nil { logger.Noticef("cannot reload systemd state: %s", err) @@ -148,7 +163,7 @@ func deriveContent(spec *Specification, snapInfo *snap.Info) map[string]osutil.F return content } -func disableRemovedServices(systemd sysd.Systemd, dir, glob string, content map[string]osutil.FileState) error { +func (b *Backend) disableRemovedServices(systemd sysd.Systemd, dir, glob string, content map[string]osutil.FileState) error { paths, err := filepath.Glob(filepath.Join(dir, glob)) if err != nil { return err @@ -159,8 +174,10 @@ func disableRemovedServices(systemd sysd.Systemd, dir, glob string, content map[ if err := systemd.Disable(service); err != nil { logger.Noticef("cannot disable service %q: %s", service, err) } - if err := systemd.Stop(service, 5*time.Second); err != nil { - logger.Noticef("cannot stop service %q: %s", service, err) + if !b.preseed { + if err := systemd.Stop(service, 5*time.Second); err != nil { + logger.Noticef("cannot stop service %q: %s", service, err) + } } } } diff --git a/interfaces/systemd/backend_test.go b/interfaces/systemd/backend_test.go index 2e873aba17..75f42bbd04 100644 --- a/interfaces/systemd/backend_test.go +++ b/interfaces/systemd/backend_test.go @@ -157,3 +157,53 @@ func (s *backendSuite) TestSettingUpSecurityWithFewerServices(c *C) { func (s *backendSuite) TestSandboxFeatures(c *C) { c.Assert(s.Backend.SandboxFeatures(), IsNil) } + +func (s *backendSuite) TestInstallingSnapWhenPreseeding(c *C) { + s.Backend = &systemd.Backend{} + opts := &interfaces.SecurityBackendOptions{Preseed: true} + s.Backend.Initialize(opts) + + var sysdLog [][]string + r := sysd.MockSystemctl(func(cmd ...string) ([]byte, error) { + sysdLog = append(sysdLog, cmd) + return []byte{}, nil + }) + defer r() + + s.Iface.SystemdPermanentSlotCallback = func(spec *systemd.Specification, slot *snap.SlotInfo) error { + return spec.AddService("snap.samba.interface.foo.service", &systemd.Service{ExecStart: "/bin/true"}) + } + s.InstallSnap(c, interfaces.ConfinementOptions{}, "", ifacetest.SambaYamlV1, 1) + service := filepath.Join(dirs.SnapServicesDir, "snap.samba.interface.foo.service") + // the service file was created + _, err := os.Stat(service) + c.Check(err, IsNil) + // the service was enabled but not started + c.Check(sysdLog, DeepEquals, [][]string{ + {"--root", dirs.GlobalRootDir, "enable", "snap.samba.interface.foo.service"}, + }) +} + +// not a viable scenario, but tested for completness +func (s *backendSuite) TestRemovingSnapWhenPreseeding(c *C) { + s.Backend = &systemd.Backend{} + opts := &interfaces.SecurityBackendOptions{Preseed: true} + s.Backend.Initialize(opts) + + s.Iface.SystemdPermanentSlotCallback = func(spec *systemd.Specification, slot *snap.SlotInfo) error { + return spec.AddService("snap.samba.interface.foo.service", &systemd.Service{ExecStart: "/bin/true"}) + } + for _, opts := range testedConfinementOpts { + snapInfo := s.InstallSnap(c, opts, "", ifacetest.SambaYamlV1, 1) + s.systemctlArgs = nil + s.RemoveSnap(c, snapInfo) + service := filepath.Join(dirs.SnapServicesDir, "snap.samba.interface.foo.service") + // the service file was removed + _, err := os.Stat(service) + c.Check(os.IsNotExist(err), Equals, true) + // the service was disabled (but no other systemctl calls) + c.Check(s.systemctlArgs, DeepEquals, [][]string{ + {"systemctl", "--root", dirs.GlobalRootDir, "disable", "snap.samba.interface.foo.service"}, + }) + } +} |
