[PATCH] readelf: Add bounds check before each CFA op that takes an argument.

Mark Wielaard mjw at redhat.com
Wed Dec 17 14:10:08 UTC 2014


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 at 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 at 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 at 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



More information about the elfutils-devel mailing list