Bug 1371630

Summary: Getting KSH Segfault even after applying the errata of #1247383
Product: Red Hat Enterprise Linux 7 Reporter: Filip Krska <fkrska>
Component: kshAssignee: Siteshwar Vashisht <svashisht>
Status: CLOSED ERRATA QA Contact: Jan Kepler <jkejda>
Severity: medium Docs Contact:
Priority: medium    
Version: 7.2CC: fkrska, isenfeld, jkejda, qe-baseos-apps, srandhaw, svashisht
Target Milestone: rcKeywords: Reproducer
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: ksh-20120801-34.el7 Doc Type: If docs needed, set a value
Doc Text:
Story Points: ---
Clone Of: 1349280
: 1466399 (view as bug list) Environment:
Last Closed: 2017-08-01 16:26:55 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: 1298243, 1393867    
Attachments:
Description Flags
ksh-20120801-typeset.patch none

Description Filip Krska 2016-08-30 16:31:33 UTC
ksh-20120801-26.el7.x86_64 reproduces as well

+++ This bug was initially created as a clone of Bug #1349280 +++


--- Additional comment from Filip Krska on 2016-08-30 12:25:19 EDT ---

Minimalistic reproducer:

# cat ksh_typeset.sh
A[0]=$"'"
B[0]=aa
C[0]=aa
typeset -a
# ksh ksh_typeset.sh 
Segmentation fault (core dumped)

Comment 1 Filip Krska 2016-09-16 15:22:47 UTC
When tracing the while loop at typeset.c:1455

 else while(namec--)
        {
                if((np=nv_search(*argv++,root,0)) && np!=onp && (!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE)))
                {
                        onp = np;
                        if(name)
                        {
                                char *newname = nv_name(np);
                                if(memcmp(name,newname,len)==0 && newname[len]== '.')
                                        continue;
                                name = 0;
                        }
                        if(flag&NV_ARRAY)
                        {
                                if(nv_aindex(np)>=0)
                                {
                                        if(!(flag&NV_IARRAY))
                                                continue;
                                }
                                else if((flag&NV_IARRAY))
                                        continue;

                        }
                        tp->scanmask = flag&~NV_NOSCOPE;
                        tp->scanroot = root;
                        print_namval(file,np,option,tp);
                        if(!is_abuiltin(np) && nv_isvtree(np))
                        {
                                name = nv_name(np);
                                len = strlen(name);
                        }
                }
        }

it seems that function print_namval(file,np,option,tp); damages argv[]:

(gdb) 
1480				print_namval(file,np,option,tp);
3: argv[1] = 0x7ffff7f905d8 "C"
1: *argv = 0x7ffff7f903b8 "B"
(gdb) n
1481				if(!is_abuiltin(np) && nv_isvtree(np))
3: argv[1] = 0x27275c2724 <Address 0x27275c2724 out of bounds>
1: *argv = 0x7ffff7f903b8 "B"

next cycle of while then leads to segfault because nv_search gets the damaged *argv++ value.

Comment 2 Filip Krska 2016-10-06 15:14:34 UTC
Actually the $ was redundant in the reproducer, following is working as well:

# cat ksh_typeset.sh 
A[0]="'"
B[0]=aa
C[0]=aa
typeset -a


This is what I got when watching *argv, rgv[1]:

(gdb) b typeset.c:1455
Breakpoint 1 at 0x4905aa: file /usr/src/debug/ksh-20120801/src/cmd/ksh93/bltins/typeset.c, line 1455.
(gdb) run ksh_typeset.sh
Starting program: /usr/bin/ksh ksh_typeset.sh

Breakpoint 1, print_scan (file=0x79cea0 <_Sfstdout>, flag=4195328, root=0x7ffff7fc8fc0, option=0, tp=0x7fffffffd9a0)
    at /usr/src/debug/ksh-20120801/src/cmd/ksh93/bltins/typeset.c:1455
1455		else while(namec--)
(gdb) watch *argv
Watchpoint 2: *argv
(gdb) watch argv[1]
Watchpoint 3: argv[1]
(gdb) c
Continuing.
Watchpoint 2: *argv

Old value = 0x7ffff7f90198 "A"
New value = 0x7ffff7f903b8 "B"
Watchpoint 3: argv[1]

Old value = 0x7ffff7f903b8 "B"
New value = 0x7ffff7f905d8 "C"
0x00000000004905b6 in print_scan (file=0x79cea0 <_Sfstdout>, flag=4195328, root=0x7ffff7fc8fc0, option=0, tp=0x7fffffffd9a0)
    at /usr/src/debug/ksh-20120801/src/cmd/ksh93/bltins/typeset.c:1457
1457			if((np=nv_search(*argv++,root,0)) && np!=onp && (!nv_isnull(np) || np->nvfun || nv_isattr(np,~NV_NOFREE)))
(gdb) 
Continuing.
Watchpoint 3: argv[1]

Old value = 0x7ffff7f905d8 "C"
New value = 0x7ffff7f90524 ""
0x00007ffff739b1da in __memmove_sse2 (dest=<optimized out>, src=<optimized out>, len=<optimized out>) at ../string/memmove.c:85
85	      BYTE_COPY_FWD (dstp, srcp, len);
(gdb) bt
#0  0x00007ffff739b1da in __memmove_sse2 (dest=<optimized out>, src=<optimized out>, len=<optimized out>) at ../string/memmove.c:85
#1  0x00000000004fd721 in sfwrite (f=0x79b0e0 <_Stak_data>, buf=0x52ec80, n=2)
    at /usr/src/debug/ksh-20120801/src/lib/libast/sfio/sfwrite.c:138
#2  0x000000000045d21d in sh_fmtq (string=0x7ffff7f90350 "'") at /usr/src/debug/ksh-20120801/src/cmd/ksh93/sh/string.c:383
#3  0x000000000044f72d in nv_outnode (np=0x7ffff7f90160, out=0x79cea0 <_Sfstdout>, indent=-1, special=0)
    at /usr/src/debug/ksh-20120801/src/cmd/ksh93/sh/nvtree.c:661
#4  0x000000000048d5bd in print_value (iop=0x79cea0 <_Sfstdout>, np=0x7ffff7f90160, tp=0x7fffffffd9a0)
    at /usr/src/debug/ksh-20120801/src/cmd/ksh93/bltins/typeset.c:514
#5  0x0000000000490182 in print_namval (file=0x79cea0 <_Sfstdout>, np=0x7ffff7f90160, flag=0, tp=0x7fffffffd9a0)
    at /usr/src/debug/ksh-20120801/src/cmd/ksh93/bltins/typeset.c:1367
#6  0x00000000004906f3 in print_scan (file=0x79cea0 <_Sfstdout>, flag=4195328, root=0x7ffff7fc8fc0, option=0, tp=0x7fffffffd9a0)
    at /usr/src/debug/ksh-20120801/src/cmd/ksh93/bltins/typeset.c:1480
#7  0x000000000048e8be in setall (argv=0x7ffff7fac698, flag=4195840, troot=0x7ffff7fc8fc0, tp=0x7fffffffd9a0)
    at /usr/src/debug/ksh-20120801/src/cmd/ksh93/bltins/typeset.c:860
#8  0x000000000048d226 in b_typeset (argc=2, argv=0x7ffff7fac698, context=0x79f830 <sh+1296>)
    at /usr/src/debug/ksh-20120801/src/cmd/ksh93/bltins/typeset.c:459
#9  0x000000000046a290 in sh_exec (t=0x7ffff7fac7d1, flags=4) at /usr/src/debug/ksh-20120801/src/cmd/ksh93/sh/xec.c:1410
#10 0x00000000004074ec in exfile (shp=0x7ffff7fac7d1, iop=0x52ec80, fno=36) at /usr/src/debug/ksh-20120801/src/cmd/ksh93/sh/main.c:581
#11 0x000000000040690c in sh_main (ac=2, av=0x7fffffffe338, userinit=0x0) at /usr/src/debug/ksh-20120801/src/cmd/ksh93/sh/main.c:353
#12 0x0000000000405ca2 in main (argc=2, argv=0x7fffffffe338) at /usr/src/debug/ksh-20120801/src/cmd/ksh93/sh/pmain.c:45
(gdb) c
Continuing.
Watchpoint 3: argv[1]

Old value = 0x7ffff7f90524 ""
New value = 0x7ffff7f92724 ""
0x00007ffff739b1da in __memmove_sse2 (dest=<optimized out>, src=<optimized out>, len=<optimized out>) at ../string/memmove.c:85
85	      BYTE_COPY_FWD (dstp, srcp, len);
(gdb) c
Continuing.
Watchpoint 3: argv[1]

Old value = 0x7ffff7f92724 ""
New value = 0x7ffff75c2724 <Address 0x7ffff75c2724 out of bounds>
sh_fmtq (string=0x7ffff7f90350 "'") at /usr/src/debug/ksh-20120801/src/cmd/ksh93/sh/string.c:445
445					stakputc(c);
(gdb) bt
#0  sh_fmtq (string=0x7ffff7f90350 "'") at /usr/src/debug/ksh-20120801/src/cmd/ksh93/sh/string.c:445
#1  0x000000000044f72d in nv_outnode (np=0x7ffff7f90160, out=0x79cea0 <_Sfstdout>, indent=-1, special=0)
    at /usr/src/debug/ksh-20120801/src/cmd/ksh93/sh/nvtree.c:661
#2  0x000000000048d5bd in print_value (iop=0x79cea0 <_Sfstdout>, np=0x7ffff7f90160, tp=0x7fffffffd9a0)
    at /usr/src/debug/ksh-20120801/src/cmd/ksh93/bltins/typeset.c:514
#3  0x0000000000490182 in print_namval (file=0x79cea0 <_Sfstdout>, np=0x7ffff7f90160, flag=0, tp=0x7fffffffd9a0)
    at /usr/src/debug/ksh-20120801/src/cmd/ksh93/bltins/typeset.c:1367
#4  0x00000000004906f3 in print_scan (file=0x79cea0 <_Sfstdout>, flag=4195328, root=0x7ffff7fc8fc0, option=0, tp=0x7fffffffd9a0)
    at /usr/src/debug/ksh-20120801/src/cmd/ksh93/bltins/typeset.c:1480
#5  0x000000000048e8be in setall (argv=0x7ffff7fac698, flag=4195840, troot=0x7ffff7fc8fc0, tp=0x7fffffffd9a0)
    at /usr/src/debug/ksh-20120801/src/cmd/ksh93/bltins/typeset.c:860
#6  0x000000000048d226 in b_typeset (argc=2, argv=0x7ffff7fac698, context=0x79f830 <sh+1296>)
    at /usr/src/debug/ksh-20120801/src/cmd/ksh93/bltins/typeset.c:459
#7  0x000000000046a290 in sh_exec (t=0x799ec4 <_ast_info+36>, flags=4) at /usr/src/debug/ksh-20120801/src/cmd/ksh93/sh/xec.c:1410
#8  0x00000000004074ec in exfile (shp=0x799ec4 <_ast_info+36>, iop=0x7ffff7f90350, fno=-134559789)
    at /usr/src/debug/ksh-20120801/src/cmd/ksh93/sh/main.c:581
#9  0x000000000040690c in sh_main (ac=2, av=0x7fffffffe338, userinit=0x0) at /usr/src/debug/ksh-20120801/src/cmd/ksh93/sh/main.c:353
#10 0x0000000000405ca2 in main (argc=2, argv=0x7fffffffe338) at /usr/src/debug/ksh-20120801/src/cmd/ksh93/sh/pmain.c:45


I don't know yet which function is to blame but imho argv[] shall not be altered inside print_namval()...

Comment 3 Siteshwar Vashisht 2016-12-12 23:14:50 UTC
Thanks Filip for the reproducer and debugging information.

I will add some more notes.

It seems ksh handles "'" specially and it goes through below codepath in sh_fmtq() function in src/cmd/ksh93/sh/string.c :

char    *sh_fmtq(const char *string)
...
...

#if SHOPT_MULTIBYTE
                if(c=='\'' || c>=128 || c<0 || !iswprint(c)) 
#else
                if(c=='\'' || !isprint(c))
#endif /* SHOPT_MULTIBYTE */
                        state = 2;

...
...
        }
        if(state<2)
        {
            ...
            ...
        }
        else
        {
                int isbyte=0;
                stakwrite("$'",2);

...
...
                        if(state)
                        {
                                stakputc('\\');
                                stakputc(c);
                        }
...
...
                stakputc('\'');
        }
        stakputc(0);
....


So at the end "'" is being expanded to "$'\\''".

This codepath is probably corrupting the stack data structure that ksh maintains.

Comment 4 Siteshwar Vashisht 2016-12-14 12:15:46 UTC
Created attachment 1231648 [details]
ksh-20120801-typeset.patch

Fix a bug in memory allocation while listing indexed arrays with typeset

Comment 12 errata-xmlrpc 2017-08-01 16:26:55 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHBA-2017:1936