]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
dwarflint: Fix a SEGV for invalid address size in CU header
authorPetr Machata <pmachata@redhat.com>
Wed, 9 Mar 2011 01:00:28 +0000 (02:00 +0100)
committerPetr Machata <pmachata@redhat.com>
Wed, 9 Mar 2011 01:00:28 +0000 (02:00 +0100)
- read_address_size has a richer interface now.  New type error_code, which
  might be more generally useful
- adapt callers
- add test case

dwarflint/check_debug_aranges.cc
dwarflint/check_debug_info.cc
dwarflint/checked_read.cc
dwarflint/checked_read.hh
dwarflint/tests/garbage-6.bz2 [new file with mode: 0644]
dwarflint/tests/run-bad.sh

index a2fcd450ccde2e38b4250022759924ed79dbde84..915dcae4f7d80b841977a7cf5605d65ce7ec8eb6 100644 (file)
@@ -1,5 +1,5 @@
 /* Low-level checking of .debug_aranges.
-   Copyright (C) 2009, 2010 Red Hat, Inc.
+   Copyright (C) 2009, 2010, 2011 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -286,11 +286,12 @@ check_aranges_structural (struct elf_file *file,
 
       /* Address size.  */
       int address_size;
-      if (!read_address_size (&sub_ctx, file->addr_64, &address_size, &where))
-       {
-         retval = false;
-         goto next;
-       }
+      error_code err = read_address_size (&sub_ctx, file->addr_64,
+                                         &address_size, &where);
+      if (err != err_ok)
+       retval = false;
+      if (err == err_fatal)
+       goto next;
 
       /* Segment size.  */
       uint8_t segment_size;
index 984d608767fbca5d57c0508b0c99bd3f59ddf99b..45af96b85ba9ee3c234fcff2b0060de544b207fe 100644 (file)
@@ -174,6 +174,7 @@ namespace
     struct read_ctx ctx;
     read_ctx_init (&ctx, sec->data, file->other_byte_order);
     uint64_t off_start, off_end;
+    bool fail = false;
 
     std::vector <cu_head> ret;
     while (!read_ctx_eof (&ctx))
@@ -278,9 +279,12 @@ namespace
            << pri::lacks_relocation ("abbrev table offset") << std::endl;
 
        /* Address size.  */
-       if (!read_address_size (&ctx, file->addr_64, &head.address_size,
-                               &head.where))
+       error_code err = read_address_size (&ctx, file->addr_64,
+                                           &head.address_size, &head.where);
+       if (err == err_fatal)
          throw check_base::failed ();
+       else if (err == err_nohl)
+         fail = true;
 
        head.head_size = ctx.ptr - cu_begin; // Length of the headers itself.
        head.total_size = cu_end - cu_begin; // Length including headers field.
@@ -295,6 +299,9 @@ namespace
        ret.push_back (head);
       }
 
+    if (fail)
+      throw check_base::failed ();
+
     return ret;
   }
 
index c6a7144541b74a87729ad77cfe84b27a6c32908f..14831ecb13d565c742deecf3049d905c37c4dbde 100644 (file)
@@ -1,5 +1,5 @@
 /* Pedantic checking of DWARF files
-   Copyright (C) 2010 Red Hat, Inc.
+   Copyright (C) 2010, 2011 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -66,7 +66,7 @@ read_size_extra (struct read_ctx *ctx, uint32_t size32, uint64_t *sizep,
   return true;
 }
 
-bool
+error_code
 read_address_size (struct read_ctx *ctx,
                   bool addr_64,
                   int *address_sizep,
@@ -76,9 +76,10 @@ read_address_size (struct read_ctx *ctx,
   if (!read_ctx_read_ubyte (ctx, &address_size))
     {
       wr_error (where, ": can't read address size.\n");
-      return false;
+      return err_fatal;
     }
 
+  error_code ret = err_ok;
   if (address_size != 4 && address_size != 8)
     {
       /* Keep going.  Deduce the address size from ELF header, and try
@@ -87,15 +88,19 @@ read_address_size (struct read_ctx *ctx,
                ": invalid address size: %d (only 4 or 8 allowed).\n",
                address_size);
       address_size = addr_64 ? 8 : 4;
+      ret = err_nohl;
     }
   else if ((address_size == 8) != addr_64)
-    /* Keep going, we may still be able to parse it.  */
-    wr_error (where,
-             ": CU reports address size of %d in %d-bit ELF.\n",
-             address_size, addr_64 ? 64 : 32);
+    {
+      /* Keep going, we may still be able to parse it.  */
+      wr_error (where,
+               ": CU reports address size of %d in %d-bit ELF.\n",
+               address_size, addr_64 ? 64 : 32);
+      ret = err_nohl;
+    }
 
   *address_sizep = address_size;
-  return true;
+  return ret;
 }
 
 bool
index 4171b57a6f3fbef8fb83d0b3fe65958907f36b4c..1e0deda8c0ef505a5cf98b4731f6cc0ebdf8aaf1 100644 (file)
@@ -1,5 +1,5 @@
 /* Pedantic checking of DWARF files
-   Copyright (C) 2010 Red Hat, Inc.
+   Copyright (C) 2010, 2011 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
 #include "where.h"
 #include "dwarf_version.hh"
 
+enum error_code
+  {
+    err_ok,     ///< The operation passed.
+    err_fatal,  ///< The operation ended in unrecoverable error.
+    err_nohl,   ///< There was an error, but low-level checks may continue.
+  };
+
 bool read_size_extra (read_ctx *ctx, uint32_t size32, uint64_t *sizep,
                      int *offset_sizep, where *where);
 
-bool read_address_size (read_ctx *ctx,
-                       bool addr_64,
-                       int *address_sizep,
-                       where const *where);
+/// Read address size and return it via address_sizep and return 0.
+/// Address size may be 4 or 8; for other values it's set depending or
+/// addr_64, and err_nohl is returned.
+error_code read_address_size (read_ctx *ctx,
+                             bool addr_64,
+                             int *address_sizep,
+                             where const *where);
 
 bool checked_read_uleb128 (read_ctx *ctx, uint64_t *ret,
                           where const *where, const char *what);
diff --git a/dwarflint/tests/garbage-6.bz2 b/dwarflint/tests/garbage-6.bz2
new file mode 100644 (file)
index 0000000..6cb8a44
Binary files /dev/null and b/dwarflint/tests/garbage-6.bz2 differ
index 2da33b651181d00d2e75f1f4e469a9c34d52b649..108f527bbc0a2698d63d7018560df643e45c251b 100755 (executable)
@@ -28,7 +28,7 @@
 srcdir=$srcdir/tests
 
 testfiles hello.bad-1 hello.bad-3 garbage-1 garbage-2 garbage-3 garbage-4 \
-    garbage-5
+    garbage-5 garbage-6
 
 testrun_compare ./dwarflint hello.bad-1 <<EOF
 error: .debug_info: DIE 0x83: abbrev section at 0x0 doesn't contain code 83.
@@ -64,3 +64,11 @@ testrun_compare ./dwarflint garbage-5 <<EOF
 error: .debug_line: offset 0x3e: not enough data to read an opcode of length 5.
 error: .debug_info: DIE 0xb (abbr. attribute 0xc): unresolved reference to .debug_line table 0x0.
 EOF
+
+testrun_compare ./dwarflint garbage-6 <<EOF
+error: .debug_info: CU 0: invalid address size: 9 (only 4 or 8 allowed).
+error: .debug_info: couldn't load CU headers for processing .debug_abbrev; assuming latest DWARF flavor.
+error: .debug_abbrev: abbr. attribute 0xc: attribute stmt_list with invalid form data4.
+error: .debug_abbrev: abbr. attribute 0x23: attribute frame_base with invalid form block1.
+error: .debug_abbrev: abbr. attribute 0x34: attribute location with invalid form block1.
+EOF