Skip to content
Open
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
38 changes: 38 additions & 0 deletions instrumentation-security/graalvm-jsinjection-24.1.0/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
dependencies {
implementation(project(":newrelic-security-api"))
implementation("com.newrelic.agent.java:newrelic-api:${nrAPIVersion}")
implementation("com.newrelic.agent.java:newrelic-weaver-api:${nrAPIVersion}")
implementation("org.graalvm.truffle:truffle-api:24.1.0")
implementation("org.graalvm.js:js:24.1.0")
}

jar {
manifest { attributes 'Implementation-Title': 'com.newrelic.instrumentation.security.graalvm-jsinjection-24.1.0' }
}

verifyInstrumentation {
passes 'org.graalvm.truffle:truffle-api:[24.1.0,)'
}

java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}

compileJava {
options.fork = true
options.bootstrapClasspath = null
}

test {
// These instrumentation tests only run on Java 17+ regardless of the -PtestN gradle property that is set.
onlyIf {
!project.hasProperty('test8') && !project.hasProperty('test11')
}
}

site {
title 'JSInjection'
type 'Messaging'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.newrelic.agent.security.instrumentation.graalvm24;

public class JSEngineUtils {

public static final String NR_SEC_CUSTOM_ATTRIB_NAME = "JSENGINE_OPERATION_LOCK_NASHORN-";
public static final String GRAALVM_JS_INJECTION_24_1_0 = "GRAALVM_JS_INJECTION_24.1.0";
public static final String METHOD_EVAL = "eval";
public static final CharSequence LANGUAGE_ID_JS = "js";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package com.oracle.truffle.polyglot;

import com.newrelic.agent.security.instrumentation.graalvm24.JSEngineUtils;
import com.newrelic.api.agent.security.NewRelicSecurity;
import com.newrelic.api.agent.security.instrumentation.helpers.GenericHelper;
import com.newrelic.api.agent.security.schema.AbstractOperation;
import com.newrelic.api.agent.security.schema.StringUtils;
import com.newrelic.api.agent.security.schema.VulnerabilityCaseType;
import com.newrelic.api.agent.security.schema.exceptions.NewRelicSecurityException;
import com.newrelic.api.agent.security.schema.operation.JSInjectionOperation;
import com.newrelic.api.agent.security.utils.logging.LogLevel;
import com.newrelic.api.agent.weaver.Weave;
import com.newrelic.api.agent.weaver.Weaver;
import com.oracle.truffle.api.source.Source;
import org.graalvm.polyglot.impl.AbstractPolyglotImpl;

@Weave(originalName = "com.oracle.truffle.polyglot.PolyglotContextImpl")
final class PolyglotContextImpl_Instrumentation {

public AbstractPolyglotImpl.APIAccess getAPIAccess() {
return Weaver.callOriginal();
}

public Object eval(String languageId, Object source) {
boolean isLockAcquired = acquireLockIfPossible();
AbstractOperation operation = null;
if (isLockAcquired) {
operation = preprocessSecurityHook(languageId, source, JSEngineUtils.METHOD_EVAL);
}
Object result;
try {
result = Weaver.callOriginal();
} finally {
if (isLockAcquired) {
releaseLock();
}
}
registerExitOperation(isLockAcquired, operation);
return result;
}

private void registerExitOperation(boolean isProcessingAllowed, AbstractOperation operation) {
try {
if (operation == null || !isProcessingAllowed || !NewRelicSecurity.isHookProcessingActive() ||
NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || GenericHelper.skipExistsEvent()
) {
return;
}
NewRelicSecurity.getAgent().registerExitEvent(operation);
} catch (Throwable ignored) {
NewRelicSecurity.getAgent()
.log(LogLevel.FINEST,
String.format(GenericHelper.EXIT_OPERATION_EXCEPTION_MESSAGE, JSEngineUtils.GRAALVM_JS_INJECTION_24_1_0, ignored.getMessage()),
ignored, this.getClass().getName());
}
}

private AbstractOperation preprocessSecurityHook(String languageId, Object source, String methodName) {
try {
if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() ||
!StringUtils.equalsIgnoreCase(languageId, JSEngineUtils.LANGUAGE_ID_JS)) {
return null;
}

// Getting the source to get the Characters
Source sourceReceiver = (com.oracle.truffle.api.source.Source) getAPIAccess().getSourceReceiver(source);
JSInjectionOperation jsInjectionOperation = new JSInjectionOperation(String.valueOf(sourceReceiver.getCharacters()), this.getClass().getName(),
methodName);
NewRelicSecurity.getAgent().registerOperation(jsInjectionOperation);
return jsInjectionOperation;
} catch (Throwable e) {
if (e instanceof NewRelicSecurityException) {
NewRelicSecurity.getAgent()
.log(LogLevel.WARNING,
String.format(GenericHelper.SECURITY_EXCEPTION_MESSAGE, JSEngineUtils.GRAALVM_JS_INJECTION_24_1_0, e.getMessage()), e,
this.getClass().getName());
throw e;
}
NewRelicSecurity.getAgent()
.log(LogLevel.SEVERE,
String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, JSEngineUtils.GRAALVM_JS_INJECTION_24_1_0, e.getMessage()), e,
this.getClass().getName());
NewRelicSecurity.getAgent()
.reportIncident(LogLevel.SEVERE,
String.format(GenericHelper.REGISTER_OPERATION_EXCEPTION_MESSAGE, JSEngineUtils.GRAALVM_JS_INJECTION_24_1_0, e.getMessage()), e,
this.getClass().getName());
}
return null;
}

private void releaseLock() {
GenericHelper.releaseLock(JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME);
}

private boolean acquireLockIfPossible() {
return GenericHelper.acquireLockIfPossible(VulnerabilityCaseType.JAVASCRIPT_INJECTION, JSEngineUtils.NR_SEC_CUSTOM_ATTRIB_NAME);
}

}

1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ include 'instrumentation:nashorn-jsinjection'
include 'instrumentation:rhino-jsinjection'
include 'instrumentation:graalvm-jsinjection-19.0.0'
include 'instrumentation:graalvm-jsinjection-22.0.0'
include 'instrumentation:graalvm-jsinjection-24.1.0'
include 'instrumentation:apache-log4j-2.0'
include 'instrumentation:apache-log4j-2.17.2'
include 'instrumentation:apache-log4j-3.0.0'
Expand Down
Loading