This is an automated email from the ASF dual-hosted git repository.
garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-bcel.git
The following commit(s) were added to refs/heads/master by this push:
new 512a70bb Silent u2/u1 count truncation across dump paths corrupts
emitted bytecode (f013).
512a70bb is described below
commit 512a70bb882c27d201e07f1645bd3679f51ab3b3
Author: Gary Gregory <[email protected]>
AuthorDate: Fri Sep 4 17:12:42 2026 -0400
Silent u2/u1 count truncation across dump paths corrupts emitted
bytecode (f013).
---
.../org/apache/bcel/classfile/AnnotationEntry.java | 3 +-
.../org/apache/bcel/classfile/Annotations.java | 3 +-
.../apache/bcel/classfile/ArrayElementValue.java | 4 +-
.../org/apache/bcel/classfile/BootstrapMethod.java | 3 +-
.../apache/bcel/classfile/BootstrapMethods.java | 3 +-
src/main/java/org/apache/bcel/classfile/Code.java | 5 ++-
.../org/apache/bcel/classfile/ConstantPool.java | 14 +++---
.../org/apache/bcel/classfile/ExceptionTable.java | 2 +-
.../org/apache/bcel/classfile/FieldOrMethod.java | 4 +-
.../org/apache/bcel/classfile/InnerClasses.java | 2 +-
.../java/org/apache/bcel/classfile/JavaClass.java | 9 ++--
.../org/apache/bcel/classfile/LineNumberTable.java | 2 +-
.../apache/bcel/classfile/LocalVariableTable.java | 2 +-
.../bcel/classfile/LocalVariableTypeTable.java | 2 +-
.../apache/bcel/classfile/MethodParameters.java | 3 +-
.../java/org/apache/bcel/classfile/Module.java | 11 ++---
.../org/apache/bcel/classfile/ModulePackages.java | 2 +-
.../org/apache/bcel/classfile/NestMembers.java | 2 +-
.../bcel/classfile/ParameterAnnotationEntry.java | 4 +-
.../bcel/classfile/ParameterAnnotations.java | 4 +-
.../apache/bcel/classfile/PermittedSubclasses.java | 2 +-
.../java/org/apache/bcel/classfile/Record.java | 2 +-
.../apache/bcel/classfile/RecordComponentInfo.java | 3 +-
.../java/org/apache/bcel/classfile/StackMap.java | 2 +-
.../org/apache/bcel/classfile/StackMapEntry.java | 5 ++-
.../apache/bcel/generic/AnnotationEntryGen.java | 7 +--
.../apache/bcel/generic/ArrayElementValueGen.java | 3 +-
.../apache/bcel/classfile/DumpU2OverflowTest.java | 52 ++++++++++++++++++++++
28 files changed, 117 insertions(+), 43 deletions(-)
diff --git a/src/main/java/org/apache/bcel/classfile/AnnotationEntry.java
b/src/main/java/org/apache/bcel/classfile/AnnotationEntry.java
index 0c3ae5e1..9d2ba196 100644
--- a/src/main/java/org/apache/bcel/classfile/AnnotationEntry.java
+++ b/src/main/java/org/apache/bcel/classfile/AnnotationEntry.java
@@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
+import org.apache.bcel.util.Args;
import org.apache.commons.lang3.stream.Streams;
/**
@@ -136,7 +137,7 @@ public class AnnotationEntry implements Node {
*/
public void dump(final DataOutputStream dos) throws IOException {
dos.writeShort(typeIndex); // u2 index of type name in cpool
- dos.writeShort(elementValuePairs.size()); // u2 element_value pair
+ dos.writeShort(Args.requireU2(elementValuePairs.size(),
"elementValuePairs.size()")); // u2 element_value pair
// count
for (final ElementValuePair envp : elementValuePairs) {
envp.dump(dos);
diff --git a/src/main/java/org/apache/bcel/classfile/Annotations.java
b/src/main/java/org/apache/bcel/classfile/Annotations.java
index 8d77d3ed..9a4065f8 100644
--- a/src/main/java/org/apache/bcel/classfile/Annotations.java
+++ b/src/main/java/org/apache/bcel/classfile/Annotations.java
@@ -25,6 +25,7 @@ import java.util.Iterator;
import java.util.stream.Stream;
import org.apache.bcel.Const;
+import org.apache.bcel.util.Args;
/**
* base class for annotations
@@ -158,7 +159,7 @@ public abstract class Annotations extends Attribute
implements Iterable<Annotati
* @throws IOException Thrown if an I/O error occurs.
*/
protected void writeAnnotations(final DataOutputStream dos) throws
IOException {
- dos.writeShort(annotationTable.length);
+ dos.writeShort(Args.requireU2(annotationTable.length,
"annotationTable.length"));
for (final AnnotationEntry element : annotationTable) {
element.dump(dos);
}
diff --git a/src/main/java/org/apache/bcel/classfile/ArrayElementValue.java
b/src/main/java/org/apache/bcel/classfile/ArrayElementValue.java
index 43404152..5a8d3195 100644
--- a/src/main/java/org/apache/bcel/classfile/ArrayElementValue.java
+++ b/src/main/java/org/apache/bcel/classfile/ArrayElementValue.java
@@ -21,6 +21,8 @@ package org.apache.bcel.classfile;
import java.io.DataOutputStream;
import java.io.IOException;
+import org.apache.bcel.util.Args;
+
/**
* Represents an array element value in an annotation.
*
@@ -48,7 +50,7 @@ public class ArrayElementValue extends ElementValue {
@Override
public void dump(final DataOutputStream dos) throws IOException {
dos.writeByte(super.getType()); // u1 type of value (ARRAY == '[')
- dos.writeShort(elementValues.length);
+ dos.writeShort(Args.requireU2(elementValues.length,
"elementValues.length"));
for (final ElementValue evalue : elementValues) {
evalue.dump(dos);
}
diff --git a/src/main/java/org/apache/bcel/classfile/BootstrapMethod.java
b/src/main/java/org/apache/bcel/classfile/BootstrapMethod.java
index 8111e61f..c44af889 100644
--- a/src/main/java/org/apache/bcel/classfile/BootstrapMethod.java
+++ b/src/main/java/org/apache/bcel/classfile/BootstrapMethod.java
@@ -25,6 +25,7 @@ import java.io.IOException;
import java.util.Arrays;
import org.apache.bcel.Const;
+import org.apache.bcel.util.Args;
import org.apache.commons.lang3.ArrayUtils;
/**
@@ -108,7 +109,7 @@ public class BootstrapMethod implements Cloneable {
*/
public final void dump(final DataOutputStream file) throws IOException {
file.writeShort(bootstrapMethodRef);
- file.writeShort(bootstrapArguments.length);
+ file.writeShort(Args.requireU2(bootstrapArguments.length,
"bootstrapArguments.length"));
for (final int bootstrapArgument : bootstrapArguments) {
file.writeShort(bootstrapArgument);
}
diff --git a/src/main/java/org/apache/bcel/classfile/BootstrapMethods.java
b/src/main/java/org/apache/bcel/classfile/BootstrapMethods.java
index a3a8dcaf..86bd897d 100644
--- a/src/main/java/org/apache/bcel/classfile/BootstrapMethods.java
+++ b/src/main/java/org/apache/bcel/classfile/BootstrapMethods.java
@@ -26,6 +26,7 @@ import java.util.Iterator;
import java.util.stream.Stream;
import org.apache.bcel.Const;
+import org.apache.bcel.util.Args;
/**
* This class represents a BootstrapMethods attribute.
@@ -118,7 +119,7 @@ public class BootstrapMethods extends Attribute implements
Iterable<BootstrapMet
public final void dump(final DataOutputStream file) throws IOException {
super.dump(file);
- file.writeShort(bootstrapMethods.length);
+ file.writeShort(Args.requireU2(bootstrapMethods.length,
"bootstrapMethods.length"));
for (final BootstrapMethod bootstrapMethod : bootstrapMethods) {
bootstrapMethod.dump(file);
}
diff --git a/src/main/java/org/apache/bcel/classfile/Code.java
b/src/main/java/org/apache/bcel/classfile/Code.java
index 0f5de194..d6a71557 100644
--- a/src/main/java/org/apache/bcel/classfile/Code.java
+++ b/src/main/java/org/apache/bcel/classfile/Code.java
@@ -202,11 +202,11 @@ public final class Code extends Attribute {
file.writeShort(maxLocals);
file.writeInt(code.length);
file.write(code, 0, code.length);
- file.writeShort(exceptionTable.length);
+ file.writeShort(Args.requireU2(exceptionTable.length,
"exceptionTable.length"));
for (final CodeException exception : exceptionTable) {
exception.dump(file);
}
- file.writeShort(attributes.length);
+ file.writeShort(Args.requireU2(attributes.length,
"attributes.length"));
for (final Attribute attribute : attributes) {
attribute.dump(file);
}
@@ -359,6 +359,7 @@ public final class Code extends Attribute {
*/
public void setExceptionTable(final CodeException[] exceptionTable) {
this.exceptionTable = exceptionTable != null ? exceptionTable :
CodeException.EMPTY_ARRAY;
+ Args.requireU2(this.exceptionTable.length, "exceptionTable.length");
super.setLength(calculateLength()); // Adjust length
}
diff --git a/src/main/java/org/apache/bcel/classfile/ConstantPool.java
b/src/main/java/org/apache/bcel/classfile/ConstantPool.java
index 975030e6..6a62dc2f 100644
--- a/src/main/java/org/apache/bcel/classfile/ConstantPool.java
+++ b/src/main/java/org/apache/bcel/classfile/ConstantPool.java
@@ -245,13 +245,15 @@ public class ConstantPool implements Cloneable, Node,
Iterable<Constant> {
*/
public void dump(final DataOutputStream file) throws IOException {
/*
- * Constants over the size of the constant pool shall not be written
out. This is a redundant measure as the ConstantPoolGen should have already
- * reported an error back in the situation.
+ * A constant pool larger than the u2 count field can represent must
fail loudly instead of being silently
+ * truncated: class structures may still reference the dropped
entries, and a wrapped count with extra bodies
+ * desynchronizes any consumer that reparses the emitted bytes (the
CVE-2022-42920 writer-overflow shape).
*/
- final int size = Math.min(constantPool.length, Const.MAX_CP_ENTRIES);
-
- file.writeShort(size);
- for (int i = 1; i < size; i++) {
+ if (constantPool.length > Const.MAX_CP_ENTRIES) {
+ throw new ClassFormatException("Constant pool size " +
constantPool.length + " exceeds the u2 maximum of " + Const.MAX_CP_ENTRIES);
+ }
+ file.writeShort(constantPool.length);
+ for (int i = 1; i < constantPool.length; i++) {
if (constantPool[i] != null) {
constantPool[i].dump(file);
}
diff --git a/src/main/java/org/apache/bcel/classfile/ExceptionTable.java
b/src/main/java/org/apache/bcel/classfile/ExceptionTable.java
index 48aca824..ae490f44 100644
--- a/src/main/java/org/apache/bcel/classfile/ExceptionTable.java
+++ b/src/main/java/org/apache/bcel/classfile/ExceptionTable.java
@@ -122,7 +122,7 @@ public final class ExceptionTable extends Attribute {
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
- file.writeShort(exceptionIndexTable.length);
+ file.writeShort(Args.requireU2(exceptionIndexTable.length,
"exceptionIndexTable.length"));
for (final int index : exceptionIndexTable) {
file.writeShort(index);
}
diff --git a/src/main/java/org/apache/bcel/classfile/FieldOrMethod.java
b/src/main/java/org/apache/bcel/classfile/FieldOrMethod.java
index e779686e..6b53db55 100644
--- a/src/main/java/org/apache/bcel/classfile/FieldOrMethod.java
+++ b/src/main/java/org/apache/bcel/classfile/FieldOrMethod.java
@@ -24,6 +24,8 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
+import org.apache.bcel.util.Args;
+
/**
* Abstract super class for fields and methods.
*/
@@ -155,7 +157,7 @@ public abstract class FieldOrMethod extends AccessFlags
implements Cloneable, No
file.writeShort(super.getAccessFlags());
file.writeShort(name_index);
file.writeShort(signature_index);
- file.writeShort(attributes_count);
+ file.writeShort(Args.requireU2(attributes_count, "attributes_count"));
for (final Attribute attribute : attributes) {
attribute.dump(file);
}
diff --git a/src/main/java/org/apache/bcel/classfile/InnerClasses.java
b/src/main/java/org/apache/bcel/classfile/InnerClasses.java
index e130c77a..8a6aab0b 100644
--- a/src/main/java/org/apache/bcel/classfile/InnerClasses.java
+++ b/src/main/java/org/apache/bcel/classfile/InnerClasses.java
@@ -120,7 +120,7 @@ public final class InnerClasses extends Attribute
implements Iterable<InnerClass
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
- file.writeShort(innerClasses.length);
+ file.writeShort(Args.requireU2(innerClasses.length,
"innerClasses.length"));
for (final InnerClass innerClass : innerClasses) {
innerClass.dump(file);
}
diff --git a/src/main/java/org/apache/bcel/classfile/JavaClass.java
b/src/main/java/org/apache/bcel/classfile/JavaClass.java
index 287c9cf4..7a45489d 100644
--- a/src/main/java/org/apache/bcel/classfile/JavaClass.java
+++ b/src/main/java/org/apache/bcel/classfile/JavaClass.java
@@ -35,6 +35,7 @@ import java.util.TreeSet;
import org.apache.bcel.Const;
import org.apache.bcel.generic.Type;
+import org.apache.bcel.util.Args;
import org.apache.bcel.util.BCELComparator;
import org.apache.bcel.util.ClassQueue;
import org.apache.bcel.util.SyntheticRepository;
@@ -348,20 +349,20 @@ public class JavaClass extends AccessFlags implements
Cloneable, Node, Comparabl
file.writeShort(super.getAccessFlags());
file.writeShort(classNameIndex);
file.writeShort(superclassNameIndex);
- file.writeShort(interfaces.length);
+ file.writeShort(Args.requireU2(interfaces.length,
"interfaces.length"));
for (final int interface1 : interfaces) {
file.writeShort(interface1);
}
- file.writeShort(fields.length);
+ file.writeShort(Args.requireU2(fields.length, "fields.length"));
for (final Field field : fields) {
field.dump(file);
}
- file.writeShort(methods.length);
+ file.writeShort(Args.requireU2(methods.length, "methods.length"));
for (final Method method : methods) {
method.dump(file);
}
if (attributes != null) {
- file.writeShort(attributes.length);
+ file.writeShort(Args.requireU2(attributes.length,
"attributes.length"));
for (final Attribute attribute : attributes) {
attribute.dump(file);
}
diff --git a/src/main/java/org/apache/bcel/classfile/LineNumberTable.java
b/src/main/java/org/apache/bcel/classfile/LineNumberTable.java
index b206abcc..57d5e538 100644
--- a/src/main/java/org/apache/bcel/classfile/LineNumberTable.java
+++ b/src/main/java/org/apache/bcel/classfile/LineNumberTable.java
@@ -119,7 +119,7 @@ public final class LineNumberTable extends Attribute
implements Iterable<LineNum
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
- file.writeShort(lineNumberTable.length);
+ file.writeShort(Args.requireU2(lineNumberTable.length,
"lineNumberTable.length"));
for (final LineNumber lineNumber : lineNumberTable) {
lineNumber.dump(file);
}
diff --git a/src/main/java/org/apache/bcel/classfile/LocalVariableTable.java
b/src/main/java/org/apache/bcel/classfile/LocalVariableTable.java
index 59218c4b..16a3085e 100644
--- a/src/main/java/org/apache/bcel/classfile/LocalVariableTable.java
+++ b/src/main/java/org/apache/bcel/classfile/LocalVariableTable.java
@@ -115,7 +115,7 @@ public class LocalVariableTable extends Attribute
implements Iterable<LocalVaria
@Override
public final void dump(final DataOutputStream file) throws IOException {
super.dump(file);
- file.writeShort(localVariableTable.length);
+ file.writeShort(Args.requireU2(localVariableTable.length,
"localVariableTable.length"));
for (final LocalVariable variable : localVariableTable) {
variable.dump(file);
}
diff --git
a/src/main/java/org/apache/bcel/classfile/LocalVariableTypeTable.java
b/src/main/java/org/apache/bcel/classfile/LocalVariableTypeTable.java
index 61e61a65..16c94593 100644
--- a/src/main/java/org/apache/bcel/classfile/LocalVariableTypeTable.java
+++ b/src/main/java/org/apache/bcel/classfile/LocalVariableTypeTable.java
@@ -120,7 +120,7 @@ public class LocalVariableTypeTable extends Attribute
implements Iterable<LocalV
@Override
public final void dump(final DataOutputStream file) throws IOException {
super.dump(file);
- file.writeShort(localVariableTypeTable.length);
+ file.writeShort(Args.requireU2(localVariableTypeTable.length,
"localVariableTypeTable.length"));
for (final LocalVariable variable : localVariableTypeTable) {
variable.dump(file);
}
diff --git a/src/main/java/org/apache/bcel/classfile/MethodParameters.java
b/src/main/java/org/apache/bcel/classfile/MethodParameters.java
index ada146e1..624b00c8 100644
--- a/src/main/java/org/apache/bcel/classfile/MethodParameters.java
+++ b/src/main/java/org/apache/bcel/classfile/MethodParameters.java
@@ -27,6 +27,7 @@ import java.util.Iterator;
import java.util.stream.Stream;
import org.apache.bcel.Const;
+import org.apache.bcel.util.Args;
/**
* This class represents a MethodParameters attribute.
@@ -76,7 +77,7 @@ public class MethodParameters extends Attribute implements
Iterable<MethodParame
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
- file.writeByte(parameters.length);
+ file.writeByte(Args.requireU1(parameters.length, "parameters.length"));
for (final MethodParameter parameter : parameters) {
parameter.dump(file);
}
diff --git a/src/main/java/org/apache/bcel/classfile/Module.java
b/src/main/java/org/apache/bcel/classfile/Module.java
index a40c8d98..4fafe757 100644
--- a/src/main/java/org/apache/bcel/classfile/Module.java
+++ b/src/main/java/org/apache/bcel/classfile/Module.java
@@ -25,6 +25,7 @@ import java.io.IOException;
import java.util.Arrays;
import org.apache.bcel.Const;
+import org.apache.bcel.util.Args;
/**
* This class is derived from <em>Attribute</em> and represents the list of
modules required, exported, opened or
@@ -153,27 +154,27 @@ public final class Module extends Attribute {
file.writeShort(moduleFlags);
file.writeShort(moduleVersionIndex);
- file.writeShort(requiresTable.length);
+ file.writeShort(Args.requireU2(requiresTable.length,
"requiresTable.length"));
for (final ModuleRequires entry : requiresTable) {
entry.dump(file);
}
- file.writeShort(exportsTable.length);
+ file.writeShort(Args.requireU2(exportsTable.length,
"exportsTable.length"));
for (final ModuleExports entry : exportsTable) {
entry.dump(file);
}
- file.writeShort(opensTable.length);
+ file.writeShort(Args.requireU2(opensTable.length,
"opensTable.length"));
for (final ModuleOpens entry : opensTable) {
entry.dump(file);
}
- file.writeShort(usesIndex.length);
+ file.writeShort(Args.requireU2(usesIndex.length, "usesIndex.length"));
for (final int entry : usesIndex) {
file.writeShort(entry);
}
- file.writeShort(providesTable.length);
+ file.writeShort(Args.requireU2(providesTable.length,
"providesTable.length"));
for (final ModuleProvides entry : providesTable) {
entry.dump(file);
}
diff --git a/src/main/java/org/apache/bcel/classfile/ModulePackages.java
b/src/main/java/org/apache/bcel/classfile/ModulePackages.java
index 45584982..53e55d47 100644
--- a/src/main/java/org/apache/bcel/classfile/ModulePackages.java
+++ b/src/main/java/org/apache/bcel/classfile/ModulePackages.java
@@ -109,7 +109,7 @@ public final class ModulePackages extends Attribute {
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
- file.writeShort(packageIndexTable.length);
+ file.writeShort(Args.requireU2(packageIndexTable.length,
"packageIndexTable.length"));
for (final int index : packageIndexTable) {
file.writeShort(index);
}
diff --git a/src/main/java/org/apache/bcel/classfile/NestMembers.java
b/src/main/java/org/apache/bcel/classfile/NestMembers.java
index 2cac6c29..dbfb928e 100644
--- a/src/main/java/org/apache/bcel/classfile/NestMembers.java
+++ b/src/main/java/org/apache/bcel/classfile/NestMembers.java
@@ -110,7 +110,7 @@ public final class NestMembers extends Attribute {
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
- file.writeShort(classes.length);
+ file.writeShort(Args.requireU2(classes.length, "classes.length"));
for (final int index : classes) {
file.writeShort(index);
}
diff --git
a/src/main/java/org/apache/bcel/classfile/ParameterAnnotationEntry.java
b/src/main/java/org/apache/bcel/classfile/ParameterAnnotationEntry.java
index b68e630e..df48f743 100644
--- a/src/main/java/org/apache/bcel/classfile/ParameterAnnotationEntry.java
+++ b/src/main/java/org/apache/bcel/classfile/ParameterAnnotationEntry.java
@@ -25,6 +25,8 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import org.apache.bcel.util.Args;
+
/**
* represents one parameter annotation in the parameter annotation table
*
@@ -94,7 +96,7 @@ public class ParameterAnnotationEntry implements Node {
* @throws IOException Thrown if an I/O error occurs.
*/
public void dump(final DataOutputStream dos) throws IOException {
- dos.writeShort(annotationTable.length);
+ dos.writeShort(Args.requireU2(annotationTable.length,
"annotationTable.length"));
for (final AnnotationEntry entry : annotationTable) {
entry.dump(dos);
}
diff --git a/src/main/java/org/apache/bcel/classfile/ParameterAnnotations.java
b/src/main/java/org/apache/bcel/classfile/ParameterAnnotations.java
index ac3abf42..8d39af10 100644
--- a/src/main/java/org/apache/bcel/classfile/ParameterAnnotations.java
+++ b/src/main/java/org/apache/bcel/classfile/ParameterAnnotations.java
@@ -24,6 +24,8 @@ import java.io.IOException;
import java.util.Iterator;
import java.util.stream.Stream;
+import org.apache.bcel.util.Args;
+
/**
* base class for parameter annotations
*
@@ -93,7 +95,7 @@ public abstract class ParameterAnnotations extends Attribute
implements Iterable
@Override
public void dump(final DataOutputStream dos) throws IOException {
super.dump(dos);
- dos.writeByte(parameterAnnotationTable.length);
+ dos.writeByte(Args.requireU1(parameterAnnotationTable.length,
"parameterAnnotationTable.length"));
for (final ParameterAnnotationEntry element :
parameterAnnotationTable) {
element.dump(dos);
diff --git a/src/main/java/org/apache/bcel/classfile/PermittedSubclasses.java
b/src/main/java/org/apache/bcel/classfile/PermittedSubclasses.java
index 3faa5e78..dec87cbd 100644
--- a/src/main/java/org/apache/bcel/classfile/PermittedSubclasses.java
+++ b/src/main/java/org/apache/bcel/classfile/PermittedSubclasses.java
@@ -113,7 +113,7 @@ public final class PermittedSubclasses extends Attribute {
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
- file.writeShort(classes.length);
+ file.writeShort(Args.requireU2(classes.length, "classes.length"));
for (final int index : classes) {
file.writeShort(index);
}
diff --git a/src/main/java/org/apache/bcel/classfile/Record.java
b/src/main/java/org/apache/bcel/classfile/Record.java
index 4949c5e3..de31aaab 100644
--- a/src/main/java/org/apache/bcel/classfile/Record.java
+++ b/src/main/java/org/apache/bcel/classfile/Record.java
@@ -116,7 +116,7 @@ public final class Record extends Attribute {
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
- file.writeShort(components.length);
+ file.writeShort(Args.requireU2(components.length,
"components.length"));
for (final RecordComponentInfo component : components) {
component.dump(file);
}
diff --git a/src/main/java/org/apache/bcel/classfile/RecordComponentInfo.java
b/src/main/java/org/apache/bcel/classfile/RecordComponentInfo.java
index 6d6e5af0..e32e1ac7 100644
--- a/src/main/java/org/apache/bcel/classfile/RecordComponentInfo.java
+++ b/src/main/java/org/apache/bcel/classfile/RecordComponentInfo.java
@@ -23,6 +23,7 @@ import java.io.DataOutputStream;
import java.io.IOException;
import org.apache.bcel.Const;
+import org.apache.bcel.util.Args;
/**
* Record component info from a record. Instances from this class maps
@@ -71,7 +72,7 @@ public class RecordComponentInfo implements Node {
public void dump(final DataOutputStream file) throws IOException {
file.writeShort(index);
file.writeShort(descriptorIndex);
- file.writeShort(attributes.length);
+ file.writeShort(Args.requireU2(attributes.length,
"attributes.length"));
for (final Attribute attribute : attributes) {
attribute.dump(file);
}
diff --git a/src/main/java/org/apache/bcel/classfile/StackMap.java
b/src/main/java/org/apache/bcel/classfile/StackMap.java
index 60e9ce2c..72a435ce 100644
--- a/src/main/java/org/apache/bcel/classfile/StackMap.java
+++ b/src/main/java/org/apache/bcel/classfile/StackMap.java
@@ -113,7 +113,7 @@ public final class StackMap extends Attribute {
@Override
public void dump(final DataOutputStream file) throws IOException {
super.dump(file);
- file.writeShort(table.length);
+ file.writeShort(Args.requireU2(table.length, "table.length"));
for (final StackMapEntry entry : table) {
entry.dump(file);
}
diff --git a/src/main/java/org/apache/bcel/classfile/StackMapEntry.java
b/src/main/java/org/apache/bcel/classfile/StackMapEntry.java
index e6c77233..93b2fed8 100644
--- a/src/main/java/org/apache/bcel/classfile/StackMapEntry.java
+++ b/src/main/java/org/apache/bcel/classfile/StackMapEntry.java
@@ -25,6 +25,7 @@ import java.io.IOException;
import java.util.Arrays;
import org.apache.bcel.Const;
+import org.apache.bcel.util.Args;
/**
* This class represents a stack map entry recording the types of local
variables and the of stack items at a given
@@ -198,11 +199,11 @@ public final class StackMapEntry implements Node,
Cloneable {
}
} else if (frameType == Const.FULL_FRAME) {
file.writeShort(byteCodeOffset);
- file.writeShort(typesOfLocals.length);
+ file.writeShort(Args.requireU2(typesOfLocals.length,
"typesOfLocals.length"));
for (final StackMapType type : typesOfLocals) {
type.dump(file);
}
- file.writeShort(typesOfStackItems.length);
+ file.writeShort(Args.requireU2(typesOfStackItems.length,
"typesOfStackItems.length"));
for (final StackMapType type : typesOfStackItems) {
type.dump(file);
}
diff --git a/src/main/java/org/apache/bcel/generic/AnnotationEntryGen.java
b/src/main/java/org/apache/bcel/generic/AnnotationEntryGen.java
index e91b29e1..feeadc34 100644
--- a/src/main/java/org/apache/bcel/generic/AnnotationEntryGen.java
+++ b/src/main/java/org/apache/bcel/generic/AnnotationEntryGen.java
@@ -36,6 +36,7 @@ import org.apache.bcel.classfile.RuntimeInvisibleAnnotations;
import org.apache.bcel.classfile.RuntimeInvisibleParameterAnnotations;
import org.apache.bcel.classfile.RuntimeVisibleAnnotations;
import org.apache.bcel.classfile.RuntimeVisibleParameterAnnotations;
+import org.apache.bcel.util.Args;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.stream.Streams;
@@ -147,7 +148,7 @@ public class AnnotationEntryGen {
// Lets do the visible ones
final ByteArrayOutputStream rvaBytes = new ByteArrayOutputStream();
try (DataOutputStream rvaDos = new DataOutputStream(rvaBytes)) {
- rvaDos.writeByte(vec.length); // First goes number of
parameters
+ rvaDos.writeByte(Args.requireU1(vec.length, "vec.length")); //
First goes number of parameters
for (int i = 0; i < vec.length; i++) {
rvaDos.writeShort(visCount[i]);
if (visCount[i] > 0) {
@@ -162,7 +163,7 @@ public class AnnotationEntryGen {
// Lets do the invisible ones
final ByteArrayOutputStream riaBytes = new ByteArrayOutputStream();
try (DataOutputStream riaDos = new DataOutputStream(riaBytes)) {
- riaDos.writeByte(vec.length); // First goes number of
parameters
+ riaDos.writeByte(Args.requireU1(vec.length, "vec.length")); //
First goes number of parameters
for (int i = 0; i < vec.length; i++) {
riaDos.writeShort(invisCount[i]);
if (invisCount[i] > 0) {
@@ -294,7 +295,7 @@ public class AnnotationEntryGen {
*/
public void dump(final DataOutputStream dos) throws IOException {
dos.writeShort(typeIndex); // u2 index of type name in cpool
- dos.writeShort(evs.size()); // u2 element_value pair count
+ dos.writeShort(Args.requireU2(evs.size(), "evs.size()")); // u2
element_value pair count
for (final ElementValuePairGen envp : evs) {
envp.dump(dos);
}
diff --git a/src/main/java/org/apache/bcel/generic/ArrayElementValueGen.java
b/src/main/java/org/apache/bcel/generic/ArrayElementValueGen.java
index c78b7c34..773c41bb 100644
--- a/src/main/java/org/apache/bcel/generic/ArrayElementValueGen.java
+++ b/src/main/java/org/apache/bcel/generic/ArrayElementValueGen.java
@@ -26,6 +26,7 @@ import java.util.stream.Collectors;
import org.apache.bcel.classfile.ArrayElementValue;
import org.apache.bcel.classfile.ElementValue;
+import org.apache.bcel.util.Args;
import org.apache.commons.lang3.stream.Streams;
/**
@@ -91,7 +92,7 @@ public class ArrayElementValueGen extends ElementValueGen {
@Override
public void dump(final DataOutputStream dos) throws IOException {
dos.writeByte(super.getElementValueType()); // u1 type of value (ARRAY
== '[')
- dos.writeShort(evalues.size());
+ dos.writeShort(Args.requireU2(evalues.size(), "evalues.size()"));
for (final ElementValueGen element : evalues) {
element.dump(dos);
}
diff --git a/src/test/java/org/apache/bcel/classfile/DumpU2OverflowTest.java
b/src/test/java/org/apache/bcel/classfile/DumpU2OverflowTest.java
new file mode 100644
index 00000000..f9059ae8
--- /dev/null
+++ b/src/test/java/org/apache/bcel/classfile/DumpU2OverflowTest.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.bcel.classfile;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+
+import org.apache.bcel.Const;
+import org.apache.bcel.generic.ClassGen;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Writer paths must refuse to emit structure counts that overflow their u2/u1
class-file fields instead of silently truncating them
+ * (DataOutputStream.writeShort keeps only the low 16 bits) while still
writing every body; the CVE-2022-42920 corruption shape.
+ */
+class DumpU2OverflowTest {
+
+ @Test
+ void testDumpRefusesOverflowingInterfaceCount() throws Exception {
+ final JavaClass javaClass = new ClassGen("A", "java.lang.Object",
"A.java", Const.ACC_PUBLIC, null).getJavaClass();
+ javaClass.setInterfaces(new int[Const.MAX_SHORT + 1]);
+ try (DataOutputStream dos = new DataOutputStream(new
ByteArrayOutputStream())) {
+ assertThrows(ClassFormatException.class, () ->
javaClass.dump(dos));
+ }
+ }
+
+ @Test
+ void testSetExceptionTableRefusesOverflowingCount() {
+ final JavaClass javaClass = new ClassGen("A", "java.lang.Object",
"A.java", Const.ACC_PUBLIC, null).getJavaClass();
+ final Code code = new Code(0, 0, 0, 0, new byte[0], null, null,
javaClass.getConstantPool());
+ assertThrows(ClassFormatException.class, () ->
code.setExceptionTable(new CodeException[Const.MAX_SHORT + 1]));
+ }
+}