CVE-2022-36044 (published 2022-09-06T20:15Z)

Rizin is a UNIX-like reverse engineering framework and command-line toolset. Versions 0.4.0 and prior are vulnerable to an out-of-bounds write when getting data from Luac files. A user opening a malicious Luac file could be affected by this vulnerability, allowing an attacker to execute code on the user's machine. Commits 07b43bc8aa1ffebd9b68d60624c9610cf7e460c7 and 05bbd147caccc60162d6fba9baaaf24befa281cd contain fixes for the issue.

CVSS v3 base score: 7.8, HIGH (CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-787
cwe_name: Out-of-bounds Write
description: The product writes data past the end, or before the beginning, of the intended buffer.
extended_description: 
            
            
             
			 
         
         

Fix information:
repo_url: https://github.com/rizinorg/rizin
commit_details: repo_url: https://github.com/rizinorg/rizin
author: wargio
author_date: 2022-08-19 23:01:10+02:00
msg: fix oob read on luac
repository: repo_url: https://github.com/rizinorg/rizin
repo_name: rizinorg/rizin
description: UNIX-like reverse engineering framework and command-line toolset.
repo_language: C
owner: rizinorg
file_changes: filename: bobj.c
change_type: ModificationType.MODIFY
diff: @@ -244,7 +244,7 @@ static RzList *classes_from_symbols(RzBinFile *bf) {
 	RzBinSymbol *sym;
 	RzListIter *iter;
 	rz_list_foreach (bf->o->symbols, iter, sym) {
-		if (sym->name[0] != '_') {
+		if (!sym->name || sym->name[0] != '_') {
 			continue;
 		}
 		const char *cn = sym->classname;

programming_language: C
filename: luac_bin.c
change_type: ModificationType.MODIFY
diff: @@ -303,7 +303,7 @@ void _luac_build_info(LuaProto *proto, LuacBinInfo *info) {
 	}
 
 	// 2.2 parse debug_upvalues
-	size_t real_upvalue_cnt = rz_list_length(proto->upvalue_entries);
+	size_t real_upvalue_cnt = RZ_MAX(rz_list_length(proto->upvalue_entries), rz_list_length(proto->dbg_upvalue_entries));
 	if (real_upvalue_cnt > 0) {
 		LuaDbgUpvalueEntry *debug_upv_entry;
 		upvalue_names = RZ_NEWS0(char *, real_upvalue_cnt);
@@ -328,6 +328,9 @@ void _luac_build_info(LuaProto *proto, LuacBinInfo *info) {
 	LuaConstEntry *const_entry;
 	rz_list_foreach (proto->const_entries, iter, const_entry) {
 		symbol_name = get_constant_symbol_name(proto_name, const_entry);
+		if (!symbol_name) {
+			continue;
+		}
 		luac_add_symbol(
 			info->symbol_list,
 			symbol_name,

programming_language: C
repo_url: https://github.com/rizinorg/rizin
commit_details: repo_url: https://github.com/rizinorg/rizin
author: wargio
author_date: 2022-08-17 14:29:37+02:00
msg: Fix oob read on _luac_build_info and luac memleaks
repository: repo_url: https://github.com/rizinorg/rizin
repo_name: rizinorg/rizin
description: UNIX-like reverse engineering framework and command-line toolset.
repo_language: C
owner: rizinorg
file_changes: filename: luac_bin.c
change_type: ModificationType.MODIFY
diff: @@ -70,12 +70,6 @@ void luac_add_string(RzList *string_list, char *string, ut64 offset, ut64 size)
 	rz_list_append(string_list, bin_string);
 }
 
-static void try_free_empty_list(RzList *list) {
-	if (list != NULL) {
-		rz_list_free(list);
-	}
-}
-
 static void free_rz_section(RzBinSection *section) {
 	if (!section) {
 		return;
@@ -111,6 +105,17 @@ static void free_rz_addr(RzBinAddr *addr) {
 	RZ_FREE(addr);
 }
 
+void luac_build_info_free(LuacBinInfo *bin_info) {
+	if (!bin_info) {
+		return;
+	}
+	rz_list_free(bin_info->entry_list);
+	rz_list_free(bin_info->symbol_list);
+	rz_list_free(bin_info->section_list);
+	rz_list_free(bin_info->string_list);
+	free(bin_info);
+}
+
 LuacBinInfo *luac_build_info(LuaProto *proto) {
 	if (!proto) {
 		RZ_LOG_ERROR("Invalid luac file\n");
@@ -128,10 +133,10 @@ LuacBinInfo *luac_build_info(LuaProto *proto) {
 	ret->string_list = rz_list_newf((RzListFree)free_rz_string);
 
 	if (!(ret->entry_list && ret->symbol_list && ret->section_list && ret->string_list)) {
-		try_free_empty_list(ret->entry_list);
-		try_free_empty_list(ret->symbol_list);
-		try_free_empty_list(ret->section_list);
-		try_free_empty_list(ret->string_list);
+		rz_list_free(ret->entry_list);
+		rz_list_free(ret->symbol_list);
+		rz_list_free(ret->section_list);
+		rz_list_free(ret->string_list);
 	}
 
 	_luac_build_info(proto, ret);
@@ -227,13 +232,13 @@ void _luac_build_info(LuaProto *proto, LuacBinInfo *info) {
 	char *section_name;
 	char *symbol_name;
 	char *proto_name;
+	char **upvalue_names = NULL;
 	RzListIter *iter;
+	int i = 0; // iter
 
 	ut64 current_offset;
 	ut64 current_size;
 
-	int i = 0; // iter
-
 	// 0. check if stripped (proto name is lost)
 	if (proto->name_size == 0 || proto->proto_name == NULL) {
 		// replace name with current offset
@@ -295,21 +300,25 @@ void _luac_build_info(LuaProto *proto, LuacBinInfo *info) {
 	}
 
 	// 2.2 parse debug_upvalues
-	char **upvalue_names;
-	int real_upvalue_cnt;
-	LuaDbgUpvalueEntry *debug_upv_entry;
-	real_upvalue_cnt = rz_list_length(proto->upvalue_entries);
-	upvalue_names = RZ_NEWS0(char *, real_upvalue_cnt);
-	if (!upvalue_names) {
-		return;
-	}
-	rz_list_foreach (proto->dbg_upvalue_entries, iter, debug_upv_entry) {
-		upvalue_names[i] = (char *)debug_upv_entry->upvalue_name;
-		luac_add_string(
-			info->string_list,
-			upvalue_names[i],
-			debug_upv_entry->offset,
-			debug_upv_entry->name_len);
+	size_t real_upvalue_cnt = rz_list_length(proto->upvalue_entries);
+	if (real_upvalue_cnt > 0) {
+		LuaDbgUpvalueEntry *debug_upv_entry;
+		upvalue_names = RZ_NEWS0(char *, real_upvalue_cnt);
+		if (!upvalue_names) {
+			free(proto_name);
+			return;
+		}
+
+		i = 0;
+		rz_list_foreach (proto->dbg_upvalue_entries, iter, debug_upv_entry) {
+			upvalue_names[i] = (char *)debug_upv_entry->upvalue_name;
+			luac_add_string(
+				info->string_list,
+				upvalue_names[i],
+				debug_upv_entry->offset,
+				debug_upv_entry->name_len);
+			i++;
+		}
 	}
 
 	// 3.1 construct constant symbols
@@ -352,5 +361,6 @@ void _luac_build_info(LuaProto *proto, LuacBinInfo *info) {
 		_luac_build_info(sub_proto, info);
 	}
 
-	RZ_FREE(proto_name);
+	free(upvalue_names);
+	free(proto_name);
 }

programming_language: C
filename: luac_common.h
change_type: ModificationType.MODIFY
diff: @@ -193,6 +193,7 @@ void luac_add_entry(RzList *entry_list, ut64 offset, int entry_type);
 void luac_add_string(RzList *string_list, char *string, ut64 offset, ut64 size);
 
 LuacBinInfo *luac_build_info(LuaProto *proto);
+void luac_build_info_free(LuacBinInfo *bin_info);
 void _luac_build_info(LuaProto *proto, LuacBinInfo *info);
 
 /* ========================================================

programming_language: C
filename: bin_luac.c
change_type: ModificationType.MODIFY
diff: @@ -100,7 +100,7 @@ static RzList *symbols(RzBinFile *bf) {
 		return NULL;
 	}
 
-	return bin_info_obj->symbol_list;
+	return rz_list_clone(bin_info_obj->symbol_list);
 }
 
 static RzList *entries(RzBinFile *bf) {
@@ -112,7 +112,7 @@ static RzList *entries(RzBinFile *bf) {
 		return NULL;
 	}
 
-	return bin_info_obj->entry_list;
+	return rz_list_clone(bin_info_obj->entry_list);
 }
 
 static RzList *strings(RzBinFile *bf) {
@@ -124,7 +124,12 @@ static RzList *strings(RzBinFile *bf) {
 		return NULL;
 	}
 
-	return bin_info_obj->string_list;
+	return rz_list_clone(bin_info_obj->string_list);
+}
+
+static void destroy(RzBinFile *bf) {
+	LuacBinInfo *bin_info_obj = GET_INTERNAL_BIN_INFO_OBJ(bf);
+	luac_build_info_free(bin_info_obj);
 }
 
 RzBinPlugin rz_bin_plugin_luac = {
@@ -133,6 +138,7 @@ RzBinPlugin rz_bin_plugin_luac = {
 	.license = "LGPL3",
 	.get_sdb = NULL,
 	.load_buffer = &load_buffer,
+	.destroy = &destroy,
 	.check_buffer = &check_buffer,
 	.baddr = NULL,
 	.entries = &entries,

programming_language: C