Exemple #1
0
func (v Vulnerability) DatabaseModel() (database.Vulnerability, error) {
	severity := types.Priority(v.Severity)
	if !severity.IsValid() {
		return database.Vulnerability{}, errors.New("Invalid severity")
	}

	var dbFeatures []database.FeatureVersion
	for _, feature := range v.FixedIn {
		dbFeature, err := feature.DatabaseModel()
		if err != nil {
			return database.Vulnerability{}, err
		}

		dbFeatures = append(dbFeatures, dbFeature)
	}

	return database.Vulnerability{
		Name:        v.Name,
		Namespace:   database.Namespace{Name: v.Namespace},
		Description: v.Description,
		Link:        v.Link,
		Severity:    severity,
		Metadata:    v.Metadata,
		FixedIn:     dbFeatures,
	}, nil
}
Exemple #2
0
// GETLayersVulnerabilities returns the complete list of vulnerabilities that
// a layer has if it exists.
func GETLayersVulnerabilities(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	// Get minumum priority parameter.
	minimumPriority := types.Priority(r.URL.Query().Get("minimumPriority"))
	if minimumPriority == "" {
		minimumPriority = "High" // Set default priority to High
	} else if !minimumPriority.IsValid() {
		httputils.WriteHTTPError(w, 0, cerrors.NewBadRequestError("invalid priority"))
		return
	}

	// Find layer
	layer, err := database.FindOneLayerByID(p.ByName("id"), []string{database.FieldLayerParent, database.FieldLayerPackages})
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	// Find layer's packages.
	packagesNodes, err := layer.AllPackages()
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	// Find vulnerabilities.
	vulnerabilities, err := getVulnerabilitiesFromLayerPackagesNodes(packagesNodes, minimumPriority, []string{database.FieldVulnerabilityID, database.FieldVulnerabilityLink, database.FieldVulnerabilityPriority, database.FieldVulnerabilityDescription, database.FieldVulnerabilityCausedByPackage})
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	httputils.WriteHTTP(w, http.StatusOK, struct{ Vulnerabilities []*database.Vulnerability }{Vulnerabilities: vulnerabilities})
}
Exemple #3
0
func ClairServiceInit() error {
	// Load database setting
	if setting.ClairDBPath != "" {
		clairConf.DBPath = setting.ClairDBPath
	} else {
		clairConf.DBPath = DefaultClairDBPath
	}

	clairConf.KeepDB = setting.ClairKeepDB
	clairConf.LogLevel = setting.ClairLogLevel
	clairConf.Duration = setting.ClairUpdateDuration
	clairConf.VulnPriority = setting.ClairVulnPriority

	// Set database
	if err := database.Open("bolt", clairConf.DBPath); err != nil {
		logrus.Debug(err)
		return err
	}

	// Set logLevel of clair lib
	logLevel, err := capnslog.ParseLevel(strings.ToUpper(clairConf.LogLevel))
	if err != nil {
		logLevel, _ = capnslog.ParseLevel(strings.ToUpper(DefaultClairLogLevel))
	}
	capnslog.SetGlobalLogLevel(logLevel)
	capnslog.SetFormatter(capnslog.NewPrettyFormatter(os.Stdout, false))

	// Set minumum priority parameter.
	if types.Priority(clairConf.VulnPriority).IsValid() {
		logrus.Debugf("Vuln priority is invalid :%v.", clairConf.VulnPriority)
		clairConf.VulnPriority = DefaultClairVulnPriority
	}

	// Set 'duration' and Update the CVE database
	if clairConf.Duration == "" {
		logrus.Debugf("No duration set, so only update at the beginning.")
		go updater.Update()
		clairStopper = nil
	} else {
		st := utils.NewStopper()
		st.Begin()
		d, err := time.ParseDuration(clairConf.Duration)
		if err != nil {
			logrus.Warnf("Wrong duration format, use the default duration: %v.", DefaultClairUpdateDuration)
			clairConf.Duration = DefaultClairUpdateDuration
			d, err = time.ParseDuration(clairConf.Duration)
			if err != nil {
				logrus.Debugf("Cannot pare du %v", err)
			}
		}

		go updater.Run(d, st)
		clairStopper = st
		st.Begin()
	}
	return nil
}
Exemple #4
0
func intMain() int {
	// Parse command-line arguments.
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, "Usage: %s [options] image-id\n\nOptions:\n", os.Args[0])
		flag.PrintDefaults()
	}
	flag.Parse()

	if len(flag.Args()) != 1 {
		flag.Usage()
		return 1
	}
	imageName := flag.Args()[0]

	minSeverity := types.Priority(*flagMinimumSeverity)
	if !minSeverity.IsValid() {
		flag.Usage()
		return 1
	}

	if *flagColorMode == "never" {
		color.NoColor = true
	} else if *flagColorMode == "always" {
		color.NoColor = false
	}

	// Create a temporary folder.
	tmpPath, err := ioutil.TempDir("", "analyze-local-image-")
	if err != nil {
		log.Fatalf("Could not create temporary folder: %s", err)
	}
	defer os.RemoveAll(tmpPath)

	// Intercept SIGINT / SIGKILl signals.
	interrupt := make(chan os.Signal)
	signal.Notify(interrupt, os.Interrupt, os.Kill)

	// Analyze the image.
	analyzeCh := make(chan error, 1)
	go func() {
		analyzeCh <- AnalyzeLocalImage(imageName, minSeverity, *flagEndpoint, *flagMyAddress, tmpPath)
	}()

	select {
	case <-interrupt:
		return 130
	case err := <-analyzeCh:
		if err != nil {
			log.Print(err)
			return 1
		}
	}
	return 0
}
Exemple #5
0
// POSTBatchLayersVulnerabilities returns the complete list of vulnerabilities
// that the provided layers have, if they all exist.
func POSTBatchLayersVulnerabilities(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	// Parse body
	var parameters POSTBatchLayersVulnerabilitiesParameters
	if s, err := httputils.ParseHTTPBody(r, &parameters); err != nil {
		httputils.WriteHTTPError(w, s, err)
		return
	}
	if len(parameters.LayersIDs) == 0 {
		httputils.WriteHTTPError(w, http.StatusBadRequest, errors.New("at least one LayerID query parameter must be provided"))
		return
	}

	// Get minumum priority parameter.
	minimumPriority := types.Priority(r.URL.Query().Get("minimumPriority"))
	if minimumPriority == "" {
		minimumPriority = "High" // Set default priority to High
	} else if !minimumPriority.IsValid() {
		httputils.WriteHTTPError(w, 0, cerrors.NewBadRequestError("invalid priority"))
		return
	}

	response := make(map[string]interface{})
	// For each LayerID parameter
	for _, layerID := range parameters.LayersIDs {
		// Find layer
		layer, err := database.FindOneLayerByID(layerID, []string{database.FieldLayerParent, database.FieldLayerPackages})
		if err != nil {
			httputils.WriteHTTPError(w, 0, err)
			return
		}

		// Find layer's packages.
		packagesNodes, err := layer.AllPackages()
		if err != nil {
			httputils.WriteHTTPError(w, 0, err)
			return
		}

		// Find vulnerabilities.
		vulnerabilities, err := getVulnerabilitiesFromLayerPackagesNodes(packagesNodes, minimumPriority, []string{database.FieldVulnerabilityID, database.FieldVulnerabilityLink, database.FieldVulnerabilityPriority, database.FieldVulnerabilityDescription, database.FieldVulnerabilityCausedByPackage})
		if err != nil {
			httputils.WriteHTTPError(w, 0, err)
			return
		}

		response[layerID] = struct{ Vulnerabilities []*database.Vulnerability }{Vulnerabilities: vulnerabilities}
	}

	httputils.WriteHTTP(w, http.StatusOK, response)
}
Exemple #6
0
func GetVulns(ID string) ([]*database.Vulnerability, error) {
	layer, err := database.FindOneLayerByID(ID, []string{database.FieldLayerParent, database.FieldLayerPackages})
	if err != nil {
		logrus.Debugf("Cannot get layer: %v", err)
		return nil, err
	}

	packagesNodes, err := layer.AllPackages()
	if err != nil {
		logrus.Debugf("Cannot get packages: %v", err)
		return nil, err
	}

	return getVulnerabilitiesFromLayerPackagesNodes(packagesNodes, types.Priority(clairConf.VulnPriority), []string{database.FieldVulnerabilityID, database.FieldVulnerabilityLink, database.FieldVulnerabilityPriority, database.FieldVulnerabilityDescription})
}
Exemple #7
0
// GETLayersVulnerabilitiesDiff returns the list of vulnerabilities that a layer
// adds and removes if it exists.
func GETLayersVulnerabilitiesDiff(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
	// Get minumum priority parameter.
	minimumPriority := types.Priority(r.URL.Query().Get("minimumPriority"))
	if minimumPriority == "" {
		minimumPriority = "High" // Set default priority to High
	} else if !minimumPriority.IsValid() {
		httputils.WriteHTTPError(w, 0, cerrors.NewBadRequestError("invalid priority"))
		return
	}

	// Find layer.
	layer, err := database.FindOneLayerByID(p.ByName("id"), []string{database.FieldLayerPackages})
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	// Selected fields for vulnerabilities.
	selectedFields := []string{database.FieldVulnerabilityID, database.FieldVulnerabilityLink, database.FieldVulnerabilityPriority, database.FieldVulnerabilityDescription, database.FieldVulnerabilityCausedByPackage}

	// Find vulnerabilities for installed packages.
	addedVulnerabilities, err := getVulnerabilitiesFromLayerPackagesNodes(layer.InstalledPackagesNodes, minimumPriority, selectedFields)
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	// Find vulnerabilities for removed packages.
	removedVulnerabilities, err := getVulnerabilitiesFromLayerPackagesNodes(layer.RemovedPackagesNodes, minimumPriority, selectedFields)
	if err != nil {
		httputils.WriteHTTPError(w, 0, err)
		return
	}

	// Remove vulnerabilities which appears both in added and removed lists (eg. case of updated packages but still vulnerable).
	for ia, a := range addedVulnerabilities {
		for ir, r := range removedVulnerabilities {
			if a.ID == r.ID {
				addedVulnerabilities = append(addedVulnerabilities[:ia], addedVulnerabilities[ia+1:]...)
				removedVulnerabilities = append(removedVulnerabilities[:ir], removedVulnerabilities[ir+1:]...)
			}
		}
	}

	httputils.WriteHTTP(w, http.StatusOK, struct{ Adds, Removes []*database.Vulnerability }{Adds: addedVulnerabilities, Removes: removedVulnerabilities})
}
Exemple #8
0
// toVulnerabilities converts a path leading to one or multiple vulnerabilities to Vulnerability structs, selecting the specified fields
func toVulnerabilities(path *path.Path, selectedFields []string) ([]*Vulnerability, error) {
	var vulnerabilities []*Vulnerability

	saveFields(path, selectedFields, []string{FieldVulnerabilityFixedIn, FieldVulnerabilityCausedByPackage})
	it, _ := path.BuildIterator().Optimize()
	defer it.Close()
	for cayley.RawNext(it) {
		tags := make(map[string]graph.Value)
		it.TagResults(tags)

		vulnerability := Vulnerability{Node: store.NameOf(it.Result())}
		for _, selectedField := range selectedFields {
			switch selectedField {
			case FieldVulnerabilityID:
				vulnerability.ID = store.NameOf(tags[FieldVulnerabilityID])
			case FieldVulnerabilityLink:
				vulnerability.Link = store.NameOf(tags[FieldVulnerabilityLink])
			case FieldVulnerabilityPriority:
				vulnerability.Priority = types.Priority(store.NameOf(tags[FieldVulnerabilityPriority]))
			case FieldVulnerabilityDescription:
				vulnerability.Description = store.NameOf(tags[FieldVulnerabilityDescription])
			case FieldVulnerabilityFixedIn:
				var err error
				vulnerability.FixedInNodes, err = toValues(cayley.StartPath(store, vulnerability.Node).Out(FieldVulnerabilityFixedIn))
				if err != nil {
					log.Errorf("could not get fixedIn on vulnerability %s: %s.", vulnerability.Node, err.Error())
					return []*Vulnerability{}, err
				}
			case FieldVulnerabilityCausedByPackage:
				vulnerability.CausedByPackage = store.NameOf(tags[FieldVulnerabilityCausedByPackage])
			default:
				panic("unknown selectedField")
			}
		}
		vulnerabilities = append(vulnerabilities, &vulnerability)
	}
	if it.Err() != nil {
		log.Errorf("failed query in toVulnerabilities: %s", it.Err())
		return []*Vulnerability{}, ErrBackendException
	}

	return vulnerabilities, nil
}
Exemple #9
0
func ClairGetVulns(ID string, ParentID string, Path string) ([]*database.Vulnerability, error) {
	// Process data.
	logrus.Debugf("Start to get vulnerabilities: %v %v %v", ID, ParentID, Path)
	if err := worker.Process(ID, ParentID, Path); err != nil {
		logrus.Debugf("End find err process: %v", err)
		return nil, err
	}
	// Find layer
	layer, err := database.FindOneLayerByID(ID, []string{database.FieldLayerParent, database.FieldLayerPackages})
	if err != nil {
		logrus.Debugf("Cannot get layer: %v", err)
		return nil, err
	}

	// Find layer's packages.
	packagesNodes, err := layer.AllPackages()
	if err != nil {
		logrus.Debugf("Cannot get packages: %v", err)
		return nil, err
	}

	// Find vulnerabilities.
	return getVulnerabilitiesFromLayerPackagesNodes(packagesNodes, types.Priority(clairConf.VulnPriority), []string{database.FieldVulnerabilityID, database.FieldVulnerabilityLink, database.FieldVulnerabilityPriority, database.FieldVulnerabilityDescription})
}
Exemple #10
0
func TestInsertVulnerability(t *testing.T) {
	datastore, err := openDatabaseForTest("InsertVulnerability", false)
	if err != nil {
		t.Error(err)
		return
	}
	defer datastore.Close()

	// Create some data.
	n1 := database.Namespace{Name: "TestInsertVulnerabilityNamespace1"}
	n2 := database.Namespace{Name: "TestInsertVulnerabilityNamespace2"}

	f1 := database.FeatureVersion{
		Feature: database.Feature{
			Name:      "TestInsertVulnerabilityFeatureVersion1",
			Namespace: n1,
		},
		Version: types.NewVersionUnsafe("1.0"),
	}
	f2 := database.FeatureVersion{
		Feature: database.Feature{
			Name:      "TestInsertVulnerabilityFeatureVersion1",
			Namespace: n2,
		},
		Version: types.NewVersionUnsafe("1.0"),
	}
	f3 := database.FeatureVersion{
		Feature: database.Feature{
			Name: "TestInsertVulnerabilityFeatureVersion2",
		},
		Version: types.MaxVersion,
	}
	f4 := database.FeatureVersion{
		Feature: database.Feature{
			Name: "TestInsertVulnerabilityFeatureVersion2",
		},
		Version: types.NewVersionUnsafe("1.4"),
	}
	f5 := database.FeatureVersion{
		Feature: database.Feature{
			Name: "TestInsertVulnerabilityFeatureVersion3",
		},
		Version: types.NewVersionUnsafe("1.5"),
	}
	f6 := database.FeatureVersion{
		Feature: database.Feature{
			Name: "TestInsertVulnerabilityFeatureVersion4",
		},
		Version: types.NewVersionUnsafe("0.1"),
	}
	f7 := database.FeatureVersion{
		Feature: database.Feature{
			Name: "TestInsertVulnerabilityFeatureVersion5",
		},
		Version: types.MaxVersion,
	}
	f8 := database.FeatureVersion{
		Feature: database.Feature{
			Name: "TestInsertVulnerabilityFeatureVersion5",
		},
		Version: types.MinVersion,
	}

	// Insert invalid vulnerabilities.
	for _, vulnerability := range []database.Vulnerability{
		{
			Name:      "",
			Namespace: n1,
			FixedIn:   []database.FeatureVersion{f1},
			Severity:  types.Unknown,
		},
		{
			Name:      "TestInsertVulnerability0",
			Namespace: database.Namespace{},
			FixedIn:   []database.FeatureVersion{f1},
			Severity:  types.Unknown,
		},
		{
			Name:      "TestInsertVulnerability0-",
			Namespace: database.Namespace{},
			FixedIn:   []database.FeatureVersion{f1},
		},
		{
			Name:      "TestInsertVulnerability0",
			Namespace: n1,
			FixedIn:   []database.FeatureVersion{f1},
			Severity:  types.Priority(""),
		},
		{
			Name:      "TestInsertVulnerability0",
			Namespace: n1,
			FixedIn:   []database.FeatureVersion{f2},
			Severity:  types.Unknown,
		},
	} {
		err := datastore.InsertVulnerabilities([]database.Vulnerability{vulnerability}, true)
		assert.Error(t, err)
	}

	// Insert a simple vulnerability and find it.
	v1meta := make(map[string]interface{})
	v1meta["TestInsertVulnerabilityMetadata1"] = "TestInsertVulnerabilityMetadataValue1"
	v1meta["TestInsertVulnerabilityMetadata2"] = struct {
		Test string
	}{
		Test: "TestInsertVulnerabilityMetadataValue1",
	}

	v1 := database.Vulnerability{
		Name:        "TestInsertVulnerability1",
		Namespace:   n1,
		FixedIn:     []database.FeatureVersion{f1, f3, f6, f7},
		Severity:    types.Low,
		Description: "TestInsertVulnerabilityDescription1",
		Link:        "TestInsertVulnerabilityLink1",
		Metadata:    v1meta,
	}
	err = datastore.InsertVulnerabilities([]database.Vulnerability{v1}, true)
	if assert.Nil(t, err) {
		v1f, err := datastore.FindVulnerability(n1.Name, v1.Name)
		if assert.Nil(t, err) {
			equalsVuln(t, &v1, &v1f)
		}
	}

	// Update vulnerability.
	v1.Description = "TestInsertVulnerabilityLink2"
	v1.Link = "TestInsertVulnerabilityLink2"
	v1.Severity = types.High
	// Update f3 in f4, add fixed in f5, add fixed in f6 which already exists, removes fixed in f7 by
	// adding f8 which is f7 but with MinVersion.
	v1.FixedIn = []database.FeatureVersion{f4, f5, f6, f8}

	err = datastore.InsertVulnerabilities([]database.Vulnerability{v1}, true)
	if assert.Nil(t, err) {
		v1f, err := datastore.FindVulnerability(n1.Name, v1.Name)
		if assert.Nil(t, err) {
			// We already had f1 before the update.
			// Add it to the struct for comparison.
			v1.FixedIn = append(v1.FixedIn, f1)

			// Removes f8 from the struct for comparison as it was just here to cancel f7.
			for i := 0; i < len(v1.FixedIn); i++ {
				if v1.FixedIn[i].Feature.Name == f8.Feature.Name {
					v1.FixedIn = append(v1.FixedIn[:i], v1.FixedIn[i+1:]...)
				}
			}

			equalsVuln(t, &v1, &v1f)
		}
	}
}
Exemple #11
0
func AnalyzeLocalImage(imageName string, minSeverity types.Priority, endpoint, myAddress, tmpPath string) error {
	// Save image.
	log.Printf("Saving %s to local disk (this may take some time)", imageName)
	err := save(imageName, tmpPath)
	if err != nil {
		return fmt.Errorf("Could not save image: %s", err)
	}

	// Retrieve history.
	log.Println("Retrieving image history")
	layerIDs, err := historyFromManifest(tmpPath)
	if err != nil {
		layerIDs, err = historyFromCommand(imageName)
	}
	if err != nil || len(layerIDs) == 0 {
		return fmt.Errorf("Could not get image's history: %s", err)
	}

	// Setup a simple HTTP server if Clair is not local.
	if !strings.Contains(endpoint, "127.0.0.1") && !strings.Contains(endpoint, "localhost") {
		allowedHost := strings.TrimPrefix(endpoint, "http://")
		portIndex := strings.Index(allowedHost, ":")
		if portIndex >= 0 {
			allowedHost = allowedHost[:portIndex]
		}

		log.Printf("Setting up HTTP server (allowing: %s)\n", allowedHost)

		ch := make(chan error)
		go listenHTTP(tmpPath, allowedHost, ch)
		select {
		case err := <-ch:
			return fmt.Errorf("An error occured when starting HTTP server: %s", err)
		case <-time.After(100 * time.Millisecond):
			break
		}

		tmpPath = "http://" + myAddress + ":" + strconv.Itoa(httpPort)
	}

	// Analyze layers.
	log.Printf("Analyzing %d layers... \n", len(layerIDs))
	for i := 0; i < len(layerIDs); i++ {
		log.Printf("Analyzing %s\n", layerIDs[i])

		if i > 0 {
			err = analyzeLayer(endpoint, tmpPath+"/"+layerIDs[i]+"/layer.tar", layerIDs[i], layerIDs[i-1])
		} else {
			err = analyzeLayer(endpoint, tmpPath+"/"+layerIDs[i]+"/layer.tar", layerIDs[i], "")
		}
		if err != nil {
			return fmt.Errorf("Could not analyze layer: %s", err)
		}
	}

	// Get vulnerabilities.
	log.Println("Retrieving image's vulnerabilities")
	layer, err := getLayer(endpoint, layerIDs[len(layerIDs)-1])
	if err != nil {
		return fmt.Errorf("Could not get layer information: %s", err)
	}

	// Print report.
	fmt.Printf("Clair report for image %s (%s)\n", imageName, time.Now().UTC())

	if len(layer.Features) == 0 {
		fmt.Printf("%s No features have been detected in the image. This usually means that the image isn't supported by Clair.\n", color.YellowString("NOTE:"))
		return nil
	}

	isSafe := true
	hasVisibleVulnerabilities := false

	var vulnerabilities = make([]vulnerabilityInfo, 0)
	for _, feature := range layer.Features {
		if len(feature.Vulnerabilities) > 0 {
			for _, vulnerability := range feature.Vulnerabilities {
				severity := types.Priority(vulnerability.Severity)
				isSafe = false

				if minSeverity.Compare(severity) > 0 {
					continue
				}

				hasVisibleVulnerabilities = true
				vulnerabilities = append(vulnerabilities, vulnerabilityInfo{vulnerability, feature, severity})
			}
		}
	}

	// Sort vulnerabilitiy by severity.
	priority := func(v1, v2 vulnerabilityInfo) bool {
		return v1.severity.Compare(v2.severity) >= 0
	}

	By(priority).Sort(vulnerabilities)

	for _, vulnerabilityInfo := range vulnerabilities {
		vulnerability := vulnerabilityInfo.vulnerability
		feature := vulnerabilityInfo.feature
		severity := vulnerabilityInfo.severity

		fmt.Printf("%s (%s)\n", vulnerability.Name, coloredSeverity(severity))

		if vulnerability.Description != "" {
			fmt.Printf("%s\n\n", text.Indent(text.Wrap(vulnerability.Description, 80), "\t"))
		}

		fmt.Printf("\tPackage:       %s @ %s\n", feature.Name, feature.Version)

		if vulnerability.FixedBy != "" {
			fmt.Printf("\tFixed version: %s\n", vulnerability.FixedBy)
		}

		if vulnerability.Link != "" {
			fmt.Printf("\tLink:          %s\n", vulnerability.Link)
		}

		fmt.Printf("\tLayer:         %s\n", feature.AddedBy)
		fmt.Println("")
	}

	if isSafe {
		fmt.Printf("%s No vulnerabilities were detected in your image\n", color.GreenString("Success!"))
	} else if !hasVisibleVulnerabilities {
		fmt.Printf("%s No vulnerabilities matching the minimum severity level were detected in your image\n", color.YellowString("NOTE:"))
	}

	return nil
}