From ee36dba246ac52a1abc2691833246190b6fdfefd Mon Sep 17 00:00:00 2001 From: idawda Date: Tue, 10 Dec 2024 19:54:03 +0530 Subject: [PATCH 1/4] Initial support for graalvm-24.1.0 --- .../graalvm-jsinjection-24.1.0/build.gradle | 38 +++++++++++++++++++ .../PolyglotContextImpl_Instrumentation.java | 28 ++++++++++++++ settings.gradle | 1 + 3 files changed, 67 insertions(+) create mode 100644 instrumentation-security/graalvm-jsinjection-24.1.0/build.gradle create mode 100644 instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java diff --git a/instrumentation-security/graalvm-jsinjection-24.1.0/build.gradle b/instrumentation-security/graalvm-jsinjection-24.1.0/build.gradle new file mode 100644 index 000000000..33c3f4a6d --- /dev/null +++ b/instrumentation-security/graalvm-jsinjection-24.1.0/build.gradle @@ -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' +} \ No newline at end of file diff --git a/instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java b/instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java new file mode 100644 index 000000000..c8fdf87db --- /dev/null +++ b/instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java @@ -0,0 +1,28 @@ +package com.oracle.truffle.polyglot; + +import com.newrelic.api.agent.weaver.Weave; +import com.newrelic.api.agent.weaver.Weaver; +import org.graalvm.polyglot.Source; +import org.graalvm.polyglot.impl.AbstractPolyglotImpl; + +@Weave(originalName = "com.oracle.truffle.polyglot.PolyglotContextImpl") +public abstract class PolyglotContextImpl_Instrumentation { + + abstract AbstractPolyglotImpl.APIAccess getAPIAccess(); + + public Object eval(String languageId, Object source) { + Object result; + try { + if (source instanceof Source) { + ((Source) source).getCharacters(); + + com.oracle.truffle.api.source.Source sourceReceiver = (com.oracle.truffle.api.source.Source) getAPIAccess().getSourceReceiver(source); + sourceReceiver.getCharacters(); + } + } catch (Exception e) { + } + result = Weaver.callOriginal(); + return result; + } +} + diff --git a/settings.gradle b/settings.gradle index 64dd79da8..28ae0a5e2 100644 --- a/settings.gradle +++ b/settings.gradle @@ -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' From f6bc287332ffabfbc292db14a61f30329c2911f1 Mon Sep 17 00:00:00 2001 From: idawda Date: Tue, 10 Dec 2024 20:02:42 +0530 Subject: [PATCH 2/4] update class and method access in graalvm --- .../polyglot/PolyglotContextImpl_Instrumentation.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java b/instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java index c8fdf87db..792aa873b 100644 --- a/instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java +++ b/instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java @@ -6,9 +6,11 @@ import org.graalvm.polyglot.impl.AbstractPolyglotImpl; @Weave(originalName = "com.oracle.truffle.polyglot.PolyglotContextImpl") -public abstract class PolyglotContextImpl_Instrumentation { +final class PolyglotContextImpl_Instrumentation { - abstract AbstractPolyglotImpl.APIAccess getAPIAccess(); + public AbstractPolyglotImpl.APIAccess getAPIAccess() { + return Weaver.callOriginal(); + } public Object eval(String languageId, Object source) { Object result; From ace5f94bc3be79a01e90f9bf729fa3ce0b62749a Mon Sep 17 00:00:00 2001 From: idawda Date: Wed, 11 Dec 2024 16:14:33 +0530 Subject: [PATCH 3/4] GraalVM Instrumentation support --- .../graalvm24/JSEngineUtils.java | 9 ++ .../PolyglotContextImpl_Instrumentation.java | 82 +++++++++++++++++-- 2 files changed, 85 insertions(+), 6 deletions(-) create mode 100644 instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/newrelic/agent/security/instrumentation/graalvm24/JSEngineUtils.java diff --git a/instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/newrelic/agent/security/instrumentation/graalvm24/JSEngineUtils.java b/instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/newrelic/agent/security/instrumentation/graalvm24/JSEngineUtils.java new file mode 100644 index 000000000..457cbc28e --- /dev/null +++ b/instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/newrelic/agent/security/instrumentation/graalvm24/JSEngineUtils.java @@ -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"; +} diff --git a/instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java b/instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java index 792aa873b..b4ea978b1 100644 --- a/instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java +++ b/instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java @@ -1,5 +1,14 @@ 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 org.graalvm.polyglot.Source; @@ -13,18 +22,79 @@ public AbstractPolyglotImpl.APIAccess getAPIAccess() { } 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 { - if (source instanceof Source) { - ((Source) source).getCharacters(); + 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 { + JSInjectionOperation jsInjectionOperation = null; + if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || + !StringUtils.equalsIgnoreCase(languageId, JSEngineUtils.LANGUAGE_ID_JS)) { + return null; + } + if (source instanceof Source) { com.oracle.truffle.api.source.Source sourceReceiver = (com.oracle.truffle.api.source.Source) getAPIAccess().getSourceReceiver(source); - sourceReceiver.getCharacters(); + jsInjectionOperation = new JSInjectionOperation(String.valueOf(sourceReceiver.getCharacters()), this.getClass().getName(), methodName); + NewRelicSecurity.getAgent().registerOperation(jsInjectionOperation); } - } catch (Exception e) { + 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()); } - result = Weaver.callOriginal(); - return result; + 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); + } + } From dce3984695c80ebffeeeaa5694327456e39094bd Mon Sep 17 00:00:00 2001 From: idawda Date: Wed, 11 Dec 2024 16:33:09 +0530 Subject: [PATCH 4/4] remove conditional statements --- .../PolyglotContextImpl_Instrumentation.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java b/instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java index b4ea978b1..3a36f5442 100644 --- a/instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java +++ b/instrumentation-security/graalvm-jsinjection-24.1.0/src/main/java/com/oracle/truffle/polyglot/PolyglotContextImpl_Instrumentation.java @@ -11,7 +11,7 @@ import com.newrelic.api.agent.security.utils.logging.LogLevel; import com.newrelic.api.agent.weaver.Weave; import com.newrelic.api.agent.weaver.Weaver; -import org.graalvm.polyglot.Source; +import com.oracle.truffle.api.source.Source; import org.graalvm.polyglot.impl.AbstractPolyglotImpl; @Weave(originalName = "com.oracle.truffle.polyglot.PolyglotContextImpl") @@ -57,16 +57,16 @@ private void registerExitOperation(boolean isProcessingAllowed, AbstractOperatio private AbstractOperation preprocessSecurityHook(String languageId, Object source, String methodName) { try { - JSInjectionOperation jsInjectionOperation = null; if (!NewRelicSecurity.isHookProcessingActive() || NewRelicSecurity.getAgent().getSecurityMetaData().getRequest().isEmpty() || !StringUtils.equalsIgnoreCase(languageId, JSEngineUtils.LANGUAGE_ID_JS)) { return null; } - if (source instanceof Source) { - com.oracle.truffle.api.source.Source sourceReceiver = (com.oracle.truffle.api.source.Source) getAPIAccess().getSourceReceiver(source); - jsInjectionOperation = new JSInjectionOperation(String.valueOf(sourceReceiver.getCharacters()), this.getClass().getName(), methodName); - NewRelicSecurity.getAgent().registerOperation(jsInjectionOperation); - } + + // 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) {