Bug 1484290

Summary: There is an illegal address access in dump_entry.c of libncurses.
Product: Red Hat Enterprise Linux 7 Reporter: owl337 <v.owl337>
Component: ncursesAssignee: Miroslav Lichvar <mlichvar>
Status: CLOSED DUPLICATE QA Contact: qe-baseos-daemons
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 7.5-AltCC: akhaitov, dickey, gobaya
Target Milestone: rc   
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2018-07-27 15:24:56 UTC Type: Bug
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:    
Bug Blocks: 1488920    
Attachments:
Description Flags
Triggered by " ./infotocap POC12 "
none
"./infotocap POC12" none

Description owl337 2017-08-23 08:06:03 UTC
Description of problem:

There is an illegal address access in dump_entry.c of libncurses.

Version-Release number of selected component (if applicable):

<= latest version

How reproducible:

./infotocap POC12

Steps to Reproduce:

$ ./../../../infotocap POC12
...
	:bl=^G:cr=\r:do=\n:i2=:i3=:kb=^H:kd=\n:kl=^H:nw=\r\n:rs=\272:\
	:sf=\n:ta=^I:
R裕驭每每:\
	:bl=^G:cr=\r:do=\n:i2=:i3=:kb=^H:kd=\n:kl=^H:nw=\r\n:sf=\n:\
	:ta=^I:
S裕驭[:\
	:bl=^G:cr=\r:do=\n:i2=:i3=:kb=^H:kd=\n:kl=^H:nw=\r\n:sf=\n:\
	:ta=^I:
j裕驭[:\
	:bl=^G:cr=\r:do=\n:kb=^H:kd=\n:kl=^H:nw=\r\n:sf=\n:ta=^I:
Segmentation fault

The GDB debugging information is as follows:
(gdb) set args POC6
(gdb) r

Starting program: /home/icy/secreal/ncurses-6.0-20170819/install/bin/infotocap POC6 
"POC6", line 1, col 9: dubious character `*' in name or alias field
"POC6", line 1, col 10, terminal 'a*9拢驭[': Illegal character (expected alphanumeric or @%&*!#) - '['
"POC6", line 1, col 14, terminal 'a*9拢驭[': unknown capability 'O'
"POC6", line 1, col 21, terminal 'a*9拢驭[': unknown capability '5'
...

Breakpoint 1, fmt_entry (tterm=0x686700, pred=<optimized out>, content_only=<optimized out>, suppress_untranslatable=0, 
    infodump=0, numbers=0) at ../progs/dump_entry.c:996
996			&& !strcmp(reset_2string, termcap_reset))
(gdb) c 
Continuing.
j:\
	:bl=^G:cr=\r:do=\n:kb=^H:kd=\n:kl=^H:nw=\r\n:rs=:sf=\n:ta=^I:
j裕詧拢[M:\
	:bl=^G:cr=\r:do=\n:i2=:i3=:kb=^H:kd=\n:kl=^H:nw=\r\n:rs=\272:\
	:sf=\n:ta=^I:
S裕驭[:\
	:bl=^G:cr=\r:do=\n:kb=^H:kd=\n:kl=^H:nw=\r\n:rs=\272:sf=\n:\
	:ta=^I:
R裕驭每每:\
	:bl=^G:cr=\r:do=\n:i2=:i3=:kb=^H:kd=\n:kl=^H:nw=\r\n:sf=\n:\
	:ta=^I:
j裕詧[M:\
	:bl=^G:cr=\r:do=\n:i2=:i3=:kb=^H:kd=\n:kl=^H:nw=\r\n:rs=\272:\
	:sf=\n:ta=^I:
R裕驭每每:\
	:bl=^G:cr=\r:do=\n:i2=:i3=:kb=^H:kd=\n:kl=^H:nw=\r\n:sf=\n:\
	:ta=^I:
S裕驭[:\
	:bl=^G:cr=\r:do=\n:i2=:i3=:kb=^H:kd=\n:kl=^H:nw=\r\n:sf=\n:\
	:ta=^I:
j裕驭[:\
	:bl=^G:cr=\r:do=\n:kb=^H:kd=\n:kl=^H:nw=\r\n:sf=\n:ta=^I:

Breakpoint 1, fmt_entry (tterm=0x68f600, pred=<optimized out>, content_only=<optimized out>, suppress_untranslatable=0, 
    infodump=0, numbers=0) at ../progs/dump_entry.c:996
996			&& !strcmp(reset_2string, termcap_reset))
(gdb) bt 
#0  fmt_entry (tterm=0x68f600, pred=<optimized out>, content_only=<optimized out>, suppress_untranslatable=0, 
    infodump=0, numbers=0) at ../progs/dump_entry.c:996
#1  0x00000000004195df in dump_entry (tterm=0x68f600, suppress_untranslatable=0, limited=1, numbers=0, pred=0x0)
    at ../progs/dump_entry.c:1513
#2  0x0000000000403e74 in main (argc=<optimized out>, argv=<optimized out>) at ../progs/tic.c:1032
(gdb) n

Program received signal SIGSEGV, Segmentation fault.
__strcmp_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcmp-sse2-unaligned.S:201
201	../sysdeps/x86_64/multiarch/strcmp-sse2-unaligned.S: No such file or directory.

Trigged in:
fmt_entry (tterm=0x68f600, pred=<optimized out>, content_only=<optimized out>, suppress_untranslatable=0, 
    infodump=0, numbers=0) at ../progs/dump_entry.c:996
996			&& !strcmp(reset_2string, termcap_reset))
(gdb) list 
991		    if (init_3string != ABSENT_STRING
992			&& !strcmp(init_3string, termcap_reset))
993			DISCARD(init_3string);
994	
995		    if (reset_2string != ABSENT_STRING
996			&& !strcmp(reset_2string, termcap_reset))
997			DISCARD(reset_2string);
998		}
999	    }
1000	



Actual results:

crash

Expected results:

crash

Additional info:

Credits:

This vulnerability is detected by team OWL337, with our custom fuzzer collAFL. Please contact ganshuitao   and chaoz.cn if you need more info about the team, the tool or the vulnerability.

Comment 2 Thomas E. Dickey 2017-08-24 08:24:14 UTC
The attachment has been deleted; there are no steps to reproduce the issue.

Comment 3 owl337 2017-08-24 08:53:14 UTC
Created attachment 1317519 [details]
"./infotocap POC12"

Comment 4 Thomas E. Dickey 2017-08-25 22:40:00 UTC
The given attachment does not produce the problem.
By the way, the trace uses a different filename.

Comment 5 owl337 2017-08-26 03:13:13 UTC
(In reply to Thomas E. Dickey from comment #4)
> The given attachment does not produce the problem.
> By the way, the trace uses a different filename.

Please set it as follow.
$gdb infotocap
...
(gdb) set args POC12

Comment 6 owl337 2017-08-26 03:20:44 UTC
I check the poc I upstreamed again. It should be correct in the latest version(date:08.19)

Comment 7 Thomas E. Dickey 2017-08-26 13:57:17 UTC
I am still unable to reproduce the problem with this data.

Comment 8 gobaya 2017-11-08 01:11:53 UTC
In curses, there are two kinds of invalid string, ABSENT_STRING (char*)0, and CANCELLED_STRING (char *)(-1). However, in ncurses 6.0, a string will be passed to strcmp if it is not an ABSENT_STRING. strcmp call on a CANCELLED_STRING causes a segment fault.

In ncurses-6.0-20171007, macro VALID_STRING check a string for both ABSENT_STRING and CANCELLED_STRING, only a string that is neither a ABSENT_STRING nor a CANCELLED_STRING will be passed to strcmp.

Comment 9 gobaya 2017-11-08 01:16:05 UTC
Here is the old code that causes the segment fault:
#undef CUR
#define CUR tterm->
    if (outform == 2) {
 if (tterm-> Strings[395] != (char *)0) {
     if (tterm-> Strings[50] != (char *)0
  && !strcmp(tterm-> Strings[50], tterm-> Strings[395]))
  tterm-> Strings[50] = (char *)0;

     if (tterm-> Strings[123] != (char *)0
  && !strcmp(tterm-> Strings[123], tterm-> Strings[395]))
  tterm-> Strings[123] = (char *)0;
 }
    }

Here is the recent code that fails to reproduce the segment fault:#undef CUR
#define CUR tterm->
    if (outform == 2) {
 if (((tterm-> Strings[395]) != (char *)(-1) && (tterm-> Strings[395]) != (char *)0)) {
     if (((tterm-> Strings[50]) != (char *)(-1) && (tterm-> Strings[50]) != (char *)0)
  && !strcmp(tterm-> Strings[50], tterm-> Strings[395]))
  tterm-> Strings[50] = (char *)0;

     if (((tterm-> Strings[123]) != (char *)(-1) && (tterm-> Strings[123]) != (char *)0)
  && !strcmp(tterm-> Strings[123], tterm-> Strings[395]))
  tterm-> Strings[123] = (char *)0;
 }
    }