CVE-2022-0521: Improper Restriction of Operations within the Bounds of a Memory Buffer (CWE-119)
value: Access of Memory Location After End of Buffer in GitHub repository radareorg/radare2 prior to 5.6.2.
CWE description: The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
CVSS v3 base score: 7.1
Published: 2022-02-08T21:15Z
Repository: https://github.com/radareorg/radare2
Language: C
Files changed: shlr/java/class.c
Commit date: 2022-02-08 15:03:16 +0100
Commit message: Improve boundary checks to fix oobread segfaults ##crash

* Reported by Cen Zhang via huntr.dev
* Reproducer: bins/fuzzed/javaoob-havoc.class

Diff: diff --git a/shlr/java/class.c b/shlr/java/class.c
index 68e0dbd825d..02d2e6c6ebf 100644
--- a/shlr/java/class.c
+++ b/shlr/java/class.c
@@ -3625,10 +3625,13 @@ R_API ut64 r_bin_java_signature_attr_calc_size(RBinJavaAttrInfo *attr) {
 	return size;
 }
 
 R_API RBinJavaAttrInfo *r_bin_java_enclosing_methods_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
 	ut64 offset = 6;
+	if (sz < 8) {
+		return NULL;
+	}
 	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
 	if (!attr || sz < 10) {
 		free (attr);
 		return NULL;
 	}
@@ -3713,31 +3716,28 @@ R_API ut64 r_bin_java_exceptions_attr_calc_size(RBinJavaAttrInfo *attr) {
 	return size;
 }
 
 R_API RBinJavaAttrInfo *r_bin_java_inner_classes_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
 	RBinJavaClassesAttribute *icattr;
-	RBinJavaAttrInfo *attr = NULL;
 	RBinJavaCPTypeObj *obj;
 	ut32 i = 0;
 	ut64 offset = 0, curpos;
-	attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
-	offset += 6;
-	if (buf_offset + offset + 8 > sz) {
-		eprintf ("Invalid amount of inner classes\n");
+	if (sz < 8) {
 		return NULL;
 	}
-	if (attr == NULL) {
-		// TODO eprintf
-		return attr;
+	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
+	if (!attr) {
+		return NULL;
 	}
+	offset += 6;
 	attr->type = R_BIN_JAVA_ATTR_TYPE_INNER_CLASSES_ATTR;
 	attr->info.inner_classes_attr.number_of_classes = R_BIN_JAVA_USHORT (buffer, offset);
 	offset += 2;
 	attr->info.inner_classes_attr.classes = r_list_newf (r_bin_java_inner_classes_attr_entry_free);
 	for (i = 0; i < attr->info.inner_classes_attr.number_of_classes; i++) {
 		curpos = buf_offset + offset;
-		if (buf_offset + offset + 8 > sz) {
+		if (offset + 8 > sz) {
 			eprintf ("Invalid amount of inner classes\n");
 			break;
 		}
 		icattr = R_NEW0 (RBinJavaClassesAttribute);
 		if (!icattr) {
@@ -3871,10 +3871,13 @@ R_API ut64 r_bin_java_line_number_table_attr_calc_size(RBinJavaAttrInfo *attr) {
 	return size;
 }
 
 R_API RBinJavaAttrInfo *r_bin_java_source_debug_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
 	ut64 offset = 6;
+	if (sz < 8) {
+		return NULL;
+	}
 	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
 	if (!attr) {
 		return NULL;
 	}
 	attr->type = R_BIN_JAVA_ATTR_TYPE_SOURCE_DEBUG_EXTENTSION_ATTR;
@@ -3938,16 +3941,15 @@ R_API ut64 r_bin_java_local_variable_table_attr_calc_size(RBinJavaAttrInfo *attr
 }
 
 R_API RBinJavaAttrInfo *r_bin_java_local_variable_table_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
 	RBinJavaLocalVariableAttribute *lvattr;
 	ut64 curpos = 0, offset = 6;
-	RBinJavaAttrInfo *attr;
 	ut32 i = 0;
-	if (!buffer || sz < 1) {
+	if (!bin || !buffer || sz < 8) {
 		return NULL;
 	}
-	attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
+	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
 	if (!attr) {
 		return NULL;
 	}
 	attr->type = R_BIN_JAVA_ATTR_TYPE_LOCAL_VARIABLE_TABLE_ATTR;
 	attr->info.local_variable_table_attr.table_length = R_BIN_JAVA_USHORT (buffer, offset);
@@ -4017,10 +4019,13 @@ R_API ut64 r_bin_java_local_variable_type_table_attr_calc_size(RBinJavaAttrInfo
 	}
 	return size;
 }
 
 R_API RBinJavaAttrInfo *r_bin_java_local_variable_type_table_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
+	if (sz < 8) {
+		return NULL;
+	}
 	RBinJavaLocalVariableTypeAttribute *lvattr;
 	ut64 offset = 6;
 	ut32 i = 0;
 	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, 0);
 	if (!attr) {
@@ -4070,41 +4075,46 @@ R_API RBinJavaAttrInfo *r_bin_java_local_variable_type_table_attr_new(RBinJavaOb
 	attr->size = offset;
 	return attr;
 }
 
 R_API RBinJavaAttrInfo *r_bin_java_source_code_file_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
-	if (!sz) {
+	if (!sz || sz == UT64_MAX) {
+		return NULL;
+	}
+#if 0
+	/// XXX this breaks tests
+	if (sz < 8) {
 		return NULL;
 	}
+#endif
 	ut64 offset = 0;
 	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
 	offset += 6;
-	if (!attr) {
-		return NULL;
+	if (attr) {
+		attr->type = R_BIN_JAVA_ATTR_TYPE_SOURCE_FILE_ATTR;
+		attr->info.source_file_attr.sourcefile_idx = R_BIN_JAVA_USHORT (buffer, offset);
+		offset += 2;
+		attr->size = offset;
+		// IFDBG r_bin_java_print_source_code_file_attr_summary(attr);
 	}
-	attr->type = R_BIN_JAVA_ATTR_TYPE_SOURCE_FILE_ATTR;
-	// if (buffer + offset > buffer + sz) return NULL;
-	attr->info.source_file_attr.sourcefile_idx = R_BIN_JAVA_USHORT (buffer, offset);
-	offset += 2;
-	attr->size = offset;
-	// IFDBG r_bin_java_print_source_code_file_attr_summary(attr);
 	return attr;
 }
 
 R_API ut64 r_bin_java_source_code_file_attr_calc_size(RBinJavaAttrInfo *attr) {
 	return attr ? 8 : 0;
 }
 
 R_API RBinJavaAttrInfo *r_bin_java_synthetic_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
-	ut64 offset = 0;
+	if (sz < 8) {
+		return NULL;
+	}
 	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
 	if (!attr) {
 		return NULL;
 	}
-	offset += 6;
 	attr->type = R_BIN_JAVA_ATTR_TYPE_SYNTHETIC_ATTR;
-	attr->size = offset;
+	attr->size = 6;
 	return attr;
 }
 
 R_API ut64 r_bin_java_synthetic_attr_calc_size(RBinJavaAttrInfo *attr) {
 	return attr ? 12 : 6;
@@ -4131,28 +4141,25 @@ R_API RBinJavaInterfaceInfo *r_bin_java_interface_new(RBinJavaObj *bin, const ut
 	return ifobj;
 }
 
 R_API RBinJavaVerificationObj *r_bin_java_verification_info_from_type(RBinJavaObj *bin, R_BIN_JAVA_STACKMAP_TYPE type, ut32 value) {
 	RBinJavaVerificationObj *se = R_NEW0 (RBinJavaVerificationObj);
-	if (!se) {
-		return NULL;
-	}
-	se->tag = type;
-	if (se->tag == R_BIN_JAVA_STACKMAP_OBJECT) {
-		se->info.obj_val_cp_idx = (ut16) value;
-	} else if (se->tag == R_BIN_JAVA_STACKMAP_UNINIT) {
-		/*if (bin->offset_sz == 4) {
-		se->info.uninit_offset = value;
-		} else {
-		se->info.uninit_offset = (ut16) value;
-		}*/
-		se->info.uninit_offset = (ut16) value;
+	if (se) {
+		se->tag = type;
+		if (se->tag == R_BIN_JAVA_STACKMAP_OBJECT) {
+			se->info.obj_val_cp_idx = (ut16) value;
+		} else if (se->tag == R_BIN_JAVA_STACKMAP_UNINIT) {
+			se->info.uninit_offset = (ut16) value;
+		}
 	}
 	return se;
 }
 
 R_API RBinJavaVerificationObj *r_bin_java_read_from_buffer_verification_info_new(ut8 *buffer, ut64 sz, ut64 buf_offset) {
+	if (sz < 8) {
+		return NULL;
+	}
 	ut64 offset = 0;
 	RBinJavaVerificationObj *se = R_NEW0 (RBinJavaVerificationObj);
 	if (!se) {
 		return NULL;
 	}
@@ -4268,10 +4275,13 @@ R_API ut64 r_bin_java_stack_map_frame_calc_size(RBinJavaStackMapFrame *sf) {
 	}
 	return size;
 }
 
 R_API RBinJavaStackMapFrame *r_bin_java_stack_map_frame_new(ut8 *buffer, ut64 sz, RBinJavaStackMapFrame *p_frame, ut64 buf_offset) {
+	if (sz < 8) {
+		return NULL;
+	}
 	RBinJavaStackMapFrame *stack_frame = r_bin_java_default_stack_frame ();
 	RBinJavaVerificationObj *se = NULL;
 	ut64 offset = 0;
 	if (!stack_frame) {
 		return NULL;
@@ -4571,17 +4581,20 @@ R_API ut64 r_bin_java_stack_map_table_attr_calc_size(RBinJavaAttrInfo *attr) {
 }
 
 R_API RBinJavaAttrInfo *r_bin_java_stack_map_table_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
 	ut32 i = 0;
 	ut64 offset = 0;
+	if (sz < 8) {
+		return NULL;
+	}
 	RBinJavaStackMapFrame *stack_frame = NULL, *new_stack_frame = NULL;
 	if (sz < 10) {
 		return NULL;
 	}
 	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
 	offset += 6;
-	IFDBG eprintf("r_bin_java_stack_map_table_attr_new: New stack map allocated.\n");
+	IFDBG eprintf ("r_bin_java_stack_map_table_attr_new: New stack map allocated.\n");
 	if (!attr) {
 		return NULL;
 	}
 	attr->info.stack_map_table_attr.stack_map_frame_entries = r_list_newf (r_bin_java_stack_frame_free);
 	// IFDBG r_bin_java_print_source_code_file_attr_summary(attr);
@@ -6352,12 +6365,14 @@ R_API ut64 r_bin_java_annotation_default_attr_calc_size(RBinJavaAttrInfo *attr)
 	return size;
 }
 
 R_API RBinJavaAttrInfo *r_bin_java_annotation_default_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
 	ut64 offset = 0;
-	RBinJavaAttrInfo *attr = NULL;
-	attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
+	if (sz < 8) {
+		return NULL;
+	}
+	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
 	offset += 6;
 	if (attr && sz >= offset) {
 		attr->type = R_BIN_JAVA_ATTR_TYPE_ANNOTATION_DEFAULT_ATTR;
 		attr->info.annotation_default_attr.default_value = r_bin_java_element_value_new (buffer + offset, sz - offset, buf_offset + offset);
 		if (attr->info.annotation_default_attr.default_value) {
@@ -6433,14 +6448,16 @@ R_API void r_bin_java_annotation_default_attr_free(void /*RBinJavaAttrInfo*/ *a)
 	}
 }
 
 R_API RBinJavaAnnotation *r_bin_java_annotation_new(ut8 *buffer, ut64 sz, ut64 buf_offset) {
 	ut32 i = 0;
-	RBinJavaAnnotation *annotation = NULL;
 	RBinJavaElementValuePair *evps = NULL;
 	ut64 offset = 0;
-	annotation = R_NEW0 (RBinJavaAnnotation);
+	if (sz < 8) {
+		return NULL;
+	}
+	RBinJavaAnnotation *annotation = R_NEW0 (RBinJavaAnnotation);
 	if (!annotation) {
 		return NULL;
 	}
 	// (ut16) read and set annotation_value.type_idx;
 	annotation->type_idx = R_BIN_JAVA_USHORT (buffer, offset);
@@ -6508,18 +6525,14 @@ R_API void r_bin_java_print_annotation_summary(RBinJavaAnnotation *annotation) {
 		}
 	}
 }
 
 R_API ut64 r_bin_java_element_pair_calc_size(RBinJavaElementValuePair *evp) {
-	ut64 sz = 0;
-	if (evp == NULL) {
-		return sz;
-	}
-	// evp->element_name_idx = r_bin_java_read_short(bin, bin->b->cur);
-	sz += 2;
-	// evp->value = r_bin_java_element_value_new (bin, offset+2);
-	if (evp->value) {
+	ut64 sz = 2;
+	if (evp && evp->value) {
+		// evp->element_name_idx = r_bin_java_read_short(bin, bin->b->cur);
+		// evp->value = r_bin_java_element_value_new (bin, offset+2);
 		sz += r_bin_java_element_value_calc_size (evp->value);
 	}
 	return sz;
 }
 
@@ -6594,10 +6607,13 @@ R_API ut64 r_bin_java_element_value_calc_size(RBinJavaElementValue *element_valu
 }
 
 R_API RBinJavaElementValue *r_bin_java_element_value_new(ut8 *buffer, ut64 sz, ut64 buf_offset) {
 	ut32 i = 0;
 	ut64 offset = 0;
+	if (sz < 8) {
+		return NULL;
+	}
 	RBinJavaElementValue *element_value = R_NEW0 (RBinJavaElementValue);
 	if (!element_value) {
 		return NULL;
 	}
 	RBinJavaElementValuePair *evps = NULL;
@@ -7009,11 +7025,11 @@ R_API RBinJavaAnnotationsArray *r_bin_java_annotation_array_new(ut8 *buffer, ut6
 }
 
 R_API RBinJavaAttrInfo *r_bin_java_rtv_annotations_attr_new(RBinJavaObj *bin, ut8 *buffer, ut64 sz, ut64 buf_offset) {
 	ut32 i = 0;
 	ut64 offset = 0;
-	if (buf_offset + 8 > sz) {
+	if (sz < 8) {
 		return NULL;
 	}
 	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
 	offset += 6;
 	if (attr) {

Vulnerable code: 	RBinJavaAttrInfo *attr = NULL;
	attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
	offset += 6;
	if (buf_offset + offset + 8 > sz) {
		eprintf ("Invalid amount of inner classes\n");
	if (attr == NULL) {
		// TODO eprintf
		return attr;
		if (buf_offset + offset + 8 > sz) {
	RBinJavaAttrInfo *attr;
	if (!buffer || sz < 1) {
	attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
	if (!sz) {
	if (!attr) {
		return NULL;
	attr->type = R_BIN_JAVA_ATTR_TYPE_SOURCE_FILE_ATTR;
	// if (buffer + offset > buffer + sz) return NULL;
	attr->info.source_file_attr.sourcefile_idx = R_BIN_JAVA_USHORT (buffer, offset);
	offset += 2;
	attr->size = offset;
	// IFDBG r_bin_java_print_source_code_file_attr_summary(attr);
	ut64 offset = 0;
	offset += 6;
	attr->size = offset;
	if (!se) {
		return NULL;
	}
	se->tag = type;
	if (se->tag == R_BIN_JAVA_STACKMAP_OBJECT) {
		se->info.obj_val_cp_idx = (ut16) value;
	} else if (se->tag == R_BIN_JAVA_STACKMAP_UNINIT) {
		/*if (bin->offset_sz == 4) {
		se->info.uninit_offset = value;
		} else {
		se->info.uninit_offset = (ut16) value;
		}*/
		se->info.uninit_offset = (ut16) value;
	IFDBG eprintf("r_bin_java_stack_map_table_attr_new: New stack map allocated.\n");
	RBinJavaAttrInfo *attr = NULL;
	attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
	RBinJavaAnnotation *annotation = NULL;
	annotation = R_NEW0 (RBinJavaAnnotation);
	ut64 sz = 0;
	if (evp == NULL) {
		return sz;
	}
	// evp->element_name_idx = r_bin_java_read_short(bin, bin->b->cur);
	sz += 2;
	// evp->value = r_bin_java_element_value_new (bin, offset+2);
	if (evp->value) {
	if (buf_offset + 8 > sz) {
Fixed code: 	if (sz < 8) {
		return NULL;
	}
	if (sz < 8) {
	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
	if (!attr) {
		return NULL;
	offset += 6;
		if (offset + 8 > sz) {
	if (sz < 8) {
		return NULL;
	}
	if (!bin || !buffer || sz < 8) {
	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
	if (sz < 8) {
		return NULL;
	}
	if (!sz || sz == UT64_MAX) {
		return NULL;
	}
#if 0
	/// XXX this breaks tests
	if (sz < 8) {
#endif
	if (attr) {
		attr->type = R_BIN_JAVA_ATTR_TYPE_SOURCE_FILE_ATTR;
		attr->info.source_file_attr.sourcefile_idx = R_BIN_JAVA_USHORT (buffer, offset);
		offset += 2;
		attr->size = offset;
		// IFDBG r_bin_java_print_source_code_file_attr_summary(attr);
	if (sz < 8) {
		return NULL;
	}
	attr->size = 6;
	if (se) {
		se->tag = type;
		if (se->tag == R_BIN_JAVA_STACKMAP_OBJECT) {
			se->info.obj_val_cp_idx = (ut16) value;
		} else if (se->tag == R_BIN_JAVA_STACKMAP_UNINIT) {
			se->info.uninit_offset = (ut16) value;
		}
	if (sz < 8) {
		return NULL;
	}
	if (sz < 8) {
		return NULL;
	}
	if (sz < 8) {
		return NULL;
	}
	IFDBG eprintf ("r_bin_java_stack_map_table_attr_new: New stack map allocated.\n");
	if (sz < 8) {
		return NULL;
	}
	RBinJavaAttrInfo *attr = r_bin_java_default_attr_new (bin, buffer, sz, buf_offset);
	if (sz < 8) {
		return NULL;
	}
	RBinJavaAnnotation *annotation = R_NEW0 (RBinJavaAnnotation);
	ut64 sz = 2;
	if (evp && evp->value) {
		// evp->element_name_idx = r_bin_java_read_short(bin, bin->b->cur);
		// evp->value = r_bin_java_element_value_new (bin, offset+2);
	if (sz < 8) {
		return NULL;
	}
	if (sz < 8) {