예제 #1
0
파일: updater.go 프로젝트: dwdm/clair
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{}
}
예제 #2
0
파일: debian.go 프로젝트: dwdm/clair
// 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
}
예제 #3
0
파일: updater.go 프로젝트: neujie/clair
// 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")
}
예제 #4
0
파일: ubuntu.go 프로젝트: dwdm/clair
// 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
}
예제 #5
0
파일: updater.go 프로젝트: dwdm/clair
func getNotes() (notes []string) {
	if jsonNotes, err := database.GetFlagValue(notesFlagName); err == nil && jsonNotes != "" {
		json.Unmarshal([]byte(jsonNotes), notes)
	}
	return
}
예제 #6
0
파일: rhel.go 프로젝트: ruo91/clair
// 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
}