-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
updater/fetchers: add alpine secdb fetcher
- Loading branch information
1 parent
fc908e6
commit 0cb8fc9
Showing
3 changed files
with
297 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
// Copyright 2016 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 alpine implements a vulnerability Fetcher using the alpine-secdb | ||
// git repository. | ||
package alpine | ||
|
||
import ( | ||
"errors" | ||
"io" | ||
"io/ioutil" | ||
"os" | ||
"strings" | ||
|
||
"gopkg.in/yaml.v2" | ||
|
||
"github.com/coreos/pkg/capnslog" | ||
|
||
"github.com/coreos/clair/database" | ||
"github.com/coreos/clair/updater" | ||
"github.com/coreos/clair/utils" | ||
cerrors "github.com/coreos/clair/utils/errors" | ||
"github.com/coreos/clair/utils/types" | ||
) | ||
|
||
const ( | ||
secdbGitURL = "http://git.alpinelinux.org/cgit/alpine-secdb" | ||
updaterFlag = "alpine-secdbUpdater" | ||
nvdURLPrefix = "https://cve.mitre.org/cgi-bin/cvename.cgi?name=" | ||
) | ||
|
||
var ( | ||
// ErrFilesystem is returned when a fetcher fails to interact with the local filesystem. | ||
ErrFilesystem = errors.New("updater/fetchers: something went wrong when interacting with the fs") | ||
|
||
// ErrGitFailure is returned when a fetcher fails to interact with git. | ||
ErrGitFailure = errors.New("updater/fetchers: something went wrong when interacting with git") | ||
|
||
log = capnslog.NewPackageLogger("github.com/coreos/clair", "updater/fetchers/alpine") | ||
) | ||
|
||
func init() { | ||
updater.RegisterFetcher("alpine", &fetcher{}) | ||
} | ||
|
||
type fetcher struct { | ||
repositoryLocalPath string | ||
} | ||
|
||
func (f *fetcher) FetchUpdate(db database.Datastore) (resp updater.FetcherResponse, err error) { | ||
log.Info("fetching Alpine vulnerabilities") | ||
|
||
// Pull the master branch. | ||
var commit string | ||
commit, err = f.pullRepository() | ||
if err != nil { | ||
return | ||
} | ||
|
||
// Ask the database for the latest commit we successfully applied. | ||
var dbCommit string | ||
dbCommit, err = db.GetKeyValue(updaterFlag) | ||
if err != nil { | ||
return | ||
} | ||
|
||
// Set the updaterFlag to equal the commit processed. | ||
resp.FlagName = updaterFlag | ||
resp.FlagValue = commit | ||
|
||
// Short-circuit if there have been no updates. | ||
if commit == dbCommit { | ||
log.Debug("no alpine update") | ||
return | ||
} | ||
|
||
// Append any changed vulnerabilities to the response. | ||
for _, namespace := range []string{"v3.3", "v3.4"} { | ||
var file io.ReadCloser | ||
file, err = os.Open(f.repositoryLocalPath + "/" + namespace + "/main.yaml") | ||
if err != nil { | ||
return | ||
} | ||
|
||
var vulns []database.Vulnerability | ||
vulns, err = parseYAML(file) | ||
if err != nil { | ||
return | ||
} | ||
resp.Vulnerabilities = append(resp.Vulnerabilities, vulns...) | ||
file.Close() | ||
} | ||
|
||
return | ||
} | ||
|
||
func (f *fetcher) pullRepository() (commit string, err error) { | ||
if _, pathExists := os.Stat(f.repositoryLocalPath); f.repositoryLocalPath == "" || os.IsNotExist(pathExists) { | ||
if f.repositoryLocalPath, err = ioutil.TempDir(os.TempDir(), "alpine-secdb"); err != nil { | ||
return "", ErrFilesystem | ||
} | ||
|
||
if out, err := utils.Exec(f.repositoryLocalPath, "git", "pull"); err != nil { | ||
f.Clean() | ||
log.Errorf("could not pull alpine-secdb repository: %s. output: %s", err, out) | ||
return "", cerrors.ErrCouldNotDownload | ||
} | ||
} | ||
|
||
out, err := utils.Exec(f.repositoryLocalPath, "git", "rev-parse", "HEAD") | ||
if err != nil { | ||
return "", ErrGitFailure | ||
} | ||
|
||
commit = strings.TrimSpace(string(out)) | ||
return | ||
} | ||
|
||
func (f *fetcher) Clean() { | ||
if f.repositoryLocalPath != "" { | ||
os.RemoveAll(f.repositoryLocalPath) | ||
} | ||
} | ||
|
||
type secdbFile struct { | ||
Distro string `yaml:"distroversion"` | ||
Packages []struct { | ||
Pkg struct { | ||
Name string `yaml:"name"` | ||
Version string `yaml:"ver"` | ||
Fixes []string `yaml:"fixes"` | ||
} `yaml:"pkg"` | ||
} `yaml:"packages"` | ||
} | ||
|
||
func parseYAML(r io.Reader) (vulns []database.Vulnerability, err error) { | ||
var rBytes []byte | ||
rBytes, err = ioutil.ReadAll(r) | ||
if err != nil { | ||
return | ||
} | ||
|
||
var file secdbFile | ||
err = yaml.Unmarshal(rBytes, &file) | ||
if err != nil { | ||
return | ||
} | ||
for _, pack := range file.Packages { | ||
pkg := pack.Pkg | ||
for _, fix := range pkg.Fixes { | ||
version, err := types.NewVersion(pkg.Version) | ||
if err != nil { | ||
log.Warningf("could not parse package version '%s': %s. skipping", pkg.Version, err.Error()) | ||
continue | ||
} | ||
|
||
var vuln database.Vulnerability | ||
vuln.Name = fix | ||
vuln.Link = nvdURLPrefix + fix | ||
vuln.FixedIn = []database.FeatureVersion{ | ||
{ | ||
Feature: database.Feature{ | ||
Namespace: database.Namespace{Name: "alpine:" + file.Distro}, | ||
Name: pkg.Name, | ||
}, | ||
Version: version, | ||
}, | ||
} | ||
|
||
vulns = append(vulns, vuln) | ||
} | ||
} | ||
|
||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
// Copyright 2016 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 alpine | ||
|
||
import ( | ||
"os" | ||
"path/filepath" | ||
"runtime" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestAlpineYAMLParsing(t *testing.T) { | ||
_, filename, _, _ := runtime.Caller(0) | ||
path := filepath.Join(filepath.Dir(filename)) | ||
|
||
testData, _ := os.Open(path + "/testdata/main.yaml") | ||
defer testData.Close() | ||
|
||
vulns, err := parseYAML(testData) | ||
if err != nil { | ||
assert.Nil(t, err) | ||
} | ||
assert.Equal(t, len(vulns), 15) | ||
assert.Equal(t, vulns[0].Name, "CVE-2016-2147") | ||
assert.Equal(t, vulns[0].FixedIn[0].Feature.Namespace.Name, "alpine:v3.3") | ||
assert.Equal(t, vulns[0].FixedIn[0].Feature.Name, "busybox") | ||
assert.Equal(t, vulns[0].Link, "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-2147") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
--- | ||
distroversion: v3.3 | ||
reponame: main | ||
archs: | ||
- x86_64 | ||
- x86 | ||
- armhf | ||
urlprefix: http://dl-cdn.alpinelinux.org/alpine | ||
apkurl: "{{urlprefix}}/{{distroversion}}/{{reponame}}/{{arch}}/{{pkg.name}}-${{pkg.ver}}.apk" | ||
packages: | ||
- pkg: | ||
name: busybox | ||
ver: 1.24.2-r0 | ||
fixes: | ||
- CVE-2016-2147 | ||
- CVE-2016-2148 | ||
- pkg: | ||
name: expat | ||
ver: 2.1.1-r1 | ||
fixes: | ||
- CVE-2016-0718 | ||
- pkg: | ||
name: gd | ||
ver: 2.1.1-r1 | ||
fixes: | ||
- CVE-2016-3074 | ||
- pkg: | ||
name: giflib | ||
ver: 5.1.1-r1 | ||
fixes: | ||
- CVE-2016-3977 | ||
- pkg: | ||
name: jq | ||
ver: 1.5-r1 | ||
fixes: | ||
- CVE-2015-8863 | ||
- pkg: | ||
name: libarchive | ||
ver: 3.1.2-r3 | ||
fixes: | ||
- CVE-2016-1541 | ||
- pkg: | ||
name: libssh2 | ||
ver: 1.6.0-r1 | ||
fixes: | ||
- CVE-2016-0787 | ||
- pkg: | ||
name: mercurial | ||
ver: 3.7.3-r1 | ||
fixes: | ||
- CVE-2016-3105 | ||
- pkg: | ||
name: openssl | ||
ver: 1.0.2h-r1 | ||
fixes: | ||
- CVE-2016-2177 | ||
- CVE-2016-2178 | ||
- pkg: | ||
name: pcre | ||
ver: 8.38-r1 | ||
fixes: | ||
- CVE-2016-1283 | ||
- CVE-2016-3191 | ||
- pkg: | ||
name: wpa_supplicant | ||
ver: 2.5-r2 | ||
fixes: | ||
- CVE-2016-4476 | ||
- CVE-2016-4477 |