func updateRepository(pathToRepo string) (int, error) { // Pull repository out, err := utils.Exec(pathToRepo, "bzr", "pull", "--overwrite") if err != nil { log.Errorf("could not pull Ubuntu repository: %s. output: %s", err, string(out)) return 0, cerrors.ErrCouldNotDownload } // Get revision number if strings.Contains(string(out), "No revisions or tags to pull") { out, _ = utils.Exec(pathToRepo, "bzr", "revno") revno, err := strconv.Atoi(string(out[:len(out)-1])) if err != nil { log.Errorf("could not parse Ubuntu repository revision number: %s. output: %s", err, string(out)) return 0, cerrors.ErrCouldNotDownload } return revno, nil } regexpMatches := revisionRegexp.FindStringSubmatch(string(out)) if len(regexpMatches) != 2 { log.Error("could not parse bzr pull output to get the revision number") return 0, cerrors.ErrCouldNotDownload } revno, err := strconv.Atoi(regexpMatches[1]) if err != nil { log.Error("could not parse bzr pull output to get the revision number") return 0, cerrors.ErrCouldNotDownload } return revno, nil }
func (f *fetcher) pullRepository() (commit string, err error) { // If the repository doesn't exist, clone it. if _, pathExists := os.Stat(f.repositoryLocalPath); f.repositoryLocalPath == "" || os.IsNotExist(pathExists) { if f.repositoryLocalPath, err = ioutil.TempDir(os.TempDir(), "alpine-secdb"); err != nil { return "", ErrFilesystem } if out, err := utils.Exec(f.repositoryLocalPath, "git", "clone", secdbGitURL, "."); err != nil { f.Clean() log.Errorf("could not pull alpine-secdb repository: %s. output: %s", err, out) return "", cerrors.ErrCouldNotDownload } } else { // The repository exists and it needs to be refreshed via a pull. _, err := utils.Exec(f.repositoryLocalPath, "git", "pull") if err != nil { return "", ErrGitFailure } } out, err := utils.Exec(f.repositoryLocalPath, "git", "rev-parse", "HEAD") if err != nil { return "", ErrGitFailure } commit = strings.TrimSpace(string(out)) return }
func (fetcher *UbuntuFetcher) pullRepository() (err error) { // Determine whether we should branch or pull. if _, pathExists := os.Stat(fetcher.repositoryLocalPath); fetcher.repositoryLocalPath == "" || os.IsNotExist(pathExists) { // Create a temporary folder to store the repository. if fetcher.repositoryLocalPath, err = ioutil.TempDir(os.TempDir(), "ubuntu-cve-tracker"); err != nil { return ErrFilesystem } // Branch repository. if out, err := utils.Exec(fetcher.repositoryLocalPath, "bzr", "branch", "--use-existing-dir", trackerRepository, "."); err != nil { log.Errorf("could not branch Ubuntu repository: %s. output: %s", err, out) return cerrors.ErrCouldNotDownload } return nil } // Pull repository. if out, err := utils.Exec(fetcher.repositoryLocalPath, "bzr", "pull", "--overwrite"); err != nil { os.RemoveAll(fetcher.repositoryLocalPath) log.Errorf("could not pull Ubuntu repository: %s. output: %s", err, out) return cerrors.ErrCouldNotDownload } return nil }
func collectModifiedVulnerabilities(revision int, dbRevision, repositoryLocalPath string) (map[string]struct{}, error) { modifiedCVE := make(map[string]struct{}) // Handle a brand new database. if dbRevision == "" { for _, folder := range []string{"active", "retired"} { d, err := os.Open(repositoryLocalPath + "/" + folder) if err != nil { log.Errorf("could not open Ubuntu vulnerabilities repository's folder: %s", err) return nil, ErrFilesystem } defer d.Close() // Get the FileInfo of all the files in the directory. names, err := d.Readdirnames(-1) if err != nil { log.Errorf("could not read Ubuntu vulnerabilities repository's folder:: %s.", err) return nil, ErrFilesystem } // Add the vulnerabilities to the list. for _, name := range names { if strings.HasPrefix(name, "CVE-") { modifiedCVE[folder+"/"+name] = struct{}{} } } } return modifiedCVE, nil } // Handle an up to date database. dbRevisionInt, _ := strconv.Atoi(dbRevision) if revision == dbRevisionInt { log.Debug("no Ubuntu update") return modifiedCVE, nil } // Handle a database that needs upgrading. out, err := utils.Exec(repositoryLocalPath, "bzr", "log", "--verbose", "-r"+strconv.Itoa(dbRevisionInt+1)+"..", "-n0") if err != nil { log.Errorf("could not get Ubuntu vulnerabilities repository logs: %s. output: %s", err, string(out)) return nil, cerrors.ErrCouldNotDownload } scanner := bufio.NewScanner(bytes.NewReader(out)) for scanner.Scan() { text := strings.TrimSpace(scanner.Text()) if strings.Contains(text, "CVE-") && (strings.HasPrefix(text, "active/") || strings.HasPrefix(text, "retired/")) { if strings.Contains(text, " => ") { text = text[strings.Index(text, " => ")+4:] } modifiedCVE[text] = struct{}{} } } return modifiedCVE, nil }
func updateRepository(pathToRepo string) error { // Pull repository out, err := utils.Exec(pathToRepo, "bzr", "pull", "--overwrite") if err != nil { log.Errorf("could not pull Ubuntu repository: %s. output: %s", err, out) return cerrors.ErrCouldNotDownload } return nil }
func createRepository(pathToRepo string) error { // Branch repository out, err := utils.Exec("/tmp/", "bzr", "branch", trackerRepository, pathToRepo) if err != nil { log.Errorf("could not branch Ubuntu repository: %s. output: %s", err, out) return cerrors.ErrCouldNotDownload } return nil }
func getRevisionNumber(pathToRepo string) (int, error) { out, err := utils.Exec(pathToRepo, "bzr", "revno") if err != nil { log.Errorf("could not get Ubuntu repository's revision number: %s. output: %s", err, out) return 0, cerrors.ErrCouldNotDownload } revno, err := strconv.Atoi(strings.TrimSpace(string(out))) if err != nil { log.Errorf("could not parse Ubuntu repository's revision number: %s. output: %s", err, out) return 0, cerrors.ErrCouldNotDownload } return revno, nil }
func createRepository(pathToRepo string) (int, error) { // Branch repository out, err := utils.Exec("/tmp/", "bzr", "branch", ubuntuTracker, pathToRepo) if err != nil { log.Errorf("could not branch Ubuntu repository: %s. output: %s", err, string(out)) return 0, cerrors.ErrCouldNotDownload } // Get revision number regexpMatches := branchedRegexp.FindStringSubmatch(string(out)) if len(regexpMatches) != 2 { log.Error("could not parse bzr branch output to get the revision number") return 0, cerrors.ErrCouldNotDownload } revision, err := strconv.Atoi(regexpMatches[1]) if err != nil { log.Error("could not parse bzr branch output to get the revision number") return 0, cerrors.ErrCouldNotDownload } return revision, err }
// Detect detects packages using var/lib/rpm/Packages from the input data func (detector *RpmFeaturesDetector) Detect(data map[string][]byte) ([]database.FeatureVersion, error) { f, hasFile := data["var/lib/rpm/Packages"] if !hasFile { return []database.FeatureVersion{}, nil } // Create a map to store packages and ensure their uniqueness packagesMap := make(map[string]database.FeatureVersion) // Write the required "Packages" file to disk tmpDir, err := ioutil.TempDir(os.TempDir(), "rpm") defer os.RemoveAll(tmpDir) if err != nil { log.Errorf("could not create temporary folder for RPM detection: %s", err) return []database.FeatureVersion{}, cerrors.ErrFilesystem } err = ioutil.WriteFile(tmpDir+"/Packages", f, 0700) if err != nil { log.Errorf("could not create temporary file for RPM detection: %s", err) return []database.FeatureVersion{}, cerrors.ErrFilesystem } // Query RPM // We actually extract binary package names instead of source package names here because RHSA refers to package names // In the dpkg system, we extract the source instead out, err := utils.Exec(tmpDir, "rpm", "--dbpath", tmpDir, "-qa", "--qf", "%{NAME} %{EPOCH}:%{VERSION}-%{RELEASE}\n") if err != nil { log.Errorf("could not query RPM: %s. output: %s", err, string(out)) // Do not bubble up because we probably won't be able to fix it, // the database must be corrupted return []database.FeatureVersion{}, nil } scanner := bufio.NewScanner(strings.NewReader(string(out))) for scanner.Scan() { line := strings.Split(scanner.Text(), " ") if len(line) != 2 { // We may see warnings on some RPM versions: // "warning: Generating 12 missing index(es), please wait..." continue } // Ignore gpg-pubkey packages which are fake packages used to store GPG keys - they are not versionned properly. if line[0] == "gpg-pubkey" { continue } // Parse version version, err := types.NewVersion(strings.Replace(line[1], "(none):", "", -1)) if err != nil { log.Warningf("could not parse package version '%s': %s. skipping", line[1], err.Error()) continue } // Add package pkg := database.FeatureVersion{ Feature: database.Feature{ Name: line[0], }, Version: version, } packagesMap[pkg.Feature.Name+"#"+pkg.Version.String()] = pkg } // Convert the map to a slice packages := make([]database.FeatureVersion, 0, len(packagesMap)) for _, pkg := range packagesMap { packages = append(packages, pkg) } return packages, nil }