Commit: Fix array overrun bugs in the S12Z disassembler

Message ID 87h83rnc78.fsf@redhat.com
State New
Headers show
Series
  • Commit: Fix array overrun bugs in the S12Z disassembler
Related show

Commit Message

Nick Clifton Oct. 29, 2019, 9:16 a.m.
Hi Guys,

  I am applying the patch below to fix several array overrun bugs in the
  S12Z when it is attempting to decode a corrupt S12Z binary.

Cheers
  Nick

opcodes/ChangeLog
2019-10-29  Nick Clifton  <nickc@redhat.com>

	* s12z-dis.c (opr_emit_disassembly): Check for illegal register
	values.
	(shift_size_table): Use a fixed size defined as S12Z_N_SIZES.
	(print_insn_s12z):  Check for illegal size values.

Patch

diff --git a/opcodes/s12z-dis.c b/opcodes/s12z-dis.c
index 6086f1635d..5930ab4ef6 100644
--- a/opcodes/s12z-dis.c
+++ b/opcodes/s12z-dis.c
@@ -25,13 +25,11 @@ 
 #include <assert.h>
 
 #include "opcode/s12z.h"
-
 #include "bfd.h"
 #include "dis-asm.h"
-
 #include "disassemble.h"
-
 #include "s12z-opc.h"
+#include "opintl.h"
 
 struct mem_read_abstraction
 {
@@ -255,7 +253,11 @@  opr_emit_disassembly (const struct operand *opr,
     case OPND_CL_REGISTER:
       {
         int r = ((struct register_operand*) opr)->reg;
-	(*info->fprintf_func) (info->stream, "%s", registers[r].name);
+
+	if (r < 0 || r >= S12Z_N_REGISTERS)
+	  (*info->fprintf_func) (info->stream, _("<illegal reg num>"));
+	else
+	  (*info->fprintf_func) (info->stream, "%s", registers[r].name);
       }
       break;
     case OPND_CL_REGISTER_ALL16:
@@ -306,14 +308,25 @@  opr_emit_disassembly (const struct operand *opr,
 	    break;
 	  }
 	if (mo->n_regs > 0)
-	  (*info->fprintf_func) (info->stream, fmt,
-				 registers[mo->regs[0]].name);
+	  {
+	    int r = mo->regs[0];
+
+	    if (r < 0 || r >= S12Z_N_REGISTERS)
+	      (*info->fprintf_func) (info->stream, fmt, _("<illegal reg num>"));
+	    else
+	      (*info->fprintf_func) (info->stream, fmt, registers[r].name);
+	  }
 	used_reg = 1;
 
         if (mo->n_regs > used_reg)
           {
-            (*info->fprintf_func) (info->stream, ",%s",
-				   registers[mo->regs[used_reg]].name);
+	    int r = mo->regs[used_reg];
+
+	    if (r < 0 || r >= S12Z_N_REGISTERS)
+	      (*info->fprintf_func) (info->stream, _("<illegal reg num>"));
+	    else
+	      (*info->fprintf_func) (info->stream, ",%s",
+				     registers[r].name);
           }
 
 	(*info->fprintf_func) (info->stream, "%c",
@@ -323,7 +336,9 @@  opr_emit_disassembly (const struct operand *opr,
     };
 }
 
-static const char shift_size_table[] = {
+#define S12Z_N_SIZES 4
+static const char shift_size_table[S12Z_N_SIZES] =
+{
   'b', 'w', 'p', 'l'
 };
 
@@ -357,6 +372,7 @@  print_insn_s12z (bfd_vma memaddr, struct disassemble_info* info)
   if (osize == -1)
     {
       bool suffix = false;
+
       for (o = 0; o < n_operands; ++o)
 	{
 	  if (operands[o] && operands[o]->osize != -1)
@@ -366,18 +382,27 @@  print_insn_s12z (bfd_vma memaddr, struct disassemble_info* info)
 		  (*mra.info->fprintf_func) (mra.info->stream, "%c", '.');
 		  suffix = true;
 		}
-	      (*mra.info->fprintf_func) (mra.info->stream, "%c",
-				     shift_size_table[operands[o]->osize]);
+
+	      osize = operands[o]->osize;
+
+	      if (osize < 0 || osize >= S12Z_N_SIZES)
+		(*mra.info->fprintf_func) (mra.info->stream, _("<bad>"));
+	      else
+		(*mra.info->fprintf_func) (mra.info->stream, "%c",
+					   shift_size_table[osize]);
+		
 	    }
 	}
     }
   else
     {
-      (*mra.info->fprintf_func) (mra.info->stream, ".%c",
-			     shift_size_table[osize]);
+      if (osize < 0 || osize >= S12Z_N_SIZES)
+	(*mra.info->fprintf_func) (mra.info->stream, _(".<bad>"));
+      else
+	(*mra.info->fprintf_func) (mra.info->stream, ".%c",
+				   shift_size_table[osize]);
     }
 
-
   /* Ship out the operands.  */
   for (o = 0; o < n_operands; ++o)
     {
diff --git a/opcodes/s12z-opc.c b/opcodes/s12z-opc.c
index eef097dfd4..e7a3577ef7 100644
--- a/opcodes/s12z-opc.c
+++ b/opcodes/s12z-opc.c
@@ -2205,8 +2205,16 @@  exg_sex_discrim (struct mem_read_abstraction_base *mra, enum optr hint ATTRIBUTE
   struct operand *op0 = create_register_operand ((eb & 0xf0) >> 4);
   struct operand *op1 = create_register_operand (eb & 0xf);
 
-  const struct reg *r0 = registers + ((struct register_operand *) op0)->reg;
-  const struct reg *r1 = registers + ((struct register_operand *) op1)->reg;
+  int reg0 = ((struct register_operand *) op0)->reg;
+  if (reg0 < 0 || reg0 >= S12Z_N_REGISTERS)
+    return OP_INVALID;
+
+  int reg1 = ((struct register_operand *) op1)->reg;
+  if (reg1 < 0 || reg1 >= S12Z_N_REGISTERS)
+    return OP_INVALID;
+
+  const struct reg *r0 = registers + reg0;
+  const struct reg *r1 = registers + reg1;
 
   enum optr operator = (r0->bytes < r1->bytes) ? OP_sex : OP_exg;