Skip to content

Commit 5cd030e

Browse files
committed
Add a sanity check in JavaClassTest
Extract some constants
1 parent 0df5c29 commit 5cd030e

1 file changed

Lines changed: 50 additions & 18 deletions

File tree

src/test/java/org/apache/bcel/classfile/JavaClassTest.java

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
import java.io.ByteArrayInputStream;
2727
import java.io.ByteArrayOutputStream;
2828
import java.io.IOException;
29+
import java.nio.file.Files;
2930
import java.nio.file.Path;
31+
import java.nio.file.Paths;
3032

3133
import org.apache.bcel.Const;
3234
import org.apache.bcel.Repository;
@@ -37,6 +39,7 @@
3739
import org.apache.bcel.generic.Type;
3840
import org.apache.bcel.util.ClassPath;
3941
import org.apache.bcel.util.SyntheticRepository;
42+
import org.apache.commons.lang3.SystemProperties;
4043
import org.junit.jupiter.api.BeforeAll;
4144
import org.junit.jupiter.api.Test;
4245
import org.junit.jupiter.api.io.TempDir;
@@ -48,8 +51,11 @@
4851
*/
4952
class JavaClassTest {
5053

51-
private static final String CLASS_NAME = "TargetClass";
54+
private static final String INTERFACE_NAME_A = "InterfaceA";
55+
56+
private static final String INTERFACE_NAME_B = "InterfaceB";
5257

58+
private static final String CLASS_NAME = "TargetClass";
5359
// Doesn't compile due to cyclic inheritance
5460
// private interface InterfaceA extends InterfaceB {
5561
// }
@@ -60,14 +66,20 @@ class JavaClassTest {
6066
@TempDir
6167
static Path tempDir;
6268

69+
static Path tempClassFile;
70+
71+
static Path tempIntefaceAFile;
72+
73+
static Path tempIntefaceBFile;
74+
6375
@BeforeAll
6476
static void beforeAll() throws Exception {
6577
// Create InterfaceA that extends InterfaceB (will create cycle)
66-
writeInterfaceA();
78+
tempIntefaceAFile = writeInterfaceA();
6779
// Create InterfaceB that extends InterfaceA (completes the cycle)
68-
writeInterfaceB();
80+
tempIntefaceBFile = writeInterfaceB();
6981
// Create a class that implements InterfaceA
70-
writeTargetClass();
82+
tempClassFile = writeTargetClass();
7183
// Cycle: InterfaceA -> InterfaceB -> InterfaceA -> ...
7284
}
7385

@@ -90,23 +102,27 @@ static byte[] toByteArray(final ClassGen cg) throws IOException {
90102
return baos.toByteArray();
91103
}
92104

93-
private static void writeInterfaceA() throws Exception {
105+
private static Path writeInterfaceA() throws Exception {
94106
// Create InterfaceA that extends InterfaceB
95-
final ClassGen cg = new ClassGen("InterfaceA", "java.lang.Object", "InterfaceA.java", Const.ACC_PUBLIC | Const.ACC_INTERFACE | Const.ACC_ABSTRACT,
96-
new String[] { "InterfaceB" });
97-
cg.getJavaClass().dump(tempDir.resolve("InterfaceA.class").toString());
107+
final ClassGen classGen = new ClassGen(INTERFACE_NAME_A, "java.lang.Object", INTERFACE_NAME_A + ".java",
108+
Const.ACC_PUBLIC | Const.ACC_INTERFACE | Const.ACC_ABSTRACT, new String[] { INTERFACE_NAME_B });
109+
final Path path = tempDir.resolve(INTERFACE_NAME_A + ".class");
110+
classGen.getJavaClass().dump(path.toString());
111+
return path;
98112
}
99113

100-
private static void writeInterfaceB() throws Exception {
114+
private static Path writeInterfaceB() throws Exception {
101115
// Create InterfaceB that extends InterfaceA
102-
final ClassGen cg = new ClassGen("InterfaceB", "java.lang.Object", "InterfaceB.java", Const.ACC_PUBLIC | Const.ACC_INTERFACE | Const.ACC_ABSTRACT,
103-
new String[] { "InterfaceA" });
104-
cg.getJavaClass().dump(tempDir.resolve("InterfaceB.class").toString());
116+
final ClassGen classGen = new ClassGen(INTERFACE_NAME_B, "java.lang.Object", INTERFACE_NAME_B + ".java",
117+
Const.ACC_PUBLIC | Const.ACC_INTERFACE | Const.ACC_ABSTRACT, new String[] { INTERFACE_NAME_A });
118+
final Path path = tempDir.resolve(INTERFACE_NAME_B + ".class");
119+
classGen.getJavaClass().dump(path.toString());
120+
return path;
105121
}
106122

107-
private static void writeTargetClass() throws Exception {
123+
private static Path writeTargetClass() throws Exception {
108124
// Create a class that implements InterfaceA
109-
final ClassGen cg = new ClassGen(CLASS_NAME, "java.lang.Object", "VulnerableClass.java", Const.ACC_PUBLIC, new String[] { "InterfaceA" });
125+
final ClassGen cg = new ClassGen(CLASS_NAME, "java.lang.Object", CLASS_NAME + ".java", Const.ACC_PUBLIC, new String[] { INTERFACE_NAME_A });
110126
// Add default constructor
111127
final InstructionList il = new InstructionList();
112128
final MethodGen constructor = new MethodGen(Const.ACC_PUBLIC, Type.VOID, Type.NO_ARGS, new String[] {}, "<init>", CLASS_NAME, il, cg.getConstantPool());
@@ -119,7 +135,9 @@ private static void writeTargetClass() throws Exception {
119135
cg.addMethod(constructor.getMethod());
120136
il.dispose();
121137
// Create the class file
122-
cg.getJavaClass().dump(tempDir.resolve(CLASS_NAME + ".class").toString());
138+
final Path path = tempDir.resolve(CLASS_NAME + ".class");
139+
cg.getJavaClass().dump(path.toString());
140+
return path;
123141
}
124142

125143
private Field findFieldDoesNotExist(final Class<?> clazz) throws ClassNotFoundException {
@@ -149,11 +167,26 @@ void testFindFieldCustomClass() throws Exception {
149167
}
150168

151169
@Test
152-
void testFindFieldCustomInterface1() throws ClassNotFoundException {
170+
void testFindFieldCustomInterface1() throws IOException, ClassNotFoundException {
153171
// Set up repository to load classes from the malicious_classes directory
154-
final String classPath = tempDir.toString() + System.getProperty("path.separator") + System.getProperty("java.class.path");
172+
final String classPath = tempDir.toString() + SystemProperties.getPathSeparator() + SystemProperties.getJavaClassPath();
155173
Repository.setRepository(SyntheticRepository.getInstance(new ClassPath(classPath)));
156174
assertThrows(ClassFormatException.class, () -> Repository.lookupClass(CLASS_NAME).findField("nonExistentField", Type.INT));
175+
// sanity check
176+
final Path targetDir = Paths.get("target/test-classes");
177+
final Path targetClassFile = targetDir.resolve(CLASS_NAME + ".class");
178+
final Path targetInterfaceA = targetDir.resolve(INTERFACE_NAME_A + ".class");
179+
final Path targetInterfaceB = targetDir.resolve(INTERFACE_NAME_B + ".class");
180+
try {
181+
Files.copy(tempClassFile, targetClassFile);
182+
Files.copy(tempIntefaceAFile, targetInterfaceA);
183+
Files.copy(tempIntefaceBFile, targetInterfaceB);
184+
assertThrows(ClassCircularityError.class, () -> Class.forName(CLASS_NAME));
185+
} finally {
186+
Files.delete(targetClassFile);
187+
Files.delete(targetInterfaceA);
188+
Files.delete(targetInterfaceB);
189+
}
157190
}
158191

159192
@Test
@@ -195,5 +228,4 @@ void testGetAllInterfaces(final Class<?> clazz) throws ClassNotFoundException {
195228
void testGetSuperClassesAll(final Class<?> clazz) throws ClassNotFoundException {
196229
assertNotNull(Repository.lookupClass(clazz.getName()).getSuperClasses());
197230
}
198-
199231
}

0 commit comments

Comments
 (0)