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 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 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 *RpmPackagesDetector) Detect(data map[string][]byte) ([]*database.Package, error) { f, hasFile := data["var/lib/rpm/Packages"] if !hasFile { return []*database.Package{}, nil } // Create a map to store packages and ensure their uniqueness packagesMap := make(map[string]*database.Package) // 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.Package{}, 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.Package{}, 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.Package{}, 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.Package{Name: line[0], Version: version} packagesMap[pkg.Key()] = pkg } // Convert the map to a slice packages := make([]*database.Package, 0, len(packagesMap)) for _, pkg := range packagesMap { packages = append(packages, pkg) } return packages, nil }