Bug 1680651 (CVE-2019-9070)

Summary: CVE-2019-9070 binutils: heap-based buffer over-read in function d_expression_1 in cp-demangle.c
Product: [Other] Security Response Reporter: Dhananjay Arunesh <darunesh>
Component: vulnerabilityAssignee: Red Hat Product Security <security-response-team>
Status: CLOSED WONTFIX QA Contact:
Severity: low Docs Contact:
Priority: low    
Version: unspecifiedCC: abhgupta, aoliva, dbaker, dvlasenk, fweimer, jakub, jokerman, law, mprchlik, nickc, ohudlick, sthangav, trankin
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2019-06-10 10:48:46 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On: 1680652    
Bug Blocks: 1680680    

Description Dhananjay Arunesh 2019-02-25 13:17:11 UTC
An issue was discovered in GNU libiberty, as distributed in GNU Binutils 2.32. It is a heap-based buffer over-read in d_expression_1 in cp-demangle.c after many recursive calls.

Reference:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89395

Comment 1 Dhananjay Arunesh 2019-02-25 13:17:24 UTC
Created binutils tracking bugs for this issue:

Affects: fedora-all [bug 1680652]

Comment 2 Scott Gayou 2019-03-13 14:10:08 UTC
Segfault on Red Hat Enterprise Linux 6. 7 seems to be okay.

```
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7ba071a in d_expression (di=0x7fffffffe030) at ./cp-demangle.c:2681
2681	      if (d_peek_char (di) == 'I')
(gdb) bt
#0  0x00007ffff7ba071a in d_expression (di=0x7fffffffe030) at ./cp-demangle.c:2681
#1  0x00007ffff7ba09f8 in d_expression (di=0x7fffffffe030) at ./cp-demangle.c:2741
#2  0x00007ffff7ba0990 in d_expression (di=0x7fffffffe030) at ./cp-demangle.c:2737
#3  0x00007ffff7ba0990 in d_expression (di=0x7fffffffe030) at ./cp-demangle.c:2737
#4  0x00007ffff7ba0990 in d_expression (di=0x7fffffffe030) at ./cp-demangle.c:2737
#5  0x00007ffff7ba09f8 in d_expression (di=0x7fffffffe030) at ./cp-demangle.c:2741
#6  0x00007ffff7ba0990 in d_expression (di=0x7fffffffe030) at ./cp-demangle.c:2737
#7  0x00007ffff7ba0990 in d_expression (di=0x7fffffffe030) at ./cp-demangle.c:2737
#8  0x00007ffff7ba0990 in d_expression (di=0x7fffffffe030) at ./cp-demangle.c:2737
#9  0x00007ffff7ba0990 in d_expression (di=0x7fffffffe030) at ./cp-demangle.c:2737
```

Comment 3 Scott Gayou 2019-03-13 15:20:40 UTC
Red Hat Enterprise Linux 6:

```
   │1399    d_source_name (struct d_info *di)                            		  │
   │1400    {                                                                             │
   │1401      long len;                                                                   │
   │1402      struct demangle_component *ret;                                             │
   │1403                                                                                  │
   │1404      len = d_number (di);                                            		  │
  >│1405      if (len <= 0)

(gdb) print len
$13 = 7550956185914230101
```

Looks like d_number is returning junk in this case.

After this, `ret = d_identifier (di, len);` runs and presumably increments di->n len bytes.

```
(gdb) print di->n
$14 = 0xfffffffff85596f2 <Address 0xfffffffff85596f2 out of bounds>
```

Thus, next time di->n is used (as a string ptr I believe), a deference leads to a crash.

Comment 4 Scott Gayou 2019-03-13 15:40:57 UTC
Still unclear why I am unable to reproduce on later versions. It looks like the di advance function in RHEL7's version (and up) has support for a "checked" advance. It looks for a NULL character and aborts if it finds one.

I didn't see an abort signal raised though, so that doesn't seem to be the solution.