-
Notifications
You must be signed in to change notification settings - Fork 186
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Yocto project support CVE security vulnerabilities using cve-check in the specific image or target you are building, add the following setting to your configuration: INHERIT += "cve-check" status of each CVE: Patched, Unpatched or Ignored The scanner look only for Unpatched package and calculate the severity using the score_v2 or score_v3. The generated from Yocto can be collected in build/tmp/log/cve/cve-summury.json Signed-off-by: Michael Trimarchi <[email protected]>
- Loading branch information
Showing
5 changed files
with
622 additions
and
0 deletions.
There are no files selected for viewing
108 changes: 108 additions & 0 deletions
108
src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java
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,108 @@ | ||
package edu.hm.hafner.analysis.parser; | ||
|
||
import org.json.JSONArray; | ||
import org.json.JSONObject; | ||
|
||
import edu.hm.hafner.analysis.Issue; | ||
import edu.hm.hafner.analysis.IssueBuilder; | ||
import edu.hm.hafner.analysis.Report; | ||
import edu.hm.hafner.analysis.Severity; | ||
|
||
import static j2html.TagCreator.*; | ||
|
||
/** | ||
* Parser for Yocto Scanner CLI (scannercli) tool. | ||
* | ||
* @author Juri Duval | ||
*/ | ||
public class YoctoScannerParser extends JsonIssueParser { | ||
private static final String VALUE_NOT_SET = "-"; | ||
private static final long serialVersionUID = 1L; | ||
private static final Double INVALID_SCORE = -1.0; | ||
|
||
@Override | ||
protected void parseJsonObject(final Report report, final JSONObject jsonReport, final IssueBuilder issueBuilder) { | ||
JSONArray packages = jsonReport.optJSONArray("package"); | ||
if (packages != null) { | ||
parseResources(report, packages, issueBuilder); | ||
} | ||
} | ||
|
||
private void parseResources(final Report report, final JSONArray packages, final IssueBuilder issueBuilder) { | ||
for (int i = 0; i < packages.length(); i++) { | ||
final Object item = packages.get(i); | ||
if (item instanceof JSONObject) { | ||
final JSONObject resourceWrapper = (JSONObject) item; | ||
if (!resourceWrapper.isNull("issue")) { | ||
parseVulnerabilities(report, issueBuilder, resourceWrapper); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void parseVulnerabilities(final Report report, final IssueBuilder issueBuilder, | ||
final JSONObject resourceWrapper) { | ||
final JSONArray vulnerabilities = resourceWrapper.getJSONArray("issue"); | ||
for (Object vulnerability : vulnerabilities) { | ||
if (vulnerability instanceof JSONObject) { | ||
final JSONObject obj = (JSONObject) vulnerability; | ||
final String status = obj.getString("status"); | ||
boolean unpatched = "Unpatched".equals(status); | ||
if (unpatched) { | ||
report.add(convertToIssue(resourceWrapper, obj, issueBuilder)); | ||
} | ||
} | ||
} | ||
} | ||
|
||
private Issue convertToIssue(final JSONObject resource, final JSONObject vulnerability, | ||
final IssueBuilder issueBuilder) { | ||
final String packageName = resource.getString("name"); | ||
return issueBuilder | ||
.setPackageName(packageName) | ||
.setSeverity(mapSeverity(vulnerability)) | ||
.setMessage(vulnerability.optString("id", "UNKNOWN")) | ||
.setDescription(formatDescription(packageName, resource, vulnerability)) | ||
.buildAndClean(); | ||
} | ||
|
||
private Severity mapSeverity(final JSONObject vulnerability) { | ||
Double score = INVALID_SCORE; | ||
boolean hasScoreV3 = vulnerability.has("scorev3"); | ||
|
||
if (hasScoreV3) { | ||
score = vulnerability.getDouble("scorev3"); | ||
} | ||
|
||
if (score <= 0) { | ||
score = vulnerability.getDouble("scorev2"); | ||
} | ||
|
||
if (score >= 0 && score < 4.0) { | ||
return Severity.WARNING_LOW; | ||
} | ||
else if (score >= 4.0 && score < 7.0) { | ||
return Severity.WARNING_NORMAL; | ||
} | ||
else if (score >= 7.0 && score <= 10.0) { | ||
return Severity.WARNING_HIGH; | ||
} | ||
|
||
return Severity.ERROR; | ||
} | ||
|
||
private String formatDescription(final String packageName, final JSONObject resource, final JSONObject vulnerability) { | ||
final String version = resource.optString("version", VALUE_NOT_SET); | ||
final String layer = resource.optString("layer", "UNKOWN"); | ||
final String vector = vulnerability.optString("vector", "UNKOWN"); | ||
final String link = vulnerability.optString("link", "UNKOWN"); | ||
final String description = vulnerability.optString("summary", ""); | ||
|
||
return join(div(b("Package: "), text(packageName)), | ||
div(b("Version: "), text(version)), | ||
div(b("Link: "), text(link)), | ||
div(b("Yocto Layer: "), text(layer)), | ||
div(b("Vector: "), text(vector)), | ||
p(text(description))).render(); | ||
} | ||
} |
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
44 changes: 44 additions & 0 deletions
44
src/main/java/edu/hm/hafner/analysis/registry/YoctoScannerDescriptor.java
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,44 @@ | ||
package edu.hm.hafner.analysis.registry; | ||
|
||
import edu.hm.hafner.analysis.IssueParser; | ||
import edu.hm.hafner.analysis.parser.YoctoScannerParser; | ||
|
||
import static j2html.TagCreator.*; | ||
|
||
/** | ||
* A descriptor for Yocto Scanner. | ||
* | ||
* @author Juri Duval | ||
*/ | ||
class YoctoScannerDescriptor extends ParserDescriptor { | ||
private static final String ID = "Yocto cli"; | ||
private static final String NAME = "Yocto Scanner"; | ||
|
||
YoctoScannerDescriptor() { | ||
super(ID, NAME); | ||
} | ||
|
||
@Override | ||
public IssueParser createParser(final Option... options) { | ||
return new YoctoScannerParser(); | ||
} | ||
|
||
@Override | ||
public String getHelp() { | ||
return join(text("Use commandline"), | ||
code("bitbake <your product image>"), | ||
text(", add INHERIT += \"cve-check\" in your local.conf"), | ||
a("Yocto Scanner").withHref("https://docs.yoctoproject.org/dev/dev-manual/vulnerabilities.html"), | ||
text("for usage details.")).render(); | ||
} | ||
|
||
@Override | ||
public String getUrl() { | ||
return "https://docs.yoctoproject.org/dev/dev-manual/vulnerabilities.html"; | ||
} | ||
|
||
@Override | ||
public String getIconUrl() { | ||
return "https://www.yoctoproject.org/wp-content/uploads/sites/32/2023/09/YoctoProject_Logo_RGB_White_small.svg"; | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
src/test/java/edu/hm/hafner/analysis/parser/YoctoScannerParserTest.java
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,53 @@ | ||
package edu.hm.hafner.analysis.parser; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
import edu.hm.hafner.analysis.IssueParser; | ||
import edu.hm.hafner.analysis.ParsingException; | ||
import edu.hm.hafner.analysis.Report; | ||
import edu.hm.hafner.analysis.Severity; | ||
import edu.hm.hafner.analysis.assertions.SoftAssertions; | ||
import edu.hm.hafner.analysis.registry.AbstractParserTest; | ||
|
||
import static edu.hm.hafner.analysis.assertions.Assertions.*; | ||
|
||
/** | ||
* Tests the class {@link YoctoScannerParser}. | ||
*/ | ||
class YoctoScannerParserTest extends AbstractParserTest { | ||
|
||
YoctoScannerParserTest() { | ||
super("yocto_scanner_result.json"); | ||
} | ||
|
||
@Override | ||
protected void assertThatIssuesArePresent(final Report report, final SoftAssertions softly) { | ||
softly.assertThat(report).hasSize(25); | ||
|
||
softly.assertThat(report.get(0)) | ||
.hasSeverity(Severity.WARNING_LOW) | ||
.hasPackageName("acl") | ||
.hasMessage("CVE-2009-4411"); | ||
softly.assertThat(report.get(3)) | ||
.hasSeverity(Severity.WARNING_NORMAL) | ||
.hasPackageName("automake-native") | ||
.hasMessage("CVE-2012-3386"); | ||
} | ||
|
||
@Test | ||
void shouldHandleEmptyResultsJenkins67296() { | ||
Report report = parse("issue67296.json"); | ||
|
||
assertThat(report).isEmpty(); | ||
} | ||
|
||
@Test | ||
void brokenInput() { | ||
assertThatThrownBy(() -> parse("eclipse.txt")).isInstanceOf(ParsingException.class); | ||
} | ||
|
||
@Override | ||
protected IssueParser createParser() { | ||
return new YoctoScannerParser(); | ||
} | ||
} |
Oops, something went wrong.