Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- [Security Manager Replacement] Create initial Java Agent to intercept Socket::connect calls ([#17724](https://github.com/opensearch-project/OpenSearch/pull/17724))
- Add ingestion management APIs for pause, resume and get ingestion state ([#17631](https://github.com/opensearch-project/OpenSearch/pull/17631))
- [Security Manager Replacement] Enhance Java Agent to intercept System::exit ([#17746](https://github.com/opensearch-project/OpenSearch/pull/17746))
- [Security Manager Replacement] Implement File Interceptor and add integration tests ([#17760](https://github.com/opensearch-project/OpenSearch/pull/17760))
- [Security Manager Replacement] Enhance Java Agent to intercept Runtime::halt ([#17757](https://github.com/opensearch-project/OpenSearch/pull/17757))
- Support AutoExpand for SearchReplica ([#17741](https://github.com/opensearch-project/OpenSearch/pull/17741))
- Implement fixed interval refresh task scheduling ([#17777](https://github.com/opensearch-project/OpenSearch/pull/17777))
Expand Down
1 change: 1 addition & 0 deletions libs/agent-sm/agent/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ tasks.named('forbiddenApisTest').configure { onlyIf { false } }

tasks.named('forbiddenApisMain').configure {
replaceSignatureFiles 'jdk-signatures'
onlyIf { false }
}

task prepareAgent(type: Copy) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
import org.opensearch.javaagent.bootstrap.AgentPolicy;

import java.lang.instrument.Instrumentation;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Files;
import java.util.Map;

import net.bytebuddy.ByteBuddy;
Expand All @@ -33,6 +35,22 @@
*/
private Agent() {}

/**
* List of methods that are intercepted
*/
private static final String[] INTERCEPTED_METHODS = {

Check warning on line 41 in libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/Agent.java

View check run for this annotation

Codecov / codecov/patch

libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/Agent.java#L41

Added line #L41 was not covered by tests
"write",
"createFile",
"createDirectories",
"createLink",
"copy",
"move",
"newByteChannel",
"delete",
"deleteIfExists",
"read",
"open" };

/**
* Premain
* @param agentArguments agent arguments
Expand All @@ -55,12 +73,18 @@

private static AgentBuilder createAgentBuilder(Instrumentation inst) throws Exception {
final Junction<TypeDescription> systemType = ElementMatchers.isSubTypeOf(SocketChannel.class);
final Junction<TypeDescription> pathType = ElementMatchers.isSubTypeOf(Files.class);
final Junction<TypeDescription> fileChannelType = ElementMatchers.isSubTypeOf(FileChannel.class);

Check warning on line 77 in libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/Agent.java

View check run for this annotation

Codecov / codecov/patch

libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/Agent.java#L76-L77

Added lines #L76 - L77 were not covered by tests

final AgentBuilder.Transformer transformer = (b, typeDescription, classLoader, module, pd) -> b.visit(
final AgentBuilder.Transformer socketTransformer = (b, typeDescription, classLoader, module, pd) -> b.visit(

Check warning on line 79 in libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/Agent.java

View check run for this annotation

Codecov / codecov/patch

libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/Agent.java#L79

Added line #L79 was not covered by tests
Advice.to(SocketChannelInterceptor.class)
.on(ElementMatchers.named("connect").and(ElementMatchers.not(ElementMatchers.isAbstract())))
);

final AgentBuilder.Transformer fileTransformer = (b, typeDescription, classLoader, module, pd) -> b.visit(
Advice.to(FileInterceptor.class).on(ElementMatchers.namedOneOf(INTERCEPTED_METHODS).or(ElementMatchers.isAbstract()))

Check warning on line 85 in libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/Agent.java

View check run for this annotation

Codecov / codecov/patch

libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/Agent.java#L84-L85

Added lines #L84 - L85 were not covered by tests
);

ClassInjector.UsingUnsafe.ofBootLoader()
.inject(
Map.of(
Expand All @@ -79,7 +103,9 @@
.with(AgentBuilder.TypeStrategy.Default.REDEFINE)
.ignore(ElementMatchers.none())
.type(systemType)
.transform(transformer)
.transform(socketTransformer)
.type(pathType.or(fileChannelType))
.transform(fileTransformer)

Check warning on line 108 in libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/Agent.java

View check run for this annotation

Codecov / codecov/patch

libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/Agent.java#L106-L108

Added lines #L106 - L108 were not covered by tests
.type(ElementMatchers.is(java.lang.System.class))
.transform(
(b, typeDescription, classLoader, module, pd) -> b.visit(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* The OpenSearch Contributors require contributions made to
* this file be licensed under the Apache-2.0 license or a
* compatible open source license.
*/

package org.opensearch.javaagent;

import org.opensearch.javaagent.bootstrap.AgentPolicy;

import java.io.FilePermission;
import java.lang.reflect.Method;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.Policy;
import java.security.ProtectionDomain;
import java.util.Collection;

import net.bytebuddy.asm.Advice;

/**
* FileInterceptor
*/
public class FileInterceptor {
/**
* FileInterceptor
*/
public FileInterceptor() {}

Check warning on line 30 in libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/FileInterceptor.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L30 was not covered by tests

/**
* Intercepts file operations
*
* @param args arguments
* @param method method
* @throws Exception exceptions
*/
@Advice.OnMethodEnter
@SuppressWarnings({ "removal", "deprecation" })
public static void intercept(@Advice.AllArguments Object[] args, @Advice.Origin Method method) throws Exception {
final Policy policy = AgentPolicy.getPolicy();

Check warning on line 42 in libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/FileInterceptor.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L42 was not covered by tests
if (policy == null) {
return; /* noop */

Check warning on line 44 in libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/FileInterceptor.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L44 was not covered by tests
}

String filePath = null;

Check warning on line 47 in libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/FileInterceptor.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L47 was not covered by tests
if (args.length > 0 && args[0] instanceof String pathStr) {
filePath = Paths.get(pathStr).toAbsolutePath().toString();

Check warning on line 49 in libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/FileInterceptor.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L49 was not covered by tests
} else if (args.length > 0 && args[0] instanceof Path path) {
filePath = path.toAbsolutePath().toString();

Check warning on line 51 in libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/FileInterceptor.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L51 was not covered by tests
}

if (filePath == null) {
return; // No valid file path found

Check warning on line 55 in libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/FileInterceptor.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L55 was not covered by tests
}

final StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
final Collection<ProtectionDomain> callers = walker.walk(StackCallerProtectionDomainChainExtractor.INSTANCE);

Check warning on line 59 in libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/FileInterceptor.java

View check run for this annotation

Codecov / codecov/patch

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

Added lines #L58 - L59 were not covered by tests

final String name = method.getName();

Check warning on line 61 in libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/FileInterceptor.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L61 was not covered by tests
final boolean isMutating = name.equals("copy")
|| name.equals("move")
|| name.equals("write")
|| name.equals("newByteChannel")
|| name.startsWith("create");
final boolean isDelete = isMutating == false ? name.startsWith("delete") : false;

// Check each permission separately
for (final ProtectionDomain domain : callers) {
// Handle FileChannel.open() separately to check read/write permissions properly
if (method.getName().equals("open")) {
if (!policy.implies(domain, new FilePermission(filePath, "read,write"))) {
throw new SecurityException("Denied OPEN access to file: " + filePath + ", domain: " + domain);

Check warning on line 74 in libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/FileInterceptor.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L74 was not covered by tests
}
}

// File mutating operations
if (isMutating && !policy.implies(domain, new FilePermission(filePath, "write"))) {
throw new SecurityException("Denied WRITE access to file: " + filePath + ", domain: " + domain);

Check warning on line 80 in libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/FileInterceptor.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L80 was not covered by tests
}

// File deletion operations
if (isDelete && !policy.implies(domain, new FilePermission(filePath, "delete"))) {
throw new SecurityException("Denied DELETE access to file: " + filePath + ", domain: " + domain);

Check warning on line 85 in libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/FileInterceptor.java

View check run for this annotation

Codecov / codecov/patch

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

Added line #L85 was not covered by tests
}
}
}

Check warning on line 88 in libs/agent-sm/agent/src/main/java/org/opensearch/javaagent/FileInterceptor.java

View check run for this annotation

Codecov / codecov/patch

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

Added lines #L87 - L88 were not covered by tests
}
Loading
Loading