From bfb89b59b2e5b3174311d1d46838bdc262e7cd37 Mon Sep 17 00:00:00 2001 From: Aman Sharma Date: Mon, 21 Aug 2023 18:30:13 +0200 Subject: [PATCH 1/4] feat: acquit classes that are part of the project itself --- .../java/io/github/algomaster99/Options.java | 18 +++++++++++ .../io/github/algomaster99/Terminator.java | 30 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/watchdog-agent/src/main/java/io/github/algomaster99/Options.java b/watchdog-agent/src/main/java/io/github/algomaster99/Options.java index 7ef485a3..3c212c43 100644 --- a/watchdog-agent/src/main/java/io/github/algomaster99/Options.java +++ b/watchdog-agent/src/main/java/io/github/algomaster99/Options.java @@ -2,7 +2,11 @@ import static io.github.algomaster99.terminator.commons.fingerprint.ParsingHelper.deserializeFingerprints; +import io.github.algomaster99.terminator.commons.cyclonedx.Bom14Schema; +import io.github.algomaster99.terminator.commons.cyclonedx.CycloneDX; import io.github.algomaster99.terminator.commons.fingerprint.provenance.Provenance; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.Map; @@ -12,6 +16,8 @@ public class Options { private boolean skipShutdown = false; + private Bom14Schema sbom = null; + public Options(String agentArgs) { String[] args = agentArgs.split(","); for (String arg : args) { @@ -29,6 +35,14 @@ public Options(String agentArgs) { case "skipShutdown": skipShutdown = Boolean.parseBoolean(value); break; + case "sbom": + Path sbomPath = Path.of(value); + try { + sbom = CycloneDX.getPOJO(Files.readString(sbomPath)); + } catch (IOException e) { + throw new IllegalArgumentException("Failed to read sbom file: " + value); + } + break; default: throw new IllegalArgumentException("Unknown argument: " + key); } @@ -45,4 +59,8 @@ public Map> getFingerprints() { public boolean shouldSkipShutdown() { return skipShutdown; } + + public Bom14Schema getSbom() { + return sbom; + } } diff --git a/watchdog-agent/src/main/java/io/github/algomaster99/Terminator.java b/watchdog-agent/src/main/java/io/github/algomaster99/Terminator.java index 3cb7eb62..c7c4c229 100644 --- a/watchdog-agent/src/main/java/io/github/algomaster99/Terminator.java +++ b/watchdog-agent/src/main/java/io/github/algomaster99/Terminator.java @@ -1,8 +1,14 @@ package io.github.algomaster99; import static io.github.algomaster99.terminator.commons.fingerprint.classfile.HashComputer.computeHash; +import static io.github.algomaster99.terminator.commons.jar.JarScanner.goInsideJarAndUpdateFingerprints; +import io.github.algomaster99.terminator.commons.cyclonedx.Bom14Schema; +import io.github.algomaster99.terminator.commons.cyclonedx.Component; import io.github.algomaster99.terminator.commons.fingerprint.provenance.Provenance; +import io.github.algomaster99.terminator.commons.jar.JarDownloader; +import java.io.File; +import java.io.IOException; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.Instrumentation; import java.security.NoSuchAlgorithmException; @@ -33,6 +39,30 @@ public byte[] transform( private static byte[] isLoadedClassWhitelisted(String className, byte[] classfileBuffer) { Map> fingerprints = options.getFingerprints(); + Bom14Schema sbom = options.getSbom(); + // Block needed to consider the project's own classes + // Assumes that package is released on maven central + if (sbom != null) { + try { + Component rootComponent = sbom.getMetadata().getComponent(); + File jarFile = JarDownloader.getMavenJarFile( + rootComponent.getGroup(), rootComponent.getName(), rootComponent.getVersion()); + goInsideJarAndUpdateFingerprints( + jarFile, + fingerprints, + // TODO: Make this configurable + "SHA256", + rootComponent.getGroup(), + rootComponent.getName(), + rootComponent.getVersion()); + } catch (IOException e) { + System.err.println("Failed to download jar file: " + e.getMessage()); + System.exit(1); + } catch (InterruptedException e) { + System.err.println("Downloading was interrupted: " + e.getMessage()); + System.exit(1); + } + } if (INTERNAL_PACKAGES.stream().anyMatch(className::startsWith)) { return classfileBuffer; } From 8a683903a39fdba8b1655dab0de9b59f0099d329 Mon Sep 17 00:00:00 2001 From: Aman Sharma Date: Tue, 22 Aug 2023 12:00:12 +0200 Subject: [PATCH 2/4] perf: update fingerprints only once --- .../java/io/github/algomaster99/Options.java | 27 ++++++++++++----- .../io/github/algomaster99/Terminator.java | 30 ------------------- 2 files changed, 20 insertions(+), 37 deletions(-) diff --git a/watchdog-agent/src/main/java/io/github/algomaster99/Options.java b/watchdog-agent/src/main/java/io/github/algomaster99/Options.java index 3c212c43..36abe60c 100644 --- a/watchdog-agent/src/main/java/io/github/algomaster99/Options.java +++ b/watchdog-agent/src/main/java/io/github/algomaster99/Options.java @@ -1,10 +1,14 @@ package io.github.algomaster99; import static io.github.algomaster99.terminator.commons.fingerprint.ParsingHelper.deserializeFingerprints; +import static io.github.algomaster99.terminator.commons.jar.JarScanner.goInsideJarAndUpdateFingerprints; import io.github.algomaster99.terminator.commons.cyclonedx.Bom14Schema; +import io.github.algomaster99.terminator.commons.cyclonedx.Component; import io.github.algomaster99.terminator.commons.cyclonedx.CycloneDX; import io.github.algomaster99.terminator.commons.fingerprint.provenance.Provenance; +import io.github.algomaster99.terminator.commons.jar.JarDownloader; +import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -16,8 +20,6 @@ public class Options { private boolean skipShutdown = false; - private Bom14Schema sbom = null; - public Options(String agentArgs) { String[] args = agentArgs.split(","); for (String arg : args) { @@ -36,9 +38,24 @@ public Options(String agentArgs) { skipShutdown = Boolean.parseBoolean(value); break; case "sbom": + // If an SBOM is passed included the root component in the fingerprints Path sbomPath = Path.of(value); try { - sbom = CycloneDX.getPOJO(Files.readString(sbomPath)); + Bom14Schema sbom = CycloneDX.getPOJO(Files.readString(sbomPath)); + Component rootComponent = sbom.getMetadata().getComponent(); + File jarFile = JarDownloader.getMavenJarFile( + rootComponent.getGroup(), rootComponent.getName(), rootComponent.getVersion()); + goInsideJarAndUpdateFingerprints( + jarFile, + fingerprints, + // TODO: Make this configurable + "SHA256", + rootComponent.getGroup(), + rootComponent.getName(), + rootComponent.getVersion()); + } catch (InterruptedException e) { + System.err.println("Downloading was interrupted: " + e.getMessage()); + System.exit(1); } catch (IOException e) { throw new IllegalArgumentException("Failed to read sbom file: " + value); } @@ -59,8 +76,4 @@ public Map> getFingerprints() { public boolean shouldSkipShutdown() { return skipShutdown; } - - public Bom14Schema getSbom() { - return sbom; - } } diff --git a/watchdog-agent/src/main/java/io/github/algomaster99/Terminator.java b/watchdog-agent/src/main/java/io/github/algomaster99/Terminator.java index c7c4c229..3cb7eb62 100644 --- a/watchdog-agent/src/main/java/io/github/algomaster99/Terminator.java +++ b/watchdog-agent/src/main/java/io/github/algomaster99/Terminator.java @@ -1,14 +1,8 @@ package io.github.algomaster99; import static io.github.algomaster99.terminator.commons.fingerprint.classfile.HashComputer.computeHash; -import static io.github.algomaster99.terminator.commons.jar.JarScanner.goInsideJarAndUpdateFingerprints; -import io.github.algomaster99.terminator.commons.cyclonedx.Bom14Schema; -import io.github.algomaster99.terminator.commons.cyclonedx.Component; import io.github.algomaster99.terminator.commons.fingerprint.provenance.Provenance; -import io.github.algomaster99.terminator.commons.jar.JarDownloader; -import java.io.File; -import java.io.IOException; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.Instrumentation; import java.security.NoSuchAlgorithmException; @@ -39,30 +33,6 @@ public byte[] transform( private static byte[] isLoadedClassWhitelisted(String className, byte[] classfileBuffer) { Map> fingerprints = options.getFingerprints(); - Bom14Schema sbom = options.getSbom(); - // Block needed to consider the project's own classes - // Assumes that package is released on maven central - if (sbom != null) { - try { - Component rootComponent = sbom.getMetadata().getComponent(); - File jarFile = JarDownloader.getMavenJarFile( - rootComponent.getGroup(), rootComponent.getName(), rootComponent.getVersion()); - goInsideJarAndUpdateFingerprints( - jarFile, - fingerprints, - // TODO: Make this configurable - "SHA256", - rootComponent.getGroup(), - rootComponent.getName(), - rootComponent.getVersion()); - } catch (IOException e) { - System.err.println("Failed to download jar file: " + e.getMessage()); - System.exit(1); - } catch (InterruptedException e) { - System.err.println("Downloading was interrupted: " + e.getMessage()); - System.exit(1); - } - } if (INTERNAL_PACKAGES.stream().anyMatch(className::startsWith)) { return classfileBuffer; } From 459bfa2db75c88d751bb56361596177d458fa249 Mon Sep 17 00:00:00 2001 From: Aman Sharma Date: Tue, 22 Aug 2023 12:07:47 +0200 Subject: [PATCH 3/4] Update docs --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e7eb7707..2c84c32d 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,9 @@ java -javaagent:=fingerprints= -jar `sbom` is a CycloneDX 1.4 JSON file. From 624c1fff310053a656960a7e7ae5320406e4da7d Mon Sep 17 00:00:00 2001 From: Aman Sharma Date: Tue, 22 Aug 2023 12:36:03 +0200 Subject: [PATCH 4/4] tests: fix disabled test message --- watchdog-agent/src/test/java/AgentTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/watchdog-agent/src/test/java/AgentTest.java b/watchdog-agent/src/test/java/AgentTest.java index d22a012d..152edd7c 100644 --- a/watchdog-agent/src/test/java/AgentTest.java +++ b/watchdog-agent/src/test/java/AgentTest.java @@ -22,7 +22,7 @@ import org.junit.jupiter.api.Test; public class AgentTest { - @Disabled("Should be worked upon after the input is from an SBOM and not maven project") + @Disabled("Should be worked upon after we know what java version is used by the application") @Test void shouldDisallowLoadingCustomJDKClass() throws MavenInvocationException, IOException, InterruptedException { // contract: watchdog-agent should detect if the class masquerading as an internal class