Exemplo n.º 1
0
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,
	}
}
Exemplo n.º 2
0
// 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
}
Exemplo n.º 3
0
// 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()
}
Exemplo n.º 4
0
// 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()
}
Exemplo n.º 5
0
// 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
}
Exemplo n.º 6
0
func (f *fakeSnappyBackend) ClearTrashedData(si *snap.Info) {
	f.ops = append(f.ops, fakeOp{
		op:    "cleanup-trash",
		name:  si.Name(),
		revno: si.Revision,
	})
}
Exemplo n.º 7
0
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)
	}
}
Exemplo n.º 8
0
// 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
}
Exemplo n.º 9
0
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
}
Exemplo n.º 10
0
// 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
}
Exemplo n.º 11
0
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
}
Exemplo n.º 12
0
// 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)
		}
	}
}
Exemplo n.º 13
0
// 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"),
	}
}
Exemplo n.º 14
0
// 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)
}
Exemplo n.º 15
0
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
}
Exemplo n.º 16
0
// 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
}
Exemplo n.º 17
0
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
}
Exemplo n.º 18
0
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
}
Exemplo n.º 19
0
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
}
Exemplo n.º 20
0
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
}
Exemplo n.º 21
0
// 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()
}
Exemplo n.º 22
0
// 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
}
Exemplo n.º 23
0
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)
}
Exemplo n.º 24
0
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
}
Exemplo n.º 25
0
// 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
}
Exemplo n.º 26
0
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)
}
Exemplo n.º 27
0
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
}
Exemplo n.º 28
0
// 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
}
Exemplo n.º 29
0
// 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
}
Exemplo n.º 30
0
// 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
}