Commit message: None
CVE: CVE-2017-6415
CWE: CWE-476
Vulnerability description: The dex_parse_debug_item function in libr/bin/p/bin_dex.c in radare2 1.2.1 allows remote attackers to cause a denial of service (NULL pointer dereference and application crash) via a crafted DEX file.

Project: radare2
File: bin_dex.c

static int already_entry(RList *entries, ut64 vaddr) {
	RBinAddr *e;
	RListIter *iter;
	r_list_foreach (entries, iter, e) {
		if (e->vaddr == vaddr) {
			return 1;
		}
	}
	return 0;
}

Project: radare2

static int check_bytes(const ut8 *buf, ut64 length) {
	if (!buf || length < 8) {
		return false;
	}
	if (!memcmp (buf, "dex\n035\0", 8)) {
		return true;
	}
	if (!memcmp (buf, "dex\n036\0", 8)) {
		return true;
	}
	if (!memcmp (buf, "dex\n009\0", 8)) {
		return true;
	}
	if (!memcmp (buf, "dex\n009\0", 8)) {
		return true;
	}
	if (!memcmp (buf, "dex\n", 4)) {
		return true;
	}
	return false;
}

Project: radare2
File: bin_dex.c

static int countOnes(ut32 val) {
	int count = 0;
	val = val - ((val >> 1) & 0x55555555);
	val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
	count = (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
	return count;
}

Project: radare2

static char *dex_method_signature(RBinDexObj *bin, int method_idx) {
	ut32 proto_id, params_off, type_id, list_size;
	char *r, *return_type = NULL, *signature = NULL, *buff = NULL; 
	ut8 *bufptr;
	ut16 type_idx;
	int pos = 0, i, size = 1;

	if (method_idx < 0 || method_idx >= bin->header.method_size) {
		return NULL;
	}
	proto_id = bin->methods[method_idx].proto_id;
	if (proto_id >= bin->header.prototypes_size) {
		return NULL;
	}
	params_off = bin->protos[proto_id].parameters_off;
	if (params_off  >= bin->size) {
		return NULL;
	}
	type_id = bin->protos[proto_id].return_type_id;
	if (type_id >= bin->header.types_size ) {
		return NULL;
	}
	return_type = getstr (bin, bin->types[type_id].descriptor_id);
	if (!return_type) {
		return NULL;
	}
	if (!params_off) {
		return r_str_newf ("()%s", return_type);;
	}
	bufptr = bin->b->buf;
	list_size = r_read_le32 (bufptr + params_off); 
	for (i = 0; i < list_size; i++) {
		int buff_len = 0;
		if (params_off + 4 + (i * 2) >= bin->size) {
			break;
		}
		type_idx = r_read_le16 (bufptr + params_off + 4 + (i * 2));
		if (type_idx < 0 ||
		    type_idx >=
			    bin->header.types_size || type_idx >= bin->size) {
			break;
		}
		buff = getstr (bin, bin->types[type_idx].descriptor_id);
		if (!buff) {
			break;
		}
		buff_len = strlen (buff);
		size += buff_len + 1;
		signature = realloc (signature, size);
		strcpy (signature + pos, buff);
		pos += buff_len;
		signature[pos] = '\0';
	}
	r = r_str_newf ("(%s)%s", signature, return_type);
	free (buff);
	free (signature);
	return r;
}

Project: radare2

static RList *dex_method_signature2(RBinDexObj *bin, int method_idx) {
	ut32 proto_id, params_off, list_size;
	char *buff = NULL; 
	ut8 *bufptr;
	ut16 type_idx;
	int i;

	RList *params = r_list_newf (free);
	if (!params) {
		return NULL;
	}
	if (method_idx < 0 || method_idx >= bin->header.method_size) {
		goto out_error;
	}
	proto_id = bin->methods[method_idx].proto_id;
	if (proto_id >= bin->header.prototypes_size) {
		goto out_error;
	}
	params_off = bin->protos[proto_id].parameters_off;
	if (params_off  >= bin->size) {
		goto out_error;
	}
	if (!params_off) {
		return params;
	}
	bufptr = bin->b->buf;
	list_size = r_read_le32 (bufptr + params_off); 
	for (i = 0; i < list_size; i++) {
		ut64 of = params_off + 4 + (i * 2);
		if (of >= bin->size || of < params_off) {
			break;
		}
		type_idx = r_read_le16 (bufptr + of);
		if (type_idx >= bin->header.types_size ||
		    type_idx > bin->size) {
			break;
		}
		buff = getstr (bin, bin->types[type_idx].descriptor_id);
		if (!buff) {
			break;
		}
		r_list_append (params, buff);
	}
	return params;
out_error:
	r_list_free (params);
	return NULL;
}

Project: radare2

static void header(RBinFile *arch) {
	struct r_bin_dex_obj_t *bin = arch->o->bin_obj;
	struct r_bin_t *rbin = arch->rbin;

	rbin->cb_printf ("DEX file header:\n");
	rbin->cb_printf ("magic               : 'dex\\n035\\0'\n");
	rbin->cb_printf ("checksum            : %x\n", bin->header.checksum);
	rbin->cb_printf ("signature           : %02x%02x...%02x%02x\n", bin->header.signature[0], bin->header.signature[1], bin->header.signature[18], bin->header.signature[19]);
	rbin->cb_printf ("file_size           : %d\n", bin->header.size);
	rbin->cb_printf ("header_size         : %d\n", bin->header.header_size);
	rbin->cb_printf ("link_size           : %d\n", bin->header.linksection_size);
	rbin->cb_printf ("link_off            : %d (0x%06x)\n", bin->header.linksection_offset, bin->header.linksection_offset);
	rbin->cb_printf ("string_ids_size     : %d\n", bin->header.strings_size);
	rbin->cb_printf ("string_ids_off      : %d (0x%06x)\n", bin->header.strings_offset, bin->header.strings_offset);
	rbin->cb_printf ("type_ids_size       : %d\n", bin->header.types_size);
	rbin->cb_printf ("type_ids_off        : %d (0x%06x)\n", bin->header.types_offset, bin->header.types_offset);
	rbin->cb_printf ("proto_ids_size       : %d\n", bin->header.prototypes_size);
	rbin->cb_printf ("proto_ids_off        : %d (0x%06x)\n", bin->header.prototypes_offset, bin->header.prototypes_offset);
	rbin->cb_printf ("field_ids_size      : %d\n", bin->header.fields_size);
	rbin->cb_printf ("field_ids_off       : %d (0x%06x)\n", bin->header.fields_offset, bin->header.fields_offset);
	rbin->cb_printf ("method_ids_size     : %d\n", bin->header.method_size);
	rbin->cb_printf ("method_ids_off      : %d (0x%06x)\n", bin->header.method_offset, bin->header.method_offset);
	rbin->cb_printf ("class_defs_size     : %d\n", bin->header.class_size);
	rbin->cb_printf ("class_defs_off      : %d (0x%06x)\n", bin->header.class_offset, bin->header.class_offset);
	rbin->cb_printf ("data_size           : %d\n", bin->header.data_size);
	rbin->cb_printf ("data_off            : %d (0x%06x)\n\n", bin->header.data_offset, bin->header.data_offset);

	dexdump = true;
	bin->methods_list = NULL;
	dex_loadcode (arch, bin);
	dexdump = false;
}