// Remove removes seccomp profiles of a given snap. func (b *Backend) Remove(snapName string) error { glob := interfaces.SecurityTagGlob(snapName) _, _, err := osutil.EnsureDirState(dirs.SnapSeccompDir, glob, nil) if err != nil { return fmt.Errorf("cannot synchronize security files for snap %q: %s", snapName, err) } return nil }
// Remove removes dbus configuration files of a given snap. // // This method should be called after removing a snap. func (b *Backend) Remove(snapName string) error { glob := fmt.Sprintf("%s.conf", interfaces.SecurityTagGlob(snapName)) _, _, err := osutil.EnsureDirState(dirs.SnapBusPolicyDir, glob, nil) if err != nil { return fmt.Errorf("cannot synchronize DBus configuration files for snap %q: %s", snapName, err) } return nil }
// Remove removes and unloads apparmor profiles of a given snap. func (b *Backend) Remove(snapName string) error { glob := interfaces.SecurityTagGlob(snapName) _, removed, errEnsure := osutil.EnsureDirState(dirs.SnapAppArmorDir, glob, nil) errUnload := unloadProfiles(removed) if errEnsure != nil { return fmt.Errorf("cannot synchronize security files for snap %q: %s", snapName, errEnsure) } return errUnload }
func ensureDirState(dir, glob string, content map[string]*osutil.FileState, snapName string) error { var errReload error changed, removed, errEnsure := osutil.EnsureDirState(dir, glob, content) if len(changed) > 0 || len(removed) > 0 { // Try reload the rules regardless of errEnsure. errReload = ReloadRules() } if errEnsure != nil { return fmt.Errorf("cannot synchronize udev rules for snap %q: %s", snapName, errEnsure) } return errReload }
func (s *EnsureDirStateSuite) TestIgnoresUnrelatedFiles(c *C) { name := filepath.Join(s.dir, "unrelated") err := ioutil.WriteFile(name, []byte(`text`), 0600) c.Assert(err, IsNil) changed, removed, err := osutil.EnsureDirState(s.dir, s.glob, map[string]*osutil.FileState{}) c.Assert(err, IsNil) // Report says that nothing has changed c.Assert(changed, HasLen, 0) c.Assert(removed, HasLen, 0) // The file is still there _, err = os.Stat(name) c.Assert(err, IsNil) }
func (s *EnsureDirStateSuite) TestRemovesUnexpectedFiless(c *C) { name := filepath.Join(s.dir, "evil.snap") err := ioutil.WriteFile(name, []byte(`evil text`), 0600) c.Assert(err, IsNil) changed, removed, err := osutil.EnsureDirState(s.dir, s.glob, map[string]*osutil.FileState{}) c.Assert(err, IsNil) // Removed file is reported c.Assert(changed, HasLen, 0) c.Assert(removed, DeepEquals, []string{"evil.snap"}) // The file is removed _, err = os.Stat(name) c.Assert(os.IsNotExist(err), Equals, true) }
func (s *EnsureDirStateSuite) TestCreatesMissingFiles(c *C) { name := filepath.Join(s.dir, "missing.snap") changed, removed, err := osutil.EnsureDirState(s.dir, s.glob, map[string]*osutil.FileState{ "missing.snap": {Content: []byte(`content`), Mode: 0600}, }) c.Assert(err, IsNil) // Created file is reported c.Assert(changed, DeepEquals, []string{"missing.snap"}) c.Assert(removed, HasLen, 0) // The content is correct content, err := ioutil.ReadFile(name) c.Assert(err, IsNil) c.Assert(content, DeepEquals, []byte("content")) // The permissions are correct stat, err := os.Stat(name) c.Assert(err, IsNil) c.Assert(stat.Mode().Perm(), Equals, os.FileMode(0600)) }
func (s *EnsureDirStateSuite) TestCorrectsFilesWithSameSize(c *C) { name := filepath.Join(s.dir, "differing.snap") err := ioutil.WriteFile(name, []byte("evil"), 0600) c.Assert(err, IsNil) changed, removed, err := osutil.EnsureDirState(s.dir, s.glob, map[string]*osutil.FileState{ "differing.snap": {Content: []byte("good"), Mode: 0600}, }) c.Assert(err, IsNil) // changed file is reported c.Assert(changed, DeepEquals, []string{"differing.snap"}) c.Assert(removed, HasLen, 0) // The content is changed content, err := ioutil.ReadFile(name) c.Assert(err, IsNil) c.Assert(content, DeepEquals, []byte("good")) // The permissions are what we expect stat, err := os.Stat(name) c.Assert(err, IsNil) c.Assert(stat.Mode().Perm(), Equals, os.FileMode(0600)) }
func (s *EnsureDirStateSuite) TestVerifiesExpectedFiles(c *C) { name := filepath.Join(s.dir, "expected.snap") err := ioutil.WriteFile(name, []byte("expected"), 0600) c.Assert(err, IsNil) changed, removed, err := osutil.EnsureDirState(s.dir, s.glob, map[string]*osutil.FileState{ "expected.snap": {Content: []byte("expected"), Mode: 0600}, }) c.Assert(err, IsNil) // Report says that nothing has changed c.Assert(changed, HasLen, 0) c.Assert(removed, HasLen, 0) // The content is correct content, err := ioutil.ReadFile(path.Join(s.dir, "expected.snap")) c.Assert(err, IsNil) c.Assert(content, DeepEquals, []byte("expected")) // The permissions are correct stat, err := os.Stat(name) c.Assert(err, IsNil) c.Assert(stat.Mode().Perm(), Equals, os.FileMode(0600)) }
func (s *EnsureDirStateSuite) TestRemovesAllManagedFilesOnError(c *C) { // Create a "prior.snap" file prior := filepath.Join(s.dir, "prior.snap") err := ioutil.WriteFile(prior, []byte("data"), 0600) c.Assert(err, IsNil) // Create a "clash.snap" directory to simulate failure clash := filepath.Join(s.dir, "clash.snap") err = os.Mkdir(clash, 0000) c.Assert(err, IsNil) // Try to ensure directory state changed, removed, err := osutil.EnsureDirState(s.dir, s.glob, map[string]*osutil.FileState{ "prior.snap": {Content: []byte("data"), Mode: 0600}, "clash.snap": {Content: []byte("data"), Mode: 0600}, }) c.Assert(changed, HasLen, 0) c.Assert(removed, DeepEquals, []string{"clash.snap", "prior.snap"}) c.Assert(err, ErrorMatches, "rename .* .*/clash.snap: is a directory") // The clashing file is removed _, err = os.Stat(clash) c.Assert(os.IsNotExist(err), Equals, true) }
func (s *EnsureDirStateSuite) TestFixesFilesWithBadPermissions(c *C) { name := filepath.Join(s.dir, "sensitive.snap") // NOTE: the existing file is currently wide-open for everyone" err := ioutil.WriteFile(name, []byte("password"), 0666) c.Assert(err, IsNil) changed, removed, err := osutil.EnsureDirState(s.dir, s.glob, map[string]*osutil.FileState{ // NOTE: we want the file to be private "sensitive.snap": {Content: []byte("password"), Mode: 0600}, }) c.Assert(err, IsNil) // changed file is reported c.Assert(changed, DeepEquals, []string{"sensitive.snap"}) c.Assert(removed, HasLen, 0) // The content is still the same content, err := ioutil.ReadFile(name) c.Assert(err, IsNil) c.Assert(content, DeepEquals, []byte("password")) // The permissions are changed stat, err := os.Stat(name) c.Assert(err, IsNil) c.Assert(stat.Mode().Perm(), Equals, os.FileMode(0600)) }
// Setup creates dbus configuration files specific to a given snap. // // DBus has no concept of a complain mode so devMode is not supported func (b *Backend) Setup(snapInfo *snap.Info, devMode bool, repo *interfaces.Repository) error { snapName := snapInfo.Name() // Get the snippets that apply to this snap snippets, err := repo.SecuritySnippetsForSnap(snapInfo.Name(), interfaces.SecurityDBus) if err != nil { return fmt.Errorf("cannot obtain DBus security snippets for snap %q: %s", snapName, err) } // Get the files that this snap should have content, err := b.combineSnippets(snapInfo, snippets) if err != nil { return fmt.Errorf("cannot obtain expected DBus configuration files for snap %q: %s", snapName, err) } glob := fmt.Sprintf("%s.conf", interfaces.SecurityTagGlob(snapName)) dir := dirs.SnapBusPolicyDir if err := os.MkdirAll(dir, 0755); err != nil { return fmt.Errorf("cannot create directory for DBus configuration files %q: %s", dir, err) } _, _, err = osutil.EnsureDirState(dir, glob, content) if err != nil { return fmt.Errorf("cannot synchronize DBus configuration files for snap %q: %s", snapName, err) } return nil }
// Setup creates and loads apparmor profiles specific to a given snap. // The snap can be in developer mode to make security violations non-fatal to // the offending application process. // // This method should be called after changing plug, slots, connections between // them or application present in the snap. func (b *Backend) Setup(snapInfo *snap.Info, devMode bool, repo *interfaces.Repository) error { snapName := snapInfo.Name() // Get the snippets that apply to this snap snippets, err := repo.SecuritySnippetsForSnap(snapName, interfaces.SecurityAppArmor) if err != nil { return fmt.Errorf("cannot obtain security snippets for snap %q: %s", snapName, err) } // Get the files that this snap should have content, err := b.combineSnippets(snapInfo, devMode, snippets) if err != nil { return fmt.Errorf("cannot obtain expected security files for snap %q: %s", snapName, err) } glob := interfaces.SecurityTagGlob(snapInfo.Name()) dir := dirs.SnapAppArmorDir if err := os.MkdirAll(dir, 0755); err != nil { return fmt.Errorf("cannot create directory for apparmor profiles %q: %s", dir, err) } _, removed, errEnsure := osutil.EnsureDirState(dir, glob, content) // NOTE: load all profiles instead of just the changed profiles. We're // relying on apparmor cache to make this efficient. This gives us // certainty that each call to Setup ends up with working profiles. all := make([]string, 0, len(content)) for name := range content { all = append(all, name) } sort.Strings(all) errReload := reloadProfiles(all) errUnload := unloadProfiles(removed) if errEnsure != nil { return fmt.Errorf("cannot synchronize security files for snap %q: %s", snapName, errEnsure) } if errReload != nil { return errReload } return errUnload }
func (s *EnsureDirStateSuite) TestReportsAbnormalPatterns(c *C) { c.Assert(func() { osutil.EnsureDirState(s.dir, "[", nil) }, PanicMatches, `EnsureDirState got invalid pattern "\[": syntax error in pattern`) }
func (s *EnsureDirStateSuite) TestReportsAbnormalFileName(c *C) { c.Assert(func() { osutil.EnsureDirState(s.dir, s.glob, map[string]*osutil.FileState{"without-namespace": {}}) }, PanicMatches, `EnsureDirState got filename "without-namespace" which doesn't match the glob pattern "\*\.snap"`) }
func (s *EnsureDirStateSuite) TestReportsAbnormalFileLocation(c *C) { c.Assert(func() { osutil.EnsureDirState(s.dir, s.glob, map[string]*osutil.FileState{"subdir/file.snap": {}}) }, PanicMatches, `EnsureDirState got filename "subdir/file.snap" which has a path component`) }