-
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
635 additions
and
0 deletions.
There are no files selected for viewing
110 changes: 110 additions & 0 deletions
110
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,110 @@ | ||
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 (bitbake) tool. | ||
* | ||
* @author Michael Trimarchi | ||
*/ | ||
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"); | ||
final String fileName = vulnerability.optString("id", "UNKNOWN"); | ||
return issueBuilder | ||
.setType(fileName) | ||
.setFileName(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; | ||
Check warning on line 93 in src/main/java/edu/hm/hafner/analysis/parser/YoctoScannerParser.java ci.jenkins.io / Code CoverageNot covered line
|
||
} | ||
|
||
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: "), a(link).withHref(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 Michael Trimarchi | ||
*/ | ||
class YoctoScannerDescriptor extends ParserDescriptor { | ||
private static final String ID = "yoctocli"; | ||
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(); | ||
Check warning on line 32 in src/main/java/edu/hm/hafner/analysis/registry/YoctoScannerDescriptor.java ci.jenkins.io / Code CoverageNot covered lines
|
||
} | ||
|
||
@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"; | ||
Check warning on line 42 in src/main/java/edu/hm/hafner/analysis/registry/YoctoScannerDescriptor.java ci.jenkins.io / Code CoverageNot covered line
|
||
} | ||
} |
64 changes: 64 additions & 0 deletions
64
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,64 @@ | ||
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) | ||
.hasFileName("acl") | ||
.hasType("CVE-2009-4411") | ||
.hasDescription("<div><b>Package: </b>acl</div> <div><b>Version: </b>2.3.2</div>" | ||
+ " <div><b>Link: </b><a href=\"https://nvd.nist.gov/vuln/detail/CVE-2009-4411\"" | ||
+ ">https://nvd.nist.gov/vuln/detail/CVE-2009-4411</a></div>" | ||
+ " <div><b>Yocto Layer: </b>meta</div> <div><b>Vector: </b>LOCAL</div> <p>" | ||
+ "The (1) setfacl and (2) getfacl commands in XFS acl 2.2.47, when running" | ||
+ " in recursive (-R) mode, follow symbolic links even when the --physical" | ||
+ " (aka -P) or -L option is specified, which might allow local users to modify" | ||
+ " the ACL for arbitrary files or directories via a symlink attack.</p>"); | ||
softly.assertThat(report.get(3)) | ||
.hasSeverity(Severity.WARNING_NORMAL) | ||
.hasFileName("automake-native") | ||
.hasType("CVE-2012-3386"); | ||
softly.assertThat(report.get(12)) | ||
.hasSeverity(Severity.WARNING_HIGH) | ||
.hasFileName("avahi") | ||
.hasType("CVE-2017-6519"); | ||
} | ||
|
||
@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.