Skip to content

Commit 6135bea

Browse files
committed
Tweak resource lookups for CodeQL
1 parent a132be4 commit 6135bea

4 files changed

Lines changed: 83 additions & 6 deletions

File tree

javaagent-bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/AgentClassLoader.java

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,7 @@ public AgentClassLoader(
147147
@Nullable
148148
@Override
149149
public URL apply(String resourceName) {
150-
JarEntry jarEntry = jarFile.getJarEntry(resourceName);
151-
AgentJarResource jarResource = AgentJarResource.create(resourceName, jarEntry);
152-
return getAgentJarResourceUrl(jarResource);
150+
return findJarResource(resourceName);
153151
}
154152
});
155153

@@ -281,8 +279,43 @@ private static String getPackageName(String className) {
281279
return index == -1 ? null : className.substring(0, index);
282280
}
283281

282+
private static boolean isNormalizedResourcePath(String resourceName) {
283+
if (resourceName.isEmpty()
284+
|| resourceName.startsWith("/")
285+
|| resourceName.startsWith("\\")) {
286+
return false;
287+
}
288+
289+
int segmentStart = 0;
290+
for (int i = 0; i <= resourceName.length(); i++) {
291+
if (i == resourceName.length() || resourceName.charAt(i) == '/') {
292+
if (!isValidResourceSegment(resourceName, segmentStart, i)) {
293+
return false;
294+
}
295+
segmentStart = i + 1;
296+
} else if (resourceName.charAt(i) == '\\') {
297+
return false;
298+
}
299+
}
300+
301+
return true;
302+
}
303+
304+
private static boolean isValidResourceSegment(String resourceName, int start, int end) {
305+
int length = end - start;
306+
return length > 0
307+
&& !(length == 1 && resourceName.charAt(start) == '.')
308+
&& !(length == 2
309+
&& resourceName.charAt(start) == '.'
310+
&& resourceName.charAt(start + 1) == '.');
311+
}
312+
284313
@Nullable
285314
private AgentJarResource findAgentJarResource(String name) {
315+
if (!isNormalizedResourcePath(name)) {
316+
return null;
317+
}
318+
286319
// shading renames .class to .classdata
287320
boolean isClass = name.endsWith(".class");
288321
if (isClass) {

javaagent-bootstrap/src/test/java/io/opentelemetry/javaagent/bootstrap/AgentClassLoaderTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,15 @@ protected String getClassSuffix() {
120120
assertThat(result.length > 0).isNotEqualTo(jdk8);
121121
}
122122
}
123+
124+
@Test
125+
void rejectsNonNormalizedResourceNames() throws Exception {
126+
URL testJarLocation = OpenTelemetrySdk.class.getProtectionDomain().getCodeSource().getLocation();
127+
128+
try (AgentClassLoader loader = new AgentClassLoader(new File(testJarLocation.toURI()))) {
129+
assertThat(loader.getResource("../test.txt")).isNull();
130+
assertThat(loader.getResource("/test.txt")).isNull();
131+
assertThat(loader.findResource("META-INF/../MANIFEST.MF")).isNull();
132+
}
133+
}
123134
}

muzzle/src/main/java/io/opentelemetry/javaagent/tooling/muzzle/ReferenceCollector.java

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,20 @@ public ReferenceCollector(
7575
* @see HelperClassPredicate
7676
*/
7777
public void collectReferencesFromResource(HelperResource helperResource) {
78-
if (!isSpiFile(helperResource.getApplicationPath())) {
78+
String applicationPath = helperResource.getApplicationPath();
79+
if (!isSpiFile(applicationPath)) {
7980
return;
8081
}
8182

83+
String agentPath = helperResource.getAgentPath();
84+
Preconditions.checkArgument(
85+
isKnownSpiResourcePath(agentPath),
86+
"Unexpected SPI resource %s for %s",
87+
agentPath,
88+
applicationPath);
89+
8290
List<String> spiImplementations = new ArrayList<>();
83-
try (InputStream stream = getResourceStream(helperResource.getAgentPath())) {
91+
try (InputStream stream = getResourceStream(agentPath)) {
8492
BufferedReader reader = new BufferedReader(new InputStreamReader(stream, UTF_8));
8593
while (reader.ready()) {
8694
String line = reader.readLine();
@@ -89,7 +97,7 @@ public void collectReferencesFromResource(HelperResource helperResource) {
8997
}
9098
}
9199
} catch (IOException e) {
92-
throw new IllegalStateException("Error reading resource " + helperResource.getAgentPath(), e);
100+
throw new IllegalStateException("Error reading resource " + agentPath, e);
93101
}
94102

95103
visitClassesAndCollectReferences(spiImplementations, /* startsFromAdviceClass= */ false);
@@ -109,6 +117,15 @@ private static boolean isSpiFile(String resource) {
109117
|| AWS_SDK_V1_SERVICE_INTERCEPTOR_SPI.matcher(resource).matches();
110118
}
111119

120+
private static boolean isKnownSpiResourcePath(String resource) {
121+
if (isSpiFile(resource)) {
122+
return true;
123+
}
124+
125+
int prefixSeparator = resource.indexOf('/');
126+
return prefixSeparator > 0 && isSpiFile(resource.substring(prefixSeparator + 1));
127+
}
128+
112129
/**
113130
* Traverse a graph of classes starting from {@code adviceClassName} and collect all references to
114131
* both internal (instrumentation) and external classes.

muzzle/src/test/java/io/opentelemetry/javaagent/tooling/muzzle/ReferenceCollectorTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import static io.opentelemetry.javaagent.tooling.muzzle.references.Flag.MinimumVisibilityFlag.PROTECTED_OR_HIGHER;
1010
import static java.util.Arrays.asList;
1111
import static org.assertj.core.api.Assertions.assertThat;
12+
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
1213
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
1314
import static org.assertj.core.api.Assertions.entry;
1415

@@ -336,6 +337,21 @@ public void shouldIgnoreArbitraryResourceFile() {
336337
assertThat(collector.getSortedHelperClasses()).isEmpty();
337338
}
338339

340+
@Test
341+
public void shouldRejectUnexpectedSpiResourcePath() {
342+
ReferenceCollector collector = new ReferenceCollector(s -> false);
343+
344+
assertThatIllegalArgumentException()
345+
.isThrownBy(
346+
() ->
347+
collector.collectReferencesFromResource(
348+
HelperResource.create(
349+
"META-INF/services/test.resource.file",
350+
"unexpected/test.resource.file",
351+
false)))
352+
.withMessageContaining("Unexpected SPI resource");
353+
}
354+
339355
@Test
340356
public void shouldCollectVirtualFields() {
341357
ReferenceCollector collector = new ReferenceCollector(s -> false);

0 commit comments

Comments
 (0)