Commit message: Fix #9943 - Invalid free on RAnal.avr
CVE: CVE-2018-11383
CWE: CWE-416
Vulnerability description: The r_strbuf_fini() function in radare2 2.5.0 allows remote attackers to cause a denial of service (invalid free and application crash) via a crafted ELF file because of an uninitialized variable in the CPSE handler in libr/anal/p/anal_avr.c.

Project: radare2
File: anal_avr.c

INST_HANDLER (bld) {	// BLD Rd, b
	if (len < 2) {
		return;
	}
	int d = ((buf[1] & 0x01) << 4) | ((buf[0] >> 4) & 0xf);
	int b = buf[0] & 0x7;
	ESIL_A ("r%d,%d,1,<<,0xff,^,&,", d, b);			// Rd/b = 0
	ESIL_A ("%d,tf,<<,|,r%d,=,", b, d);			// Rd/b |= T<<b
}

Project: radare2

INST_HANDLER (brbx) {	// BRBC s, k
	int s = buf[0] & 0x7;
	op->jump = op->addr
		+ ((((buf[1] & 0x03) << 6) | ((buf[0] & 0xf8) >> 2))
			| (buf[1] & 0x2 ? ~((int) 0x7f) : 0))
		+ 2;
	op->fail = op->addr + op->size;
	op->cycles = 1;	// XXX: This is a bug, because depends on eval state,
	ESIL_A ("%d,1,<<,sreg,&,", s);				// SREG(s)
	ESIL_A (buf[1] & 0x4
			? "!,"		// BRBC => branch if cleared
			: "!,!,");	// BRBS => branch if set
	ESIL_A ("?{,%"PFMT64d",pc,=,},", op->jump);	// ?true => jmp
}

Project: radare2

INST_HANDLER (bset) {	// BSET s
	int s = (buf[0] >> 4) & 0x7;
	ESIL_A ("%d,1,<<,sreg,|=,", s);
}

Project: radare2

INST_HANDLER (eor) {	// EOR Rd, Rr
	int d = ((buf[0] >> 4) & 0xf) | ((buf[1] & 1) << 4);
	int r = (buf[0] & 0xf) | ((buf[1] & 2) << 3);
	ESIL_A ("r%d,r%d,^,", r, d);			// 0: Rd ^ Rr
	__generic_bitop_flags (op);			// up flags
	ESIL_A ("r%d,=,", d);				// Rd = Result
}

Project: radare2

INST_HANDLER (ldd) {	// LD Rd, Y	LD Rd, Z
	int offset = (buf[1] & 0x20)
			| ((buf[1] & 0xc) << 1)
			| (buf[0] & 0x7);
	__generic_ld_st (
		op, "ram",
		buf[0] & 0x8 ? 'y' : 'z',	// index register Y/Z
		0,				// no use RAMP* registers
		!(buf[1] & 0x10)
			? 0			// no increment
			: buf[0] & 0x1
				? 1		// post incremented
				: -1,		// pre decremented
		!(buf[1] & 0x10) ? offset : 0,	// offset or not offset
		0);				// load operation (!st)
	ESIL_A ("r%d,=,", ((buf[1] & 1) << 4) | ((buf[0] >> 4) & 0xf));
	op->cycles =
		(buf[1] & 0x10) == 0
			? (!offset ? 1 : 3)		// LDD
			: (buf[0] & 0x3) == 0
				? 1			// LD Rd, X
				: (buf[0] & 0x3) == 1
					? 2		// LD Rd, X+
					: 3;		// LD Rd, -X
	if (!STR_BEGINS (cpu->model, "ATxmega") && op->cycles > 1) {
		op->cycles--;
	}
}

Project: radare2

INST_HANDLER (lpm) {	// LPM
	ut16 ins = (((ut16) buf[1]) << 8) | ((ut16) buf[0]);
	__generic_ld_st (
		op, "prog",
		'z',				// index register Y/Z
		1,				// use RAMP* registers
		(ins & 0xfe0f) == 0x9005
			? 1			// post incremented
			: 0,			// no increment
		0,				// not offset
		0);				// load operation (!st)
	ESIL_A ("r%d,=,",
		(ins == 0x95c8)
			? 0			// LPM (r0)
			: ((buf[0] >> 4) & 0xf)	// LPM Rd
				| ((buf[1] & 0x1) << 4));
}

Project: radare2
File: anal_avr.c

INST_HANDLER (movw) {	// MOVW Rd+1:Rd, Rr+1:Rr
	int d = (buf[0] & 0xf0) >> 3;
	int r = (buf[0] & 0x0f) << 1;
	ESIL_A ("r%d,r%d,=,r%d,r%d,=,", r, d, r + 1, d + 1);
}

Project: radare2
File: anal_avr.c

INST_HANDLER (out) {	// OUT A, Rr
	int r = ((buf[0] >> 4) & 0x0f) | ((buf[1] & 0x01) << 4);
	int a = (buf[0] & 0x0f) | ((buf[1] & 0x6) << 3);
	RStrBuf *io_dst = __generic_io_dest (a, 1, cpu);
	op->type2 = 1;
	op->val = a;
	op->family = R_ANAL_OP_FAMILY_IO;
	ESIL_A ("r%d,%s,", r, r_strbuf_get (io_dst));
	r_strbuf_free (io_dst);
}

Project: radare2

INST_HANDLER (std) {	// ST Y, Rr	ST Z, Rr
	ESIL_A ("r%d,", ((buf[1] & 1) << 4) | ((buf[0] >> 4) & 0xf));
	__generic_ld_st (
		op, "ram",
		buf[0] & 0x8 ? 'y' : 'z',	// index register Y/Z
		0,				// no use RAMP* registers
		!(buf[1] & 0x10)
			? 0			// no increment
			: buf[0] & 0x1
				? 1		// post incremented
				: -1,		// pre decremented
		!(buf[1] & 0x10)
			? (buf[1] & 0x20)	// offset
			| ((buf[1] & 0xc) << 1)
			| (buf[0] & 0x7)
			: 0,			// no offset
		1);				// load operation (!st)
}

Project: radare2
File: anal_avr.c

static void __generic_add_update_flags_rr(RAnalOp *op, int d, int r) {
	__generic_add_update_flags(op, 'r', d, 'r', r);
}

Project: radare2
File: anal_avr.c

static void __generic_pop(RAnalOp *op, int sz) {
	if (sz > 1) {
		ESIL_A ("1,sp,+,_ram,+,");	// calc SRAM(sp+1)
		ESIL_A ("[%d],", sz);		// read value
		ESIL_A ("%d,sp,+=,", sz);	// sp += item_size
	} else {
		ESIL_A ("1,sp,+=,"		// increment stack pointer
			"sp,_ram,+,[1],");	// load SRAM[sp]
	}
}

Project: radare2
File: anal_avr.c

static int archinfo(RAnal *anal, int q) {
	if (q == R_ANAL_ARCHINFO_ALIGN)
		return 2;
	if (q == R_ANAL_ARCHINFO_MAX_OP_SIZE)
		return 4;
	if (q == R_ANAL_ARCHINFO_MIN_OP_SIZE)
		return 2;
	return 2; // XXX
}

Project: radare2

void _CbInRangeAav(RCore *core, ut64 from, ut64 to, int vsize, bool asterisk, int count) {
	bool isarm = archIsArmOrThumb (core);
	if (isarm) {
		if (to & 1) {
			to--;
			r_anal_hint_set_bits (core->anal, to, 16);
		} else {
			r_core_seek_archbits (core, from);
			ut64 bits = r_config_get_i (core->config, "asm.bits");
			r_anal_hint_set_bits (core->anal, from, bits);
		}
	} else {
		bool ismips = archIsMips (core);
		if (ismips) {
			if (from % 4 || to % 4) {
				eprintf ("False positive\n");
				return;
			}
		}
	}
	if (asterisk) {
		r_cons_printf ("ax 0x%"PFMT64x " 0x%"PFMT64x "\n", to, from);
		r_cons_printf ("Cd %d @ 0x%"PFMT64x "\n", vsize, from);
		r_cons_printf ("f+ aav.0x%08"PFMT64x "= 0x%08"PFMT64x, to, to);
	} else {
#if 1
		r_anal_ref_add (core->anal, to, from, ' ');
		r_meta_add (core->anal, 'd', from, from + vsize, NULL);
		if (!r_flag_get_at (core->flags, to, false)) {
			char *name = r_str_newf ("aav.0x%08"PFMT64x, to);
			r_flag_set (core->flags, name, to, vsize);
			free (name);
		}
#else
		r_core_cmdf (core, "ax 0x%"PFMT64x " 0x%"PFMT64x, to, from);
		r_core_cmdf (core, "Cd %d @ 0x%"PFMT64x, vsize, from);
		r_core_cmdf (core, "f+ aav.0x%08"PFMT64x "= 0x%08"PFMT64x, to, to);
#endif
	}
}