diff --git a/CHANGELOG.md b/CHANGELOG.md index 41e7d2e12c564..29962e798bdfa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Fix pull-based ingestion out-of-bounds offset scenarios and remove persisted offsets ([#19607](https://github.com/opensearch-project/OpenSearch/pull/19607)) - [Star Tree] Fix sub-aggregator casting for search with profile=true ([19652](https://github.com/opensearch-project/OpenSearch/pull/19652)) - Fix issue with updating core with a patch number other than 0 ([#19377](https://github.com/opensearch-project/OpenSearch/pull/19377)) +- [Java Agent] Allow JRT protocol URLs in protection domain extraction ([#19683](https://github.com/opensearch-project/OpenSearch/pull/19683)) ### Dependencies - Update to Gradle 9.1 ([#19575](https://github.com/opensearch-project/OpenSearch/pull/19575)) diff --git a/libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/StackCallerProtectionDomainChainExtractor.java b/libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/StackCallerProtectionDomainChainExtractor.java index 8c348a29ab69e..da2c00cd8a3f3 100644 --- a/libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/StackCallerProtectionDomainChainExtractor.java +++ b/libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/StackCallerProtectionDomainChainExtractor.java @@ -54,6 +54,7 @@ public Collection apply(Stream frames) { .map(StackFrame::getDeclaringClass) .map(Class::getProtectionDomain) .filter(pd -> pd.getCodeSource() != null) // Filter out JDK classes + .filter(pd -> !"jrt".equals(pd.getCodeSource().getLocation().getProtocol())) // Filter out codesources beginning with jrt: .collect(Collectors.toSet()); } } diff --git a/libs/agent-sm/agent/src/test/java/org/opensearch/javaagent/StackCallerProtectionDomainExtractorTests.java b/libs/agent-sm/agent/src/test/java/org/opensearch/javaagent/StackCallerProtectionDomainExtractorTests.java index eab0711a2288f..2efb993448dc3 100644 --- a/libs/agent-sm/agent/src/test/java/org/opensearch/javaagent/StackCallerProtectionDomainExtractorTests.java +++ b/libs/agent-sm/agent/src/test/java/org/opensearch/javaagent/StackCallerProtectionDomainExtractorTests.java @@ -8,8 +8,10 @@ package org.opensearch.javaagent; +import org.junit.Assume; import org.junit.Test; +import java.lang.invoke.MethodType; import java.net.URI; import java.net.URISyntaxException; import java.nio.file.Path; @@ -21,6 +23,7 @@ import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; @@ -257,4 +260,92 @@ public void testAccessControllerUsingCheckedRunnableThrowsException() { org.opensearch.secure_sm.AccessController.doPrivilegedChecked(() -> { throw new IllegalArgumentException("Test exception"); }); }); } + + private static final class FakeFrame implements StackWalker.StackFrame { + private final Class clazz; + private final String method; + + FakeFrame(Class clazz, String method) { + this.clazz = clazz; + this.method = method; + } + + @Override + public Class getDeclaringClass() { + return clazz; + } + + @Override + public String getClassName() { + return clazz.getName(); + } + + @Override + public String getMethodName() { + return method; + } + + @Override + public String getFileName() { + return null; + } + + @Override + public int getLineNumber() { + return -1; + } + + @Override + public boolean isNativeMethod() { + return false; + } + + @Override + public StackTraceElement toStackTraceElement() { + return new StackTraceElement(getClassName(), getMethodName(), null, -1); + } + + // JDK 21 methods; stub minimally + @Override + public String getDescriptor() { + return "()V"; + } + + @Override + public int getByteCodeIndex() { + return -1; + } + + @Override + public MethodType getMethodType() { + return MethodType.methodType(void.class); + } + } + + @Test + public void testFiltersJrtProtocol() { + // Guard: ensure HttpClient is truly from jrt: + ProtectionDomain pd = java.net.http.HttpClient.class.getProtectionDomain(); + Assume.assumeTrue( + pd != null + && pd.getCodeSource() != null + && pd.getCodeSource().getLocation() != null + && "jrt".equals(pd.getCodeSource().getLocation().getProtocol()) + ); + + StackWalker.StackFrame jrtFrame = new FakeFrame(java.net.http.HttpClient.class, "send"); + StackWalker.StackFrame fileFrame = new FakeFrame(StackCallerProtectionDomainExtractorTests.class, "helper"); + + Set pds = (Set) StackCallerProtectionDomainChainExtractor.INSTANCE.apply( + Stream.of(jrtFrame, fileFrame) + ); + + // Only the file: PD should remain + assertEquals(1, pds.size()); + assertThat( + pds.stream().map(x -> x.getCodeSource().getLocation().getProtocol()).collect(Collectors.toSet()), + containsInAnyOrder("file") + ); + } + } diff --git a/libs/agent-sm/build.gradle b/libs/agent-sm/build.gradle index 656411a08080f..edc9ad886b3b7 100644 --- a/libs/agent-sm/build.gradle +++ b/libs/agent-sm/build.gradle @@ -20,3 +20,7 @@ base { test.enabled = false testingConventions.enabled = false + +dependencies { + compileOnly "com.github.spotbugs:spotbugs-annotations:4.9.7" +}