libunwind-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Libunwind-devel] [PATCH] Check that the CIE is within the segment


From: Peter Wu
Subject: Re: [Libunwind-devel] [PATCH] Check that the CIE is within the segment
Date: Tue, 02 Dec 2014 18:06:17 +0100
User-agent: KMail/4.14.3 (Linux/3.17.0-rc4-custom-00168-g7ec62d4; KDE/4.14.3; x86_64; ; )

ping?

On Tuesday 25 November 2014 22:10:33 Peter Wu wrote:
> Due to a bug in the gold linker[1], the .eh_frame and .eh_frame_hdr
> sections contains garbage. When dwarf_extract_proc_info_from_fde tried
> to look up the begin of the CIE subsection, it would underflow the
> .eh_frame segment, resulting in a crash[2].
> 
> This patch avoids that crash by checking whether the CIE pointer is
> located after the begin of the .eh_frame section. The variable "base"
> was misused in various places as a boolean (decode as .debug_frame or
> decode as .eh_frame). These instances have been renamed to
> is_debug_frame where applicable.
> 
> Tested on Linux x86_64.
> 
>  [1]: https://sourceware.org/bugzilla/show_bug.cgi?id=17639
>  [2]: 
> http://lists.nongnu.org/archive/html/libunwind-devel/2014-11/msg00009.html
> 
> Signed-off-by: Peter Wu <address@hidden>
> ---
>  include/dwarf.h                 |  3 ++-
>  src/dwarf/Gfde.c                | 27 ++++++++++++++++++---------
>  src/dwarf/Gfind_proc_info-lsb.c | 12 ++++++++----
>  3 files changed, 28 insertions(+), 14 deletions(-)
> 
> diff --git a/include/dwarf.h b/include/dwarf.h
> index 169f739..633868b 100644
> --- a/include/dwarf.h
> +++ b/include/dwarf.h
> @@ -423,8 +423,9 @@ extern int dwarf_extract_proc_info_from_fde 
> (unw_addr_space_t as,
>                                               unw_accessors_t *a,
>                                               unw_word_t *fde_addr,
>                                               unw_proc_info_t *pi,
> -                                             int need_unwind_info,
>                                               unw_word_t base,
> +                                             int need_unwind_info,
> +                                             int is_debug_frame,
>                                               void *arg);
>  extern int dwarf_find_save_locs (struct dwarf_cursor *c);
>  extern int dwarf_create_state_record (struct dwarf_cursor *c,
> diff --git a/src/dwarf/Gfde.c b/src/dwarf/Gfde.c
> index dd00b62..5bcaa4d 100644
> --- a/src/dwarf/Gfde.c
> +++ b/src/dwarf/Gfde.c
> @@ -45,7 +45,7 @@ is_cie_id (unw_word_t val, int is_debug_frame)
>  static inline int
>  parse_cie (unw_addr_space_t as, unw_accessors_t *a, unw_word_t addr,
>             const unw_proc_info_t *pi, struct dwarf_cie_info *dci,
> -           unw_word_t base, void *arg)
> +           int is_debug_frame, void *arg)
>  {
>    uint8_t version, ch, augstr[5], fde_encoding, handler_encoding;
>    unw_word_t len, cie_end_addr, aug_size;
> @@ -79,7 +79,7 @@ parse_cie (unw_addr_space_t as, unw_accessors_t *a, 
> unw_word_t addr,
>        /* the CIE is in the 32-bit DWARF format */
>        uint32_t cie_id;
>        /* DWARF says CIE id should be 0xffffffff, but in .eh_frame, it's 0 */
> -      const uint32_t expected_id = (base) ? 0xffffffff : 0;
> +      const uint32_t expected_id = (is_debug_frame) ? 0xffffffff : 0;
>  
>        len = u32val;
>        cie_end_addr = addr + len;
> @@ -97,7 +97,7 @@ parse_cie (unw_addr_space_t as, unw_accessors_t *a, 
> unw_word_t addr,
>        uint64_t cie_id;
>        /* DWARF says CIE id should be 0xffffffffffffffff, but in
>           .eh_frame, it's 0 */
> -      const uint64_t expected_id = (base) ? 0xffffffffffffffffull : 0;
> +      const uint64_t expected_id = (is_debug_frame) ? 0xffffffffffffffffull 
> : 0;
>  
>        if ((ret = dwarf_readu64 (as, a, &addr, &u64val, arg)) < 0)
>          return ret;
> @@ -220,7 +220,8 @@ parse_cie (unw_addr_space_t as, unw_accessors_t *a, 
> unw_word_t addr,
>  HIDDEN int
>  dwarf_extract_proc_info_from_fde (unw_addr_space_t as, unw_accessors_t *a,
>                                    unw_word_t *addrp, unw_proc_info_t *pi,
> -                                  int need_unwind_info, unw_word_t base,
> +                                  unw_word_t base,
> +                                  int need_unwind_info, int is_debug_frame,
>                                    void *arg)
>  {
>    unw_word_t fde_end_addr, cie_addr, cie_offset_addr, aug_end_addr = 0;
> @@ -251,14 +252,18 @@ dwarf_extract_proc_info_from_fde (unw_addr_space_t as, 
> unw_accessors_t *a,
>        *addrp = fde_end_addr = addr + u32val;
>        cie_offset_addr = addr;
>  
> +      /* CIE must be within the segment. */
> +      if (cie_offset_addr < base)
> +          return -UNW_ENOINFO;
> +
>        if ((ret = dwarf_reads32 (as, a, &addr, &cie_offset, arg)) < 0)
>          return ret;
>  
> -      if (is_cie_id (cie_offset, base != 0))
> +      if (is_cie_id (cie_offset, is_debug_frame))
>          /* ignore CIEs (happens during linear searches) */
>          return 0;
>  
> -      if (base != 0)
> +      if (is_debug_frame)
>          cie_addr = base + cie_offset;
>        else
>          /* DWARF says that the CIE_pointer in the FDE is a
> @@ -279,14 +284,18 @@ dwarf_extract_proc_info_from_fde (unw_addr_space_t as, 
> unw_accessors_t *a,
>        *addrp = fde_end_addr = addr + u64val;
>        cie_offset_addr = addr;
>  
> +      /* CIE must be within the segment. */
> +      if (cie_offset_addr < base)
> +          return -UNW_ENOINFO;
> +
>        if ((ret = dwarf_reads64 (as, a, &addr, &cie_offset, arg)) < 0)
>          return ret;
>  
> -      if (is_cie_id (cie_offset, base != 0))
> +      if (is_cie_id (cie_offset, is_debug_frame))
>          /* ignore CIEs (happens during linear searches) */
>          return 0;
>  
> -      if (base != 0)
> +      if (is_debug_frame)
>          cie_addr = base + cie_offset;
>        else
>          /* DWARF says that the CIE_pointer in the FDE is a
> @@ -298,7 +307,7 @@ dwarf_extract_proc_info_from_fde (unw_addr_space_t as, 
> unw_accessors_t *a,
>  
>    Debug (15, "looking for CIE at address %lx\n", (long) cie_addr);
>  
> -  if ((ret = parse_cie (as, a, cie_addr, pi, &dci, base, arg)) < 0)
> +  if ((ret = parse_cie (as, a, cie_addr, pi, &dci, is_debug_frame, arg)) < 0)
>      return ret;
>  
>    /* IP-range has same encoding as FDE pointers, except that it's
> diff --git a/src/dwarf/Gfind_proc_info-lsb.c b/src/dwarf/Gfind_proc_info-lsb.c
> index e1bfbe7..32f165a 100644
> --- a/src/dwarf/Gfind_proc_info-lsb.c
> +++ b/src/dwarf/Gfind_proc_info-lsb.c
> @@ -59,8 +59,9 @@ linear_search (unw_addr_space_t as, unw_word_t ip,
>    while (i++ < fde_count && addr < eh_frame_end)
>      {
>        fde_addr = addr;
> -      if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, pi, 0, 0, 
> arg))
> -          < 0)
> +      if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, pi,
> +                                                   eh_frame_start,
> +                                                   0, 0, arg)) < 0)
>          return ret;
>  
>        if (ip >= pi->start_ip && ip < pi->end_ip)
> @@ -69,6 +70,7 @@ linear_search (unw_addr_space_t as, unw_word_t ip,
>              return 1;
>            addr = fde_addr;
>            if ((ret = dwarf_extract_proc_info_from_fde (as, a, &addr, pi,
> +                                                       eh_frame_start,
>                                                         need_unwind_info, 0,
>                                                         arg))
>                < 0)
> @@ -468,8 +470,8 @@ dwarf_find_debug_frame (int found, unw_dyn_info_t 
> *di_debug, unw_word_t ip,
>  
>                   err = dwarf_extract_proc_info_from_fde 
> (unw_local_addr_space,
>                                                           a, &fde_addr,
> -                                                         &this_pi, 0,
> -                                                         (uintptr_t) buf,
> +                                                         &this_pi,
> +                                                         (uintptr_t) buf, 0, 
> 1,
>                                                           NULL);
>                   if (err == 0)
>                     {
> @@ -902,6 +904,8 @@ dwarf_search_unwind_table (unw_addr_space_t as, 
> unw_word_t ip,
>              "fde_addr = %lx\n", (long) e->fde_offset, (long) segbase,
>              (long) debug_frame_base, (long) fde_addr);
>    if ((ret = dwarf_extract_proc_info_from_fde (as, a, &fde_addr, pi,
> +                                               debug_frame_base ?
> +                                               debug_frame_base : segbase,
>                                                 need_unwind_info,
>                                                 debug_frame_base, arg)) < 0)
>      return ret;
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]