Esempio n. 1
0
func (sd *SecurityDefinitions) generatePolicyForServiceBinary(m *packageYaml, name string, baseDir string) error {
	p, err := sd.generatePolicyForServiceBinaryResult(m, name, baseDir)
	if err != nil {
		return err
	}

	os.MkdirAll(filepath.Dir(p.scFn), 0755)
	err = helpers.AtomicWriteFile(p.scFn, []byte(p.scPolicy), 0644, 0)
	if err != nil {
		logger.Noticef("Failed to write seccomp policy for %s: %v", name, err)
		return err
	}

	os.MkdirAll(filepath.Dir(p.aaFn), 0755)
	err = helpers.AtomicWriteFile(p.aaFn, []byte(p.aaPolicy), 0644, 0)
	if err != nil {
		logger.Noticef("Failed to write AppArmor policy for %s: %v", name, err)
		return err
	}
	out, err := loadAppArmorPolicy(p.aaFn)
	if err != nil {
		logger.Noticef("Failed to load AppArmor policy for %s: %v\n:%s", name, err, out)
		return err
	}

	return nil
}
Esempio n. 2
0
func addPackageBinaries(m *snapYaml, baseDir string) error {
	if err := os.MkdirAll(dirs.SnapBinariesDir, 0755); err != nil {
		return err
	}

	for _, app := range m.Apps {
		if app.Daemon != "" {
			continue
		}

		aaProfile, err := getSecurityProfile(m, app.Name, baseDir)
		if err != nil {
			return err
		}
		// this will remove the global base dir when generating the
		// service file, this ensures that /snaps/foo/1.0/bin/start
		// is in the service file when the SetRoot() option
		// is used
		realBaseDir := stripGlobalRootDir(baseDir)
		content, err := generateSnapBinaryWrapper(app, realBaseDir, aaProfile, m)
		if err != nil {
			return err
		}

		if err := helpers.AtomicWriteFile(generateBinaryName(m, app), []byte(content), 0755, 0); err != nil {
			return err
		}
	}

	return nil
}
func (s *PartitionTestSuite) TestWriteDueToMissingValues(c *C) {
	s.makeFakeUbootEnv(c)

	// this file needs specific data
	c.Assert(ioutil.WriteFile(bootloaderUbootEnvFile, []byte(""), 0644), IsNil)

	atomiCall := false
	atomicWriteFile = func(a string, b []byte, c os.FileMode, f helpers.AtomicWriteFlags) error {
		atomiCall = true
		return helpers.AtomicWriteFile(a, b, c, f)
	}

	partition := New()
	u := newUboot(partition)
	c.Assert(u, NotNil)

	c.Check(u.MarkCurrentBootSuccessful("a"), IsNil)
	c.Assert(atomiCall, Equals, true)

	bytes, err := ioutil.ReadFile(bootloaderUbootEnvFile)
	c.Assert(err, IsNil)
	c.Check(strings.Contains(string(bytes), "snappy_mode=try"), Equals, false)
	c.Check(strings.Contains(string(bytes), "snappy_mode=regular"), Equals, true)
	c.Check(strings.Contains(string(bytes), "snappy_ab=a"), Equals, true)
}
Esempio n. 4
0
// MigrateToDynamicGrub rearranges things to work with the old,
// dynamic grub setup. Needed for when you rollback over the switch to
// static grub.
func MigrateToDynamicGrub() error {
	grubConfigRaw, err := ioutil.ReadFile(bootloaderGrubConfigFile())
	if err != nil && !os.IsNotExist(err) {
		return err
	}

	grubConfig := string(grubConfigRaw)
	if !isOldGrubConfig(grubConfig) {
		// nothing to do
		return nil
	}

	part := New()
	// first copy current kernel/initrd to /boot/grub/$current (a or b)
	if err := copyKernelAssets("/", part.rootPartition().shortName); err != nil {
		return err
	}

	// then copy other kernel/initrd to /boot/grub/$other (a or b)
	if helpers.FileExists("/writable/cache/system/boot") {
		if err := copyKernelAssets("/writable/cache/system/", part.otherRootPartition().shortName); err != nil {
			return err
		}
	}

	return helpers.AtomicWriteFile(bootloaderGrubConfigFile(), []byte(newGrubConfig), 0644, 0)
}
Esempio n. 5
0
func enableFirstEther() error {
	oem, _ := getOem()
	if oem != nil && oem.OEM.SkipIfupProvisioning {
		return nil
	}

	var eths []string
	for _, glob := range globs {
		eths, _ = filepath.Glob(glob)
		if len(eths) != 0 {
			break
		}
	}
	if len(eths) == 0 {
		return nil
	}
	eth := filepath.Base(eths[0])
	ethfile := filepath.Join(ethdir, eth)
	data := fmt.Sprintf("allow-hotplug %[1]s\niface %[1]s inet dhcp\n", eth)

	if err := helpers.AtomicWriteFile(ethfile, []byte(data), 0644, 0); err != nil {
		return err
	}

	ifup := exec.Command(ifup, eth)
	ifup.Stdout = os.Stdout
	ifup.Stderr = os.Stderr
	if err := ifup.Run(); err != nil {
		return err
	}

	return nil
}
Esempio n. 6
0
// this rewrites the json manifest to include the origin in the on-disk
// manifest.json to be compatible with click again
func writeCompatManifestJSON(clickMetaDir string, manifestData []byte, origin string) error {
	var cm clickManifest
	if err := json.Unmarshal(manifestData, &cm); err != nil {
		return err
	}

	if cm.Type != pkg.TypeFramework && cm.Type != pkg.TypeOem {
		// add the origin to the name
		cm.Name = fmt.Sprintf("%s.%s", cm.Name, origin)
	}

	if origin == SideloadedOrigin {
		cm.Version = filepath.Base(filepath.Join(clickMetaDir, "..", ".."))
	}

	outStr, err := json.MarshalIndent(cm, "", "  ")
	if err != nil {
		return err
	}
	if err := helpers.AtomicWriteFile(filepath.Join(clickMetaDir, cm.Name+".manifest"), []byte(outStr), 0644, 0); err != nil {
		return err
	}

	return nil
}
Esempio n. 7
0
// ExtractHashes reads "hashes.yaml" from the clickdeb and writes it to
// the given directory.
func (d *ClickDeb) ExtractHashes(dir string) error {
	hashesFile := filepath.Join(dir, "hashes.yaml")
	hashesData, err := d.ControlMember("hashes.yaml")
	if err != nil {
		return err
	}

	return helpers.AtomicWriteFile(hashesFile, hashesData, 0644, 0)
}
Esempio n. 8
0
// WriteStoreToken takes the token and stores it on the filesystem for
// later reading via ReadStoreToken()
func WriteStoreToken(token StoreToken) error {
	targetFile := storeTokenFilename()
	if err := os.MkdirAll(filepath.Dir(targetFile), 0750); err != nil {
		return err
	}
	outStr, err := json.MarshalIndent(token, "", " ")
	if err != nil {
		return nil
	}

	return helpers.AtomicWriteFile(targetFile, []byte(outStr), 0600, 0)
}
Esempio n. 9
0
func stampFirstBoot() error {
	// filepath.Dir instead of firstbootDir directly to ease testing
	stampDir := filepath.Dir(stampFile)

	if _, err := os.Stat(stampDir); os.IsNotExist(err) {
		if err := os.MkdirAll(stampDir, 0755); err != nil {
			return err
		}
	}

	return helpers.AtomicWriteFile(stampFile, []byte{}, 0644, 0)
}
Esempio n. 10
0
func (s *systemd) WriteMountUnitFile(name, what, where string) (string, error) {
	c := fmt.Sprintf(`[Unit]
Description=Squashfs mount unit for %s

[Mount]
What=%s
Where=%s
`, name, what, where)

	mu := MountUnitPath(where, "mount")
	return filepath.Base(mu), helpers.AtomicWriteFile(mu, []byte(c), 0644, 0)
}
Esempio n. 11
0
func (s *RemoteSnapPart) saveStoreManifest() error {
	content, err := yaml.Marshal(s.pkg)
	if err != nil {
		return err
	}

	if err := os.MkdirAll(dirs.SnapMetaDir, 0755); err != nil {
		return err
	}

	// don't worry about previous contents
	return helpers.AtomicWriteFile(RemoteManifestPath(s), content, 0644, 0)
}
Esempio n. 12
0
func atomicWriteEntry(data []byte, secret bool, top string, subpath ...string) error {
	fpath := filepath.Join(top, filepath.Join(subpath...))
	dir := filepath.Dir(fpath)
	err := os.MkdirAll(dir, 0775)
	if err != nil {
		return err
	}
	fperm := 0664
	if secret {
		fperm = 0600
	}
	return helpers.AtomicWriteFile(fpath, data, os.FileMode(fperm), 0)
}
Esempio n. 13
0
// writeApparmorAdditionalFile generate a $partID.json.additional file.
//
// This file grants additional access on top of the existing apparmor json
// rules. This is required for the OEM hardware assign code because by
// default apparmor will not allow access to /dev. We grant access here
// and the ubuntu-core-launcher is then used to generate a confinement
// based on the devices cgroup.
func writeApparmorAdditionalFile(m *packageYaml) error {
	if err := os.MkdirAll(dirs.SnapAppArmorDir, 0755); err != nil {
		return err
	}

	for _, h := range m.OEM.Hardware.Assign {
		jsonAdditionalPath := filepath.Join(dirs.SnapAppArmorDir, fmt.Sprintf("%s.json.additional", h.PartID))
		if err := helpers.AtomicWriteFile(jsonAdditionalPath, []byte(apparmorAdditionalContent), 0644, 0); err != nil {
			return err
		}
	}

	return nil
}
Esempio n. 14
0
func setPassthrough(rootDir string, pc []passthroughConfig) error {
	for _, c := range pc {
		path := filepath.Join(rootDir, c.Name)
		if c.Content == "" {
			os.Remove(path)
			continue
		}
		if err := helpers.AtomicWriteFile(path, []byte(c.Content), 0644, helpers.AtomicWriteFollow); err != nil {
			return err
		}
	}

	return nil
}
func (s *PartitionTestSuite) TestNoWriteNotNeeded(c *C) {
	s.makeFakeUbootEnv(c)

	atomiCall := false
	atomicWriteFile = func(a string, b []byte, c os.FileMode, f helpers.AtomicWriteFlags) error {
		atomiCall = true
		return helpers.AtomicWriteFile(a, b, c, f)
	}

	partition := New()
	u := newUboot(partition)
	c.Assert(u, NotNil)

	c.Check(u.MarkCurrentBootSuccessful("a"), IsNil)
	c.Assert(atomiCall, Equals, false)
}
Esempio n. 16
0
func setModules(modules []string) error {
	oldModules, err := getModules()
	if err != nil {
		return err
	}

	for i := range modules {
		m := strings.TrimSpace(modules[i])
		if len(m) == 0 {
			continue
		}

		if m[0] == '-' {
			m = m[1:]
			idx := sort.SearchStrings(oldModules, m)
			if idx == len(oldModules) || oldModules[idx] != m {
				// not found
				continue
			}
			oldModules = append(oldModules[:idx], oldModules[idx+1:]...)
		} else {
			idx := sort.SearchStrings(oldModules, m)
			if idx < len(oldModules) && oldModules[idx] == m {
				// already got it
				continue
			}
			oldModules = append(oldModules, "")
			copy(oldModules[idx+1:], oldModules[idx:])
			oldModules[idx] = m
		}
	}

	var buf bytes.Buffer

	// bytes' Write* methods always return nil error
	buf.WriteString(modulesHeader)

	for i := range oldModules {
		buf.WriteString(oldModules[i])
		buf.WriteByte('\n')
	}

	return helpers.AtomicWriteFile(modulesPath, buf.Bytes(), 0644, helpers.AtomicWriteFollow)
}
Esempio n. 17
0
func addUdevRuleForSnap(snapname, newRule string) error {
	udevRulesFile := udevRulesPathForPart(snapname)

	rules, err := ioutil.ReadFile(udevRulesFile)
	if nil != err && !os.IsNotExist(err) {
		return err
	}

	// At this point either rules variable contains some rules if the
	// file exists, or it is nil if the file does not exist yet.
	// In both cases, updatedRules will have the right content.
	updatedRules := append(rules, newRule...)

	if err := helpers.AtomicWriteFile(udevRulesFile, updatedRules, 0644, 0); nil != err {
		return err
	}

	return nil
}
Esempio n. 18
0
func removeUdevRuleForSnap(snapname, device string) error {
	udevRulesFile := udevRulesPathForPart(snapname)

	file, err := os.Open(udevRulesFile)
	if nil != err && !os.IsNotExist(err) {
		return err
	}

	// Get the full list of rules to keep
	var rulesToKeep []string
	scanner := bufio.NewScanner(file)
	devicePattern := "\"" + filepath.Base(device) + "\""

	for scanner.Scan() {
		rule := scanner.Text()
		if "" != rule && !strings.Contains(rule, devicePattern) {
			rulesToKeep = append(rulesToKeep, rule)
		}
	}
	file.Close()

	// Update the file with the remaining rules or delete it
	// if there is not any rule left.
	if 0 < len(rulesToKeep) {
		// Appending the []string list of rules in a single
		// string to convert it later in []byte
		var out string
		for _, rule := range rulesToKeep {
			out = out + rule + "\n"
		}

		if err := helpers.AtomicWriteFile(udevRulesFile, []byte(out), 0644, 0); nil != err {
			return err
		}
	} else {
		if err := os.Remove(udevRulesFile); nil != err {
			return err
		}
	}

	return nil
}
Esempio n. 19
0
func writeHWAccessJSONFile(snapname string, appArmorAdditional appArmorAdditionalJSON) error {
	if len(appArmorAdditional.WritePath) == 0 {
		appArmorAdditional.ReadPath = nil
	} else {
		appArmorAdditional.ReadPath = []string{udevDataGlob}
	}
	out, err := json.MarshalIndent(appArmorAdditional, "", "  ")
	if err != nil {
		return err
	}
	// append final newline
	out = append(out, '\n')

	additionalFile := getHWAccessJSONFile(snapname)
	if err := helpers.AtomicWriteFile(additionalFile, out, 0640, 0); err != nil {
		return err
	}

	return nil
}
Esempio n. 20
0
func writeOemHardwareUdevRules(m *packageYaml) error {
	os.MkdirAll(dirs.SnapUdevRulesDir, 0755)

	// cleanup
	if err := cleanupOemHardwareUdevRules(m); err != nil {
		return err
	}
	// write new files
	for _, h := range m.OEM.Hardware.Assign {
		rulesContent, err := h.generateUdevRuleContent()
		if err != nil {
			return err
		}
		outfile := filepath.Join(dirs.SnapUdevRulesDir, fmt.Sprintf("80-snappy_%s_%s.rules", m.Name, h.PartID))
		if err := helpers.AtomicWriteFile(outfile, []byte(rulesContent), 0644, 0); err != nil {
			return err
		}
	}

	return nil
}
Esempio n. 21
0
func writeHWAccessYamlFile(snapname string, appArmorAdditional SecurityOverrideDefinition) error {
	if len(appArmorAdditional.WritePaths) == 0 {
		appArmorAdditional.ReadPaths = nil
	} else {
		appArmorAdditional.ReadPaths = []string{udevDataGlob}
	}
	out, err := yaml.Marshal(appArmorAdditional)
	if err != nil {
		return err
	}

	additionalFile := getHWAccessYamlFile(snapname)
	if !helpers.FileExists(filepath.Dir(additionalFile)) {
		if err := os.MkdirAll(filepath.Dir(additionalFile), 0755); err != nil {
			return err
		}
	}
	if err := helpers.AtomicWriteFile(additionalFile, out, 0640, 0); err != nil {
		return err
	}

	return nil
}
Esempio n. 22
0
	tz, err := ioutil.ReadFile(tzFile())
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(string(tz)), nil
}

// setTimezone sets the specified timezone for the system, an error is returned
// if it can't.
var setTimezone = func(timezone string) error {
	if err := helpers.CopyFile(filepath.Join(tzZoneInfoPath, timezone), tzZoneInfoTarget, helpers.CopyFlagOverwrite); err != nil {
		return err
	}

	return helpers.AtomicWriteFile(tzFile(), []byte(timezone), 0644, helpers.AtomicWriteFollow)
}

func getPassthrough(rootDir string) (pc []passthroughConfig, err error) {
	filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			return nil
		}
		content, err := ioutil.ReadFile(path)
		if err != nil {
			return err
		}
		pc = append(pc, passthroughConfig{
			Name:    path[len(rootDir):],
			Content: string(content),
		})
Esempio n. 23
0
func addPackageServices(m *snapYaml, baseDir string, inhibitHooks bool, inter interacter) error {
	for _, app := range m.Apps {
		if app.Daemon == "" {
			continue
		}
		aaProfile, err := getSecurityProfile(m, app.Name, baseDir)
		if err != nil {
			return err
		}
		// this will remove the global base dir when generating the
		// service file, this ensures that /snaps/foo/1.0/bin/start
		// is in the service file when the SetRoot() option
		// is used
		realBaseDir := stripGlobalRootDir(baseDir)
		// Generate service file
		content, err := generateSnapServicesFile(app, realBaseDir, aaProfile, m)
		if err != nil {
			return err
		}
		serviceFilename := generateServiceFileName(m, app)
		os.MkdirAll(filepath.Dir(serviceFilename), 0755)
		if err := helpers.AtomicWriteFile(serviceFilename, []byte(content), 0644, 0); err != nil {
			return err
		}
		// Generate systemd socket file if needed
		if app.Socket {
			content, err := generateSnapSocketFile(app, realBaseDir, aaProfile, m)
			if err != nil {
				return err
			}
			socketFilename := generateSocketFileName(m, app)
			os.MkdirAll(filepath.Dir(socketFilename), 0755)
			if err := helpers.AtomicWriteFile(socketFilename, []byte(content), 0644, 0); err != nil {
				return err
			}
		}
		// If necessary, generate the DBus policy file so the framework
		// service is allowed to start
		if m.Type == snap.TypeFramework && app.BusName != "" {
			content, err := genBusPolicyFile(app.BusName)
			if err != nil {
				return err
			}
			policyFilename := generateBusPolicyFileName(m, app)
			os.MkdirAll(filepath.Dir(policyFilename), 0755)
			if err := helpers.AtomicWriteFile(policyFilename, []byte(content), 0644, 0); err != nil {
				return err
			}
		}

		// daemon-reload and start only if we are not in the
		// inhibitHooks mode
		//
		// *but* always run enable (which just sets a symlink)
		serviceName := filepath.Base(generateServiceFileName(m, app))
		sysd := systemd.New(dirs.GlobalRootDir, inter)
		if !inhibitHooks {
			if err := sysd.DaemonReload(); err != nil {
				return err
			}
		}

		// we always enable the service even in inhibit hooks
		if err := sysd.Enable(serviceName); err != nil {
			return err
		}

		if !inhibitHooks {
			if err := sysd.Start(serviceName); err != nil {
				return err
			}
		}

		if app.Socket {
			socketName := filepath.Base(generateSocketFileName(m, app))
			// we always enable the socket even in inhibit hooks
			if err := sysd.Enable(socketName); err != nil {
				return err
			}

			if !inhibitHooks {
				if err := sysd.Start(socketName); err != nil {
					return err
				}
			}
		}
	}

	return nil
}