Some CFA ops don't take any arguments, for those it is valid to be at the
end of the data block.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
src/ChangeLog | 5 +++++
src/readelf.c | 42 ++++++++++++++++++++++++++++++++++++++++--
2 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/src/ChangeLog b/src/ChangeLog
index 7960496..e39fc3e 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
+2014-12-17 Mark Wielaard <mjw(a)redhat.com>
+
+ * readelf.c (print_cfa_program): Add bounds check before each op that
+ takes at least one argument.
+
2014-12-16 Mark Wielaard <mjw(a)redhat.com>
* readelf.c (print_debug_line_section): Correct overflow check for
diff --git a/src/readelf.c b/src/readelf.c
index 9c62853..b3eaccb 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -4971,11 +4971,15 @@ print_cfa_program (const unsigned char *readp, const unsigned char
*const endp,
puts (" nop");
break;
case DW_CFA_set_loc:
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_uleb128 (op1, readp, endp);
op1 += vma_base;
printf (" set_loc %" PRIu64 "\n", op1 * code_align);
break;
case DW_CFA_advance_loc1:
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
printf (" advance_loc1 %u to %#" PRIx64 "\n",
*readp, pc += *readp * code_align);
++readp;
@@ -4995,6 +4999,8 @@ print_cfa_program (const unsigned char *readp, const unsigned char
*const endp,
op1, pc += op1 * code_align);
break;
case DW_CFA_offset_extended:
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_uleb128 (op1, readp, endp);
if ((uint64_t) (endp - readp) < 1)
goto invalid;
@@ -5004,19 +5010,27 @@ print_cfa_program (const unsigned char *readp, const unsigned char
*const endp,
op1, regname (op1), op2 * data_align);
break;
case DW_CFA_restore_extended:
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_uleb128 (op1, readp, endp);
printf (" restore_extended r%" PRIu64 " (%s)\n",
op1, regname (op1));
break;
case DW_CFA_undefined:
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_uleb128 (op1, readp, endp);
printf (" undefined r%" PRIu64 " (%s)\n", op1, regname
(op1));
break;
case DW_CFA_same_value:
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_uleb128 (op1, readp, endp);
printf (" same_value r%" PRIu64 " (%s)\n", op1, regname
(op1));
break;
case DW_CFA_register:
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_uleb128 (op1, readp, endp);
if ((uint64_t) (endp - readp) < 1)
goto invalid;
@@ -5031,6 +5045,8 @@ print_cfa_program (const unsigned char *readp, const unsigned char
*const endp,
puts (" restore_state");
break;
case DW_CFA_def_cfa:
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_uleb128 (op1, readp, endp);
if ((uint64_t) (endp - readp) < 1)
goto invalid;
@@ -5039,15 +5055,21 @@ print_cfa_program (const unsigned char *readp, const unsigned char
*const endp,
op1, regname (op1), op2);
break;
case DW_CFA_def_cfa_register:
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_uleb128 (op1, readp, endp);
printf (" def_cfa_register r%" PRIu64 " (%s)\n",
op1, regname (op1));
break;
case DW_CFA_def_cfa_offset:
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_uleb128 (op1, readp, endp);
printf (" def_cfa_offset %" PRIu64 "\n", op1);
break;
case DW_CFA_def_cfa_expression:
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_uleb128 (op1, readp, endp); /* Length of DW_FORM_block. */
printf (" def_cfa_expression %" PRIu64 "\n", op1);
if ((uint64_t) (endp - readp) < op1)
@@ -5061,6 +5083,8 @@ print_cfa_program (const unsigned char *readp, const unsigned char
*const endp,
readp += op1;
break;
case DW_CFA_expression:
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_uleb128 (op1, readp, endp);
if ((uint64_t) (endp - readp) < 1)
goto invalid;
@@ -5074,6 +5098,8 @@ print_cfa_program (const unsigned char *readp, const unsigned char
*const endp,
readp += op2;
break;
case DW_CFA_offset_extended_sf:
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_uleb128 (op1, readp, endp);
if ((uint64_t) (endp - readp) < 1)
goto invalid;
@@ -5083,6 +5109,8 @@ print_cfa_program (const unsigned char *readp, const unsigned char
*const endp,
op1, regname (op1), sop2 * data_align);
break;
case DW_CFA_def_cfa_sf:
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_uleb128 (op1, readp, endp);
if ((uint64_t) (endp - readp) < 1)
goto invalid;
@@ -5091,11 +5119,14 @@ print_cfa_program (const unsigned char *readp, const unsigned char
*const endp,
op1, regname (op1), sop2 * data_align);
break;
case DW_CFA_def_cfa_offset_sf:
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_sleb128 (sop1, readp, endp);
printf (" def_cfa_offset_sf %" PRId64 "\n", sop1 *
data_align);
break;
case DW_CFA_val_offset:
- // XXX overflow check
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_uleb128 (op1, readp, endp);
if ((uint64_t) (endp - readp) < 1)
goto invalid;
@@ -5104,7 +5135,8 @@ print_cfa_program (const unsigned char *readp, const unsigned char
*const endp,
op1, op2 * data_align);
break;
case DW_CFA_val_offset_sf:
- // XXX overflow check
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_uleb128 (op1, readp, endp);
if ((uint64_t) (endp - readp) < 1)
goto invalid;
@@ -5113,6 +5145,8 @@ print_cfa_program (const unsigned char *readp, const unsigned char
*const endp,
op1, sop2 * data_align);
break;
case DW_CFA_val_expression:
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_uleb128 (op1, readp, endp);
if ((uint64_t) (endp - readp) < 1)
goto invalid;
@@ -5136,6 +5170,8 @@ print_cfa_program (const unsigned char *readp, const unsigned char
*const endp,
puts (" GNU_window_save");
break;
case DW_CFA_GNU_args_size:
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_uleb128 (op1, readp, endp);
printf (" args_size %" PRIu64 "\n", op1);
break;
@@ -5149,6 +5185,8 @@ print_cfa_program (const unsigned char *readp, const unsigned char
*const endp,
else if (opcode < DW_CFA_restore)
{
uint64_t offset;
+ if ((uint64_t) (endp - readp) < 1)
+ goto invalid;
get_uleb128 (offset, readp, endp);
printf (" offset r%u (%s) at cfa%+" PRId64 "\n",
opcode & 0x3f, regname (opcode & 0x3f), offset * data_align);
--
1.8.3.1