Skip to content

Commit 6b976ea

Browse files
retaandrross
andauthored
Fix FileInterceptor to properly check read / write sides path separation (#17836)
Signed-off-by: Andriy Redko <[email protected]> Signed-off-by: Andrew Ross <[email protected]> Co-authored-by: Andrew Ross <[email protected]>
1 parent 9b4688f commit 6b976ea

File tree

2 files changed

+35
-8
lines changed

2 files changed

+35
-8
lines changed

libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/FileInterceptor.java

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,18 +61,27 @@ public static void intercept(@Advice.AllArguments Object[] args, @Advice.Origin
6161
final Collection<ProtectionDomain> callers = walker.walk(StackCallerProtectionDomainChainExtractor.INSTANCE);
6262

6363
final String name = method.getName();
64-
boolean isMutating = name.equals("copy") || name.equals("move") || name.equals("write") || name.startsWith("create");
64+
boolean isMutating = name.equals("move") || name.equals("write") || name.startsWith("create");
6565
final boolean isDelete = isMutating == false ? name.startsWith("delete") : false;
6666

67-
if (isMutating == false && isDelete == false && name.equals("newByteChannel") == true) {
68-
if (args.length > 1 && args[1] instanceof OpenOption[] opts) {
69-
for (final OpenOption opt : opts) {
70-
if (opt != StandardOpenOption.READ) {
71-
isMutating = true;
72-
break;
67+
String targetFilePath = null;
68+
if (isMutating == false && isDelete == false) {
69+
if (name.equals("newByteChannel") == true) {
70+
if (args.length > 1 && args[1] instanceof OpenOption[] opts) {
71+
for (final OpenOption opt : opts) {
72+
if (opt != StandardOpenOption.READ) {
73+
isMutating = true;
74+
break;
75+
}
7376
}
74-
}
7577

78+
}
79+
} else if (name.equals("copy") == true) {
80+
if (args.length > 1 && args[1] instanceof String pathStr) {
81+
targetFilePath = Paths.get(pathStr).toAbsolutePath().toString();
82+
} else if (args.length > 1 && args[1] instanceof Path path) {
83+
targetFilePath = path.toAbsolutePath().toString();
84+
}
7685
}
7786
}
7887

@@ -85,6 +94,19 @@ public static void intercept(@Advice.AllArguments Object[] args, @Advice.Origin
8594
}
8695
}
8796

97+
// Handle Files.copy() separately to check read/write permissions properly
98+
if (method.getName().equals("copy")) {
99+
if (!policy.implies(domain, new FilePermission(filePath, "read"))) {
100+
throw new SecurityException("Denied OPEN access to file: " + filePath + ", domain: " + domain);
101+
}
102+
103+
if (targetFilePath != null) {
104+
if (!policy.implies(domain, new FilePermission(targetFilePath, "write"))) {
105+
throw new SecurityException("Denied OPEN access to file: " + targetFilePath + ", domain: " + domain);
106+
}
107+
}
108+
}
109+
88110
// File mutating operations
89111
if (isMutating && !policy.implies(domain, new FilePermission(filePath, "write"))) {
90112
throw new SecurityException("Denied WRITE access to file: " + filePath + ", domain: " + domain);

libs/agent-sm/agent/src/test/java/org/opensearch/javaagent/FileInterceptorIntegTests.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
import static org.junit.Assert.assertEquals;
3131
import static org.junit.Assert.assertFalse;
32+
import static org.junit.Assert.assertThrows;
3233
import static org.junit.Assert.assertTrue;
3334

3435
@SuppressWarnings("removal")
@@ -144,6 +145,10 @@ public void testCopy() throws Exception {
144145

145146
// Test copy operation
146147
Files.copy(sourcePath, targetPath);
148+
assertThrows(
149+
SecurityException.class,
150+
() -> Files.copy(sourcePath, tmpDir.getRoot().resolve("test-target-" + randomAlphaOfLength(8) + ".txt"))
151+
);
147152

148153
// Verify copy
149154
assertTrue("Target file should exist", Files.exists(targetPath));

0 commit comments

Comments
 (0)