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 }
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) }
// 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) }
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 }
// 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 }
// 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) }
// 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) }
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) }
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) }
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) }
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) }
// 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 }
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) }
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) }
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 }
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 }
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 }
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 }
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 }
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), })
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 }