119 lines
3.5 KiB
Go
119 lines
3.5 KiB
Go
// Copyright 2019 clair authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package vulnerability
|
|
|
|
import (
|
|
"database/sql"
|
|
|
|
"github.com/coreos/clair/database"
|
|
"github.com/coreos/clair/database/pgsql/feature"
|
|
"github.com/coreos/clair/database/pgsql/util"
|
|
"github.com/coreos/clair/ext/versionfmt"
|
|
"github.com/lib/pq"
|
|
)
|
|
|
|
const (
|
|
searchPotentialAffectingVulneraibilities = `
|
|
SELECT nf.id, v.id, vaf.affected_version, vaf.id
|
|
FROM vulnerability_affected_feature AS vaf, vulnerability AS v,
|
|
namespaced_feature AS nf, feature AS f
|
|
WHERE nf.id = ANY($1)
|
|
AND nf.feature_id = f.id
|
|
AND nf.namespace_id = v.namespace_id
|
|
AND vaf.feature_name = f.name
|
|
AND vaf.feature_type = f.type
|
|
AND vaf.vulnerability_id = v.id
|
|
AND v.deleted_at IS NULL`
|
|
insertVulnerabilityAffected = `
|
|
INSERT INTO vulnerability_affected_feature(vulnerability_id, feature_name, affected_version, feature_type, fixedin)
|
|
VALUES ($1, $2, $3, $4, $5)
|
|
RETURNING ID
|
|
`
|
|
searchVulnerabilityAffected = `
|
|
SELECT vulnerability_id, feature_name, affected_version, t.name, fixedin
|
|
FROM vulnerability_affected_feature AS vaf, feature_type AS t
|
|
WHERE t.id = vaf.feature_type AND vulnerability_id = ANY($1)
|
|
`
|
|
|
|
searchVulnerabilityPotentialAffected = `
|
|
WITH req AS (
|
|
SELECT vaf.id AS vaf_id, n.id AS n_id, vaf.feature_name AS name, vaf.feature_type AS type, v.id AS vulnerability_id
|
|
FROM vulnerability_affected_feature AS vaf,
|
|
vulnerability AS v,
|
|
namespace AS n
|
|
WHERE vaf.vulnerability_id = ANY($1)
|
|
AND v.id = vaf.vulnerability_id
|
|
AND n.id = v.namespace_id
|
|
)
|
|
SELECT req.vulnerability_id, nf.id, f.version, req.vaf_id AS added_by
|
|
FROM feature AS f, namespaced_feature AS nf, req
|
|
WHERE f.name = req.name
|
|
AND f.type = req.type
|
|
AND nf.namespace_id = req.n_id
|
|
AND nf.feature_id = f.id`
|
|
)
|
|
|
|
type vulnerabilityCache struct {
|
|
nsFeatureID int64
|
|
vulnID int64
|
|
vulnAffectingID int64
|
|
}
|
|
|
|
func SearchAffectingVulnerabilities(tx *sql.Tx, features []database.NamespacedFeature) ([]vulnerabilityCache, error) {
|
|
if len(features) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
ids, err := feature.FindNamespacedFeatureIDs(tx, features)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
fMap := map[int64]database.NamespacedFeature{}
|
|
for i, f := range features {
|
|
if !ids[i].Valid {
|
|
return nil, database.ErrMissingEntities
|
|
}
|
|
fMap[ids[i].Int64] = f
|
|
}
|
|
|
|
cacheTable := []vulnerabilityCache{}
|
|
rows, err := tx.Query(searchPotentialAffectingVulneraibilities, pq.Array(ids))
|
|
if err != nil {
|
|
return nil, util.HandleError("searchPotentialAffectingVulneraibilities", err)
|
|
}
|
|
|
|
defer rows.Close()
|
|
for rows.Next() {
|
|
var (
|
|
cache vulnerabilityCache
|
|
affected string
|
|
)
|
|
|
|
err := rows.Scan(&cache.nsFeatureID, &cache.vulnID, &affected, &cache.vulnAffectingID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if ok, err := versionfmt.InRange(fMap[cache.nsFeatureID].VersionFormat, fMap[cache.nsFeatureID].Version, affected); err != nil {
|
|
return nil, err
|
|
} else if ok {
|
|
cacheTable = append(cacheTable, cache)
|
|
}
|
|
}
|
|
|
|
return cacheTable, nil
|
|
}
|