func mapLocal(localSnap *snap.Info, snapst *snapstate.SnapState) map[string]interface{} { status := "installed" if snapst.Active && localSnap.Revision == snapst.Current { status = "active" } apps := make([]appJSON, 0, len(localSnap.Apps)) for _, app := range localSnap.Apps { apps = append(apps, appJSON{ Name: app.Name, }) } return map[string]interface{}{ "description": localSnap.Description(), "developer": localSnap.Developer, "icon": snapIcon(localSnap), "id": localSnap.SnapID, "install-date": snapDate(localSnap), "installed-size": localSnap.Size, "name": localSnap.Name(), "revision": localSnap.Revision, "status": status, "summary": localSnap.Summary(), "type": string(localSnap.Type), "version": localSnap.Version, "channel": localSnap.Channel, "confinement": localSnap.Confinement, "devmode": snapst.DevMode(), "trymode": snapst.TryMode(), "private": localSnap.Private, "apps": apps, "broken": localSnap.Broken, } }
// Setup creates a conf file with list of kernel modules required by given snap, // writes it in /etc/modules-load.d/ directory and immediately loads the modules // using /sbin/modprobe. The devMode is ignored. // // If the method fails it should be re-tried (with a sensible strategy) by the caller. func (b *Backend) Setup(snapInfo *snap.Info, confinement interfaces.ConfinementOptions, repo *interfaces.Repository) error { snapName := snapInfo.Name() // Get the snippets that apply to this snap snippets, err := repo.SecuritySnippetsForSnap(snapInfo.Name(), interfaces.SecurityKMod) if err != nil { return fmt.Errorf("cannot obtain kmod security snippets for snap %q: %s", snapName, err) } // Get the files that this snap should have glob := interfaces.SecurityTagGlob(snapName) content, modules, err := b.combineSnippets(snapInfo, snippets) if err != nil { return fmt.Errorf("cannot obtain expected security files for snap %q: %s", snapName, err) } dir := dirs.SnapKModModulesDir if err := os.MkdirAll(dir, 0755); err != nil { return fmt.Errorf("cannot create directory for kmod files %q: %s", dir, err) } changed, _, err := osutil.EnsureDirState(dirs.SnapKModModulesDir, glob, content) if err != nil { return err } if len(changed) > 0 { return loadModules(modules) } return nil }
// templateVariables returns text defining apparmor variables that can be used in the // apparmor template and by apparmor snippets. func templateVariables(info *snap.Info) []byte { var buf bytes.Buffer fmt.Fprintf(&buf, "@{SNAP_NAME}=\"%s\"\n", info.Name()) fmt.Fprintf(&buf, "@{SNAP_REVISION}=\"%s\"\n", info.Revision) fmt.Fprintf(&buf, "@{INSTALL_DIR}=\"/snap\"") return buf.Bytes() }
// CheckInterfaces checks whether plugs and slots of snap are allowed for installation. func CheckInterfaces(st *state.State, snapInfo *snap.Info) error { // XXX: AddImplicitSlots is really a brittle interface snap.AddImplicitSlots(snapInfo) baseDecl, err := assertstate.BaseDeclaration(st) if err != nil { return fmt.Errorf("internal error: cannot find base declaration: %v", err) } var snapDecl *asserts.SnapDeclaration if snapInfo.SnapID != "" { var err error snapDecl, err = assertstate.SnapDeclaration(st, snapInfo.SnapID) if err != nil { return fmt.Errorf("cannot find snap declaration for %q: %v", snapInfo.Name(), err) } } ic := policy.InstallCandidate{ Snap: snapInfo, SnapDeclaration: snapDecl, BaseDeclaration: baseDecl, } return ic.Check() }
// combineSnippets combines security snippets collected from all the interfaces // affecting a given snap into a de-duplicated list of kernel modules. func (b *Backend) combineSnippets(snapInfo *snap.Info, snippets map[string][][]byte) (content map[string]*osutil.FileState, modules []string, err error) { content = make(map[string]*osutil.FileState) for _, appInfo := range snapInfo.Apps { for _, snippet := range snippets[appInfo.SecurityTag()] { // split snippet by newline to get the list of modules for _, line := range bytes.Split(snippet, []byte{'\n'}) { l := bytes.TrimSpace(line) // ignore empty lines and comments if len(l) > 0 && l[0] != '#' { modules = append(modules, string(l)) } } } } sort.Strings(modules) modules = uniqueLines(modules) if len(modules) > 0 { var buffer bytes.Buffer buffer.WriteString("# This file is automatically generated.\n") for _, module := range modules { buffer.WriteString(module) buffer.WriteByte('\n') } content[fmt.Sprintf("%s.conf", snap.SecurityTag(snapInfo.Name()))] = &osutil.FileState{ Content: buffer.Bytes(), Mode: 0644, } } return content, modules, nil }
func (f *fakeSnappyBackend) ClearTrashedData(si *snap.Info) { f.ops = append(f.ops, fakeOp{ op: "cleanup-trash", name: si.Name(), revno: si.Revision, }) }
func (s *BackendSuite) removePlugsSlots(c *C, snapInfo *snap.Info) { for _, plug := range s.Repo.Plugs(snapInfo.Name()) { err := s.Repo.RemovePlug(plug.Snap.Name(), plug.Name) c.Assert(err, IsNil) } for _, slot := range s.Repo.Slots(snapInfo.Name()) { err := s.Repo.RemoveSlot(slot.Snap.Name(), slot.Name) c.Assert(err, IsNil) } }
// AddSnap adds plugs and slots declared by the given snap to the repository. // // This function can be used to implement snap install or, when used along with // RemoveSnap, snap upgrade. // // AddSnap doesn't change existing plugs/slots. The caller is responsible for // ensuring that the snap is not present in the repository in any way prior to // calling this function. If this constraint is violated then no changes are // made and an error is returned. // // Each added plug/slot is validated according to the corresponding interface. // Unknown interfaces and plugs/slots that don't validate are not added. // Information about those failures are returned to the caller. func (r *Repository) AddSnap(snapInfo *snap.Info) error { r.m.Lock() defer r.m.Unlock() snapName := snapInfo.Name() if r.plugs[snapName] != nil || r.slots[snapName] != nil { return fmt.Errorf("cannot register interfaces for snap %q more than once", snapName) } bad := BadInterfacesError{ snap: snapName, issues: make(map[string]string), } for plugName, plugInfo := range snapInfo.Plugs { iface, ok := r.ifaces[plugInfo.Interface] if !ok { bad.issues[plugName] = "unknown interface" continue } plug := &Plug{PlugInfo: plugInfo} if err := iface.SanitizePlug(plug); err != nil { bad.issues[plugName] = err.Error() continue } if r.plugs[snapName] == nil { r.plugs[snapName] = make(map[string]*Plug) } r.plugs[snapName][plugName] = plug } for slotName, slotInfo := range snapInfo.Slots { iface, ok := r.ifaces[slotInfo.Interface] if !ok { bad.issues[slotName] = "unknown interface" continue } slot := &Slot{SlotInfo: slotInfo} if err := iface.SanitizeSlot(slot); err != nil { bad.issues[slotName] = err.Error() continue } if r.slots[snapName] == nil { r.slots[snapName] = make(map[string]*Slot) } r.slots[snapName][slotName] = slot } if len(bad.issues) > 0 { return &bad } return nil }
func (f *fakeStoreClient) Download(remoteSnap *snap.Info, pb progress.Meter, sa store.Authenticator) (path string, err error) { f.downloadCalls[getDownloadCall(remoteSnap.Name(), remoteSnap.Channel)]++ f.totalDownloadCalls++ if f.downloadErr { if f.totalDownloadCalls > f.correctDownloadCalls { return "", errors.New("") } } return getSnapFilename(remoteSnap.Name(), remoteSnap.Channel), nil }
// UpdateSnap "updates" an existing snap from YAML. func (s *BackendSuite) UpdateSnap(c *C, oldSnapInfo *snap.Info, devMode bool, snapYaml string, revision int) *snap.Info { newSnapInfo := snaptest.MockInfo(c, snapYaml, &snap.SideInfo{ Revision: snap.R(revision), Developer: "acme", }) c.Assert(newSnapInfo.Name(), Equals, oldSnapInfo.Name()) s.removePlugsSlots(c, oldSnapInfo) s.addPlugsSlots(c, newSnapInfo) err := s.Backend.Setup(newSnapInfo, devMode, s.Repo) c.Assert(err, IsNil) return newSnapInfo }
func (b *Backend) Setup(snapInfo *snap.Info, confinement interfaces.ConfinementOptions, repo *interfaces.Repository) error { snapName := snapInfo.Name() rawSnippets, err := repo.SecuritySnippetsForSnap(snapInfo.Name(), interfaces.SecuritySystemd) if err != nil { return fmt.Errorf("cannot obtain systemd security snippets for snap %q: %s", snapName, err) } snippets, err := unmarshalRawSnippetMap(rawSnippets) if err != nil { return fmt.Errorf("cannot unmarshal systemd snippets for snap %q: %s", snapName, err) } snippet, err := mergeSnippetMap(snippets) if err != nil { return fmt.Errorf("cannot merge systemd snippets for snap %q: %s", snapName, err) } content, err := renderSnippet(snippet) if err != nil { return fmt.Errorf("cannot render systemd snippets for snap %q: %s", snapName, err) } dir := dirs.SnapServicesDir if err := os.MkdirAll(dir, 0755); err != nil { return fmt.Errorf("cannot create directory for systemd services %q: %s", dir, err) } glob := interfaces.InterfaceServiceName(snapName, "*") systemd := sysd.New(dirs.GlobalRootDir, &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 { 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 { err := systemd.DaemonReload() if err != nil { logger.Noticef("cannot reload systemd state: %s", err) } } // Ensure the service is running right now and on reboots for _, service := range changed { 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) } } return errEnsure }
// ClearTrashedData removes the trash. It returns no errors on the assumption that it is called very late in the game. func (b Backend) ClearTrashedData(oldSnap *snap.Info) { dirs, err := snapDataDirs(oldSnap) if err != nil { logger.Noticef("Cannot remove previous data for %q: %v", oldSnap.Name(), err) return } for _, d := range dirs { if err := clearTrash(d); err != nil { logger.Noticef("Cannot remove %s: %v", d, err) } } }
// basicEnv returns the app-level environment variables for a snap. // Despite this being a bit snap-specific, this is in helpers.go because it's // used by so many other modules, we run into circular dependencies if it's // somewhere more reasonable like the snappy module. func basicEnv(info *snap.Info) map[string]string { return map[string]string{ "SNAP": info.MountDir(), "SNAP_COMMON": info.CommonDataDir(), "SNAP_DATA": info.DataDir(), "SNAP_NAME": info.Name(), "SNAP_VERSION": info.Version, "SNAP_REVISION": info.Revision.String(), "SNAP_ARCH": arch.UbuntuArchitecture(), "SNAP_LIBRARY_PATH": "/var/lib/snapd/lib/gl:", "SNAP_REEXEC": os.Getenv("SNAP_REEXEC"), } }
// FetchAndCheckSnapAssertions fetches and cross checks the snap assertions matching the given snap file using the provided asserts.Fetcher and assertion database. func FetchAndCheckSnapAssertions(snapPath string, info *snap.Info, f asserts.Fetcher, db asserts.RODatabase) error { sha3_384, size, err := asserts.SnapFileSHA3_384(snapPath) if err != nil { return err } if err := snapasserts.FetchSnapAssertions(f, sha3_384); err != nil { return fmt.Errorf("cannot fetch snap signatures/assertions: %v", err) } // cross checks return snapasserts.CrossCheck(info.Name(), sha3_384, size, &info.SideInfo, db) }
func mapRemote(remoteSnap *snap.Info) map[string]interface{} { status := "available" if remoteSnap.MustBuy { status = "priced" } confinement := remoteSnap.Confinement if confinement == "" { confinement = snap.StrictConfinement } screenshots := make([]screenshotJSON, len(remoteSnap.Screenshots)) for i, screenshot := range remoteSnap.Screenshots { screenshots[i] = screenshotJSON{ URL: screenshot.URL, Width: screenshot.Width, Height: screenshot.Height, } } result := map[string]interface{}{ "description": remoteSnap.Description(), "developer": remoteSnap.Developer, "download-size": remoteSnap.Size, "icon": snapIcon(remoteSnap), "id": remoteSnap.SnapID, "name": remoteSnap.Name(), "revision": remoteSnap.Revision, "status": status, "summary": remoteSnap.Summary(), "type": string(remoteSnap.Type), "version": remoteSnap.Version, "channel": remoteSnap.Channel, "private": remoteSnap.Private, "confinement": confinement, } if len(screenshots) > 0 { result["screenshots"] = screenshots } if len(remoteSnap.Prices) > 0 { result["prices"] = remoteSnap.Prices } if len(remoteSnap.Channels) > 0 { result["channels"] = remoteSnap.Channels } return result }
// combineSnippets combines security snippets collected from all the interfaces // affecting a given snap into a content map applicable to EnsureDirState. func (b *Backend) combineSnippets(snapInfo *snap.Info, snippets map[string][][]byte) (result [][]byte, err error) { var snapSnippets = make(map[string][]byte) // We put all snippets from apps and hooks in the following part in a // map to reach a deduplicated set of snippets we can then write out // in a per snap udev rules file. for _, appInfo := range snapInfo.Apps { securityTag := appInfo.SecurityTag() appSnippets := snippets[securityTag] if len(appSnippets) == 0 { continue } for _, snippet := range appSnippets { snapSnippets[string(snippet)] = snippet } } for _, hookInfo := range snapInfo.Hooks { securityTag := hookInfo.SecurityTag() hookSnippets := snippets[securityTag] if len(hookSnippets) == 0 { continue } for _, snippet := range hookSnippets { snapSnippets[string(snippet)] = snippet } } nonePrefix := snap.NoneSecurityTag(snapInfo.Name(), "") for securityTag, slotSnippets := range snippets { if !strings.HasPrefix(securityTag, nonePrefix) { continue } for _, snippet := range slotSnippets { snapSnippets[string(snippet)] = snippet } } var combinedSnippets [][]byte for _, snippet := range snapSnippets { combinedSnippets = append(combinedSnippets, snippet) } return combinedSnippets, nil }
func setupSnapSecurity(task *state.Task, snapInfo *snap.Info, devMode bool, repo *interfaces.Repository) error { st := task.State() snapName := snapInfo.Name() for _, backend := range backends.All { st.Unlock() err := backend.Setup(snapInfo, devMode, repo) st.Lock() if err != nil { task.Errorf("cannot setup %s for snap %q: %s", backend.Name(), snapName, err) return err } } return nil }
func checkGadgetOrKernel(st *state.State, snapInfo, curInfo *snap.Info, flags snapstate.Flags) error { kind := "" var currentInfo func(*state.State) (*snap.Info, error) var getName func(*asserts.Model) string switch snapInfo.Type { case snap.TypeGadget: kind = "gadget" currentInfo = snapstate.GadgetInfo getName = (*asserts.Model).Gadget case snap.TypeKernel: kind = "kernel" currentInfo = snapstate.KernelInfo getName = (*asserts.Model).Kernel default: // not a relevant check return nil } if release.OnClassic { // for the time being return fmt.Errorf("cannot install a %s snap on classic", kind) } currentSnap, err := currentInfo(st) if err != nil && err != state.ErrNoState { return fmt.Errorf("cannot find original %s snap: %v", kind, err) } if currentSnap != nil { // already installed, snapstate takes care return nil } // first installation of a gadget/kernel model, err := Model(st) if err == state.ErrNoState { return fmt.Errorf("cannot install %s without model assertion", kind) } if err != nil { return err } expectedName := getName(model) if snapInfo.Name() != expectedName { return fmt.Errorf("cannot install %s %q, model assertion requests %q", kind, snapInfo.Name(), expectedName) } return nil }
func checkGadgetOrKernel(st *state.State, snapInfo, curInfo *snap.Info, flags Flags) error { kind := "" var currentInfo func(*state.State) (*snap.Info, error) switch snapInfo.Type { case snap.TypeGadget: kind = "gadget" currentInfo = GadgetInfo case snap.TypeKernel: kind = "kernel" currentInfo = KernelInfo default: // not a relevant check return nil } if release.OnClassic { // for the time being return fmt.Errorf("cannot install a %s snap on classic", kind) } currentSnap, err := currentInfo(st) // in firstboot we have no gadget/kernel yet - that is ok // devicestate considers that case if err == state.ErrNoState { return nil } if err != nil { return fmt.Errorf("cannot find original %s snap: %v", kind, err) } if currentSnap.SnapID != "" && snapInfo.SnapID != "" { if currentSnap.SnapID == snapInfo.SnapID { // same snap return nil } return fmt.Errorf("cannot replace %s snap with a different one", kind) } if currentSnap.SnapID != "" && snapInfo.SnapID == "" { return fmt.Errorf("cannot replace signed %s snap with an unasserted one", kind) } if currentSnap.Name() != snapInfo.Name() { return fmt.Errorf("cannot replace %s snap with a different one", kind) } return nil }
func (b *Backend) Setup(snapInfo *snap.Info, devMode bool, repo *interfaces.Repository) error { snapName := snapInfo.Name() rawSnippets, err := repo.SecuritySnippetsForSnap(snapInfo.Name(), interfaces.SecuritySystemd) if err != nil { return fmt.Errorf("cannot obtain systemd security snippets for snap %q: %s", snapName, err) } snippets, err := unmarshalRawSnippetMap(rawSnippets) if err != nil { return fmt.Errorf("cannot unmarshal systemd snippets for snap %q: %s", snapName, err) } snippet, err := mergeSnippetMap(snippets) if err != nil { return fmt.Errorf("cannot merge systemd snippets for snap %q: %s", snapName, err) } content, err := renderSnippet(snippet) if err != nil { return fmt.Errorf("cannot render systemd snippets for snap %q: %s", snapName, err) } dir := dirs.SnapServicesDir if err := os.MkdirAll(dir, 0755); err != nil { return fmt.Errorf("cannot create directory for systemd services %q: %s", dir, err) } glob := interfaces.InterfaceServiceName(snapName, "*") changed, removed, errEnsure := osutil.EnsureDirState(dir, glob, content) systemd := sysd.New(dirs.GlobalRootDir, &dummyReporter{}) // Reload systemd whenever something is added or removed if len(changed) > 0 || len(removed) > 0 { err := systemd.DaemonReload() if err != nil { logger.Noticef("cannot reload systemd state: %s", err) } } // Start any new services for _, service := range changed { err := systemd.Start(service) if err != nil { logger.Noticef("cannot start service %q: %s", service, err) } } // Stop any removed services for _, service := range removed { err := systemd.Stop(service, 10*time.Second) if err != nil { logger.Noticef("cannot stop service %q: %s", service, err) } } return errEnsure }
// AppLabelExpr returns the specification of the apparmor label describing // all the apps bound to a given slot. The result has one of three forms, // depending on how apps are bound to the slot: // // - "snap.$snap.$app" if there is exactly one app bound // - "snap.$snap.{$app1,...$appN}" if there are some, but not all, apps bound // - "snap.$snap.*" if all apps are bound to the slot func appLabelExpr(apps map[string]*snap.AppInfo, snap *snap.Info) []byte { var buf bytes.Buffer fmt.Fprintf(&buf, `"snap.%s.`, snap.Name()) if len(apps) == 1 { for appName := range apps { buf.WriteString(appName) } } else if len(apps) == len(snap.Apps) { buf.WriteByte('*') } else { appNames := make([]string, 0, len(apps)) for appName := range apps { appNames = append(appNames, appName) } sort.Strings(appNames) buf.WriteByte('{') for _, appName := range appNames { buf.WriteString(appName) buf.WriteByte(',') } buf.Truncate(buf.Len() - 1) buf.WriteByte('}') } buf.WriteByte('"') return buf.Bytes() }
// RemoveSnapDesktopFiles removes the added desktop files for the applications in the snap. func RemoveSnapDesktopFiles(s *snap.Info) error { glob := filepath.Join(dirs.SnapDesktopFilesDir, s.Name()+"_*.desktop") activeDesktopFiles, err := filepath.Glob(glob) if err != nil { return fmt.Errorf("cannot get desktop files for %v: %s", glob, err) } for _, f := range activeDesktopFiles { os.Remove(f) } // updates mime info etc if err := updateDesktopDatabase(activeDesktopFiles); err != nil { return err } return nil }
func (m *InterfaceManager) setupProfilesForSnap(task *state.Task, _ *tomb.Tomb, snapInfo *snap.Info, devModeAllowed bool) error { snap.AddImplicitSlots(snapInfo) snapName := snapInfo.Name() // The snap may have been updated so perform the following operation to // ensure that we are always working on the correct state: // // - disconnect all connections to/from the given snap // - remembering the snaps that were affected by this operation // - remove the (old) snap from the interfaces repository // - add the (new) snap to the interfaces repository // - restore connections based on what is kept in the state // - if a connection cannot be restored then remove it from the state // - setup the security of all the affected snaps affectedSnaps, err := m.repo.DisconnectSnap(snapName) if err != nil { return err } // XXX: what about snap renames? We should remove the old name (or switch // to IDs in the interfaces repository) if err := m.repo.RemoveSnap(snapName); err != nil { return err } if err := m.repo.AddSnap(snapInfo); err != nil { if _, ok := err.(*interfaces.BadInterfacesError); ok { logger.Noticef("%s", err) } else { return err } } if err := m.reloadConnections(snapName); err != nil { return err } // FIXME: here we should not reconnect auto-connect plug/slot // pairs that were explicitly disconnected by the user if err := m.autoConnect(task, snapName, nil); err != nil { return err } if err := setupSnapSecurity(task, snapInfo, devModeAllowed, m.repo); err != nil { return err } return m.setupAffectedSnaps(task, snapName, affectedSnaps) }
func checkAssumes(si *snap.Info) error { missing := ([]string)(nil) for _, flag := range si.Assumes { if strings.HasPrefix(flag, "snapd") && checkVersion(flag[5:]) { continue } if !featureSet[flag] { missing = append(missing, flag) } } if len(missing) > 0 { hint := "try to refresh the core snap" if release.OnClassic { hint = "try to update snapd and refresh the core snap" } return fmt.Errorf("snap %q assumes unsupported features: %s (%s)", si.Name(), strings.Join(missing, ", "), hint) } return nil }
// canRemove verifies that a snap can be removed. func canRemove(si *snap.Info, active bool) bool { // Gadget snaps should not be removed as they are a key // building block for Gadgets. Pruning non active ones // is acceptable. if si.Type == snap.TypeGadget && active { return false } // You never want to remove an active kernel or OS if (si.Type == snap.TypeKernel || si.Type == snap.TypeOS) && active { return false } // TODO: on classic likely let remove core even if active if it's only snap left. // never remove anything that is used for booting if boot.InUse(si.Name(), si.Revision) { return false } return true }
func addMountUnit(s *snap.Info, meter progress.Meter) error { squashfsPath := dirs.StripRootDir(s.MountFile()) whereDir := dirs.StripRootDir(s.MountDir()) sysd := systemd.New(dirs.GlobalRootDir, meter) mountUnitName, err := sysd.WriteMountUnitFile(s.Name(), squashfsPath, whereDir, "squashfs") if err != nil { return err } // we need to do a daemon-reload here to ensure that systemd really // knows about this new mount unit file if err := sysd.DaemonReload(); err != nil { return err } if err := sysd.Enable(mountUnitName); err != nil { return err } return sysd.Start(mountUnitName) }
func checkCoreName(st *state.State, snapInfo, curInfo *snap.Info, flags Flags) error { if snapInfo.Type != snap.TypeOS { // not a relevant check return nil } if curInfo != nil { // already one of these installed return nil } core, err := CoreInfo(st) if err == state.ErrNoState { return nil } if err != nil { return err } if core.Name() != snapInfo.Name() { return fmt.Errorf("cannot install core snap %q when core snap %q is already present", snapInfo.Name(), core.Name()) } return nil }
// Setup creates dbus configuration files specific to a given snap. // // DBus has no concept of a complain mode so confinment type is ignored. func (b *Backend) Setup(snapInfo *snap.Info, opts interfaces.ConfinementOptions, 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 seccomp 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(snapInfo.Name(), interfaces.SecuritySecComp) 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(snapName) dir := dirs.SnapSeccompDir if err := os.MkdirAll(dir, 0755); err != nil { return fmt.Errorf("cannot create directory for seccomp profiles %q: %s", dir, err) } _, _, err = osutil.EnsureDirState(dir, glob, content) if err != nil { return fmt.Errorf("cannot synchronize security 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, opts interfaces.ConfinementOptions, 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, opts, 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 }