func getLastUpdate() time.Time { if lastUpdateTSS, err := database.GetFlagValue(flagName); err == nil && lastUpdateTSS != "" { if lastUpdateTS, err := strconv.ParseInt(lastUpdateTSS, 10, 64); err == nil { return time.Unix(lastUpdateTS, 0).UTC() } } return time.Time{} }
// FetchUpdate fetches vulnerability updates from the Debian Security Tracker. func (fetcher *DebianFetcher) FetchUpdate() (resp updater.FetcherResponse, err error) { log.Info("fetching Debian vulneratibilities") // Download JSON. r, err := http.Get(url) if err != nil { log.Errorf("could not download Debian's update: %s", err) return resp, cerrors.ErrCouldNotDownload } // Get the SHA-1 of the latest update's JSON data latestHash, err := database.GetFlagValue(debianUpdaterFlag) if err != nil { return resp, err } // Parse the JSON. resp, err = buildResponse(r.Body, latestHash) if err != nil { return resp, err } return resp, nil }
// Run updates the vulnerability database at regular intervals func Run(interval time.Duration, st *utils.Stopper) { defer st.End() // Do not run the updater if the interval is 0 if interval == 0 { log.Infof("updater service is disabled.") return } whoAmI := uuid.New() healthIdentifier = whoAmI log.Infof("updater service started. lock identifier: %s", whoAmI) for { // Set the next update time to (last update time + interval) or now if there // is no last update time stored in database (first update) or if an error // occurs nextUpdate := time.Now().UTC() if lastUpdateTSS, err := database.GetFlagValue(flagName); err == nil && lastUpdateTSS != "" { if lastUpdateTS, err := strconv.ParseInt(lastUpdateTSS, 10, 64); err == nil { healthLatestSuccessfulUpdate = time.Unix(lastUpdateTS, 0) nextUpdate = time.Unix(lastUpdateTS, 0).Add(interval) } } // If the next update timer is in the past, then try to update. if nextUpdate.Before(time.Now().UTC()) { // Attempt to get a lock on the the update. log.Debug("attempting to obtain update lock") hasLock, hasLockUntil := database.Lock(flagName, lockDuration, whoAmI) if hasLock { healthLockOwner = healthIdentifier // Launch update in a new go routine. doneC := make(chan bool, 1) go func() { Update() doneC <- true }() for done := false; !done; { select { case <-doneC: done = true case <-time.After(refreshLockDuration): // Refresh the lock until the update is done. database.Lock(flagName, lockDuration, whoAmI) } } // Unlock the update. database.Unlock(flagName, whoAmI) } else { lockOwner, lockExpiration, err := database.LockInfo(flagName) if err != nil { log.Debug("update lock is already taken") nextUpdate = hasLockUntil } else { log.Debugf("update lock is already taken by %s until %v", lockOwner, lockExpiration) nextUpdate = lockExpiration healthLockOwner = lockOwner } } } // Sleep, but remain stoppable until approximately the next update time. now := time.Now().UTC() waitUntil := nextUpdate.Add(time.Duration(rand.ExpFloat64()/0.5) * time.Second) log.Debugf("next update attempt scheduled for %v.", waitUntil) if !waitUntil.Before(now) { if !st.Sleep(waitUntil.Sub(time.Now())) { break } } } log.Info("updater service stopped") }
// FetchUpdate gets vulnerability updates from the Ubuntu CVE Tracker. func (fetcher *UbuntuFetcher) FetchUpdate() (resp updater.FetcherResponse, err error) { log.Info("fetching Ubuntu vulneratibilities") // Check to see if the repository does not already exist. if _, pathExists := os.Stat(repositoryLocalPath); repositoryLocalPath == "" || os.IsNotExist(pathExists) { // Create a temporary folder and download the repository. p, err := ioutil.TempDir(os.TempDir(), "ubuntu-cve-tracker") if err != nil { return resp, ErrFilesystem } // bzr wants an empty target directory. repositoryLocalPath = p + "/repository" // Create the new repository. err = createRepository(repositoryLocalPath) if err != nil { return resp, err } } else { // Update the repository that's already on disk. err = updateRepository(repositoryLocalPath) if err != nil { return resp, err } } // Get revision number. revisionNumber, err := getRevisionNumber(repositoryLocalPath) if err != nil { return resp, err } // Get the latest revision number we successfully applied in the database. dbRevisionNumber, err := database.GetFlagValue("ubuntuUpdater") if err != nil { return resp, err } // Get the list of vulnerabilities that we have to update. modifiedCVE, err := collectModifiedVulnerabilities(revisionNumber, dbRevisionNumber, repositoryLocalPath) if err != nil { return resp, err } // Parse and add the vulnerabilities. for cvePath := range modifiedCVE { file, err := os.Open(repositoryLocalPath + "/" + cvePath) if err != nil { // This can happen when a file is modified and then moved in another // commit. continue } v, pkgs, unknownReleases, err := parseUbuntuCVE(file) if err != nil { return resp, err } if len(v.FixedInNodes) > 0 { resp.Vulnerabilities = append(resp.Vulnerabilities, v) resp.Packages = append(resp.Packages, pkgs...) } // Log any unknown releases. for k := range unknownReleases { note := fmt.Sprintf("Ubuntu %s is not mapped to any version number (eg. trusty->14.04). Please update me.", k) resp.Notes = append(resp.Notes, note) log.Warning(note) // If we encountered unknown Ubuntu release, we don't want the revision // number to be considered as managed. dbRevisionNumberInt, _ := strconv.Atoi(dbRevisionNumber) revisionNumber = dbRevisionNumberInt } // Close the file manually. // // We do that instead of using defer because defer works on a function-level scope. // We would open many files and close them all at once at the end of the function, // which could lead to exceed fs.file-max. file.Close() } // Add flag information resp.FlagName = ubuntuUpdaterFlag resp.FlagValue = strconv.Itoa(revisionNumber) return }
func getNotes() (notes []string) { if jsonNotes, err := database.GetFlagValue(notesFlagName); err == nil && jsonNotes != "" { json.Unmarshal([]byte(jsonNotes), notes) } return }
// FetchUpdate gets vulnerability updates from the Red Hat OVAL definitions. func (f *RHELFetcher) FetchUpdate() (resp updater.FetcherResponse, err error) { log.Info("fetching Red Hat vulneratibilities") // Get the first RHSA we have to manage. flagValue, err := database.GetFlagValue(rhelUpdaterFlag) if err != nil { return resp, err } firstRHSA, err := strconv.Atoi(flagValue) if firstRHSA == 0 || err != nil { firstRHSA = firstRHEL5RHSA } // Fetch the update list. r, err := http.Get(ovalURI) if err != nil { log.Errorf("could not download RHEL's update list: %s", err) return resp, cerrors.ErrCouldNotDownload } // Get the list of RHSAs that we have to process. var rhsaList []int scanner := bufio.NewScanner(r.Body) for scanner.Scan() { line := scanner.Text() r := rhsaRegexp.FindStringSubmatch(line) if len(r) == 2 { rhsaNo, _ := strconv.Atoi(r[1]) if rhsaNo > firstRHSA { rhsaList = append(rhsaList, rhsaNo) } } } for _, rhsa := range rhsaList { // Download the RHSA's XML file. r, err := http.Get(ovalURI + rhsaFilePrefix + strconv.Itoa(rhsa) + ".xml") if err != nil { log.Errorf("could not download RHEL's update file: %s", err) return resp, cerrors.ErrCouldNotDownload } // Parse the XML. vs, err := parseRHSA(r.Body) if err != nil { return resp, err } // Collect vulnerabilities. for _, v := range vs { if len(v.FixedIn) > 0 { resp.Vulnerabilities = append(resp.Vulnerabilities, v) } } } // Set the flag if we found anything. if len(rhsaList) > 0 { resp.FlagName = rhelUpdaterFlag resp.FlagValue = strconv.Itoa(rhsaList[len(rhsaList)-1]) } else { log.Debug("no Red Hat update.") } return resp, nil }