Package: libklibc-dev Version: 2.0.8-6 Followup-For: Bug #943425 X-Debbugs-Cc: t...@debian.org
I am able to track this down on the porterbox zelenka. $ apt-get source mksh $ cd mksh-59c $ mkdir -p build/klibc $ cd build/klibc $ cp /usr/lib/klibc/bin/mksh . $ chmod +x mksh # because the x attribute is removed if testsfail $ gdb --args ./mksh -c 'x=q; e=1; x=${ echo a; typeset e=2; return 3; echo x$e;}; echo 3:y$x,$e,$?.' (gdb) r [...] Program received signal SIGSEGV, Segmentation fault. 0x0000000001007c32 in comsub (fn=14, cp=0x0, xp=<synthetic pointer>) at ../../eval.c:1611 warning: Source file is more recent than executable. 1611 lseek(shf_fileno(shf), (off_t)0, SEEK_SET); (gdb) bt #0 0x0000000001007c32 in comsub (fn=14, cp=0x0, xp=<synthetic pointer>) at ../../eval.c:1611 #1 expand (ccp=ccp@entry=0x3fffdfe4768 "\001x\001=\016\\echo a ; \\typeset e=2 ; \\return 3 ; \\echo x$e ", wp=wp@entry=0x3ffffffed48, f=f@entry=4128) at ../../eval.c:346 #2 0x000000000100a366 in evalstr ( cp=0x3fffdfe4768 "\001x\001=\016\\echo a ; \\typeset e=2 ; \\return 3 ; \\echo x$e ", f=f@entry=4128) at ../../eval.c:173 #3 0x000000000100d082 in comexec (t=0x3fffdfe4888, tp=tp@entry=0x0, ap=0x3fffdfe45e8, flags=<optimized out>, xerrok=<optimized out>) at ../../exec.c:640 #4 0x000000000100bf0a in execute (t=<optimized out>, flags=<optimized out>, xerrok=xerrok@entry=0x0) at ../../exec.c:162 #5 0x000000000100c0a2 in execute (t=t@entry=0x3fffdfe4588, flags=flags@entry=0, xerrok=xerrok@entry=0x0) at ../../exec.c:204 #6 0x000000000101e048 in shell (s=s@entry=0x3fffdfe3b68, level=level@entry=0) at ../../main.c:954 #7 0x0000000001000e78 in main (argc=<optimized out>, argv=<optimized out>) at ../../main.c:742 (gdb) print shf $1 = (struct shf *) 0x0 The code in question (where it crashes) is thus: 1584 } else if (fn == FUNSUB) { 1585 int ofd1; 1586 struct temp *tf = NULL; 1587 1588 /* 1589 * create a temporary file, open for reading and writing, 1590 * with an shf open for reading (buffered) but yet unused 1591 */ 1592 maketemp(ATEMP, TT_FUNSUB, &tf); 1593 if (!tf->shf) { 1594 errorf(Tf_temp, 1595 Tcreate, tf->tffn, cstrerror(errno)); 1596 } 1597 /* extract shf from temporary file, unlink and free it */ 1598 shf = tf->shf; 1599 unlink(tf->tffn); 1600 afree(tf, ATEMP); 1601 /* save stdout and let it point to the tempfile */ 1602 ofd1 = savefd(1); 1603 ksh_dup2(shf_fileno(shf), 1, false); 1604 /* 1605 * run tree, with output thrown into the tempfile, 1606 * in a new function block 1607 */ 1608 valsub(t, NULL); 1609 subst_exstat = exstat & 0xFF; 1610 /* rewind the tempfile and restore regular stdout */ 1611 lseek(shf_fileno(shf), (off_t)0, SEEK_SET); 1612 restfd(1, ofd1); The crash occurs in line 1611 because shf (a local variable) is nil. The really interesting part, though, is in line 1608, a call to valsub(): 2093 /* helper function due to setjmp/longjmp woes */ 2094 static char * 2095 valsub(struct op *t, Area *ap) 2096 { 2097 char * volatile cp = NULL; 2098 struct tbl * volatile vp = NULL; 2099 2100 newenv(E_FUNC); 2101 newblock(); 2102 if (ap) 2103 vp = local(TREPLY, false); 2104 if (!kshsetjmp(e->jbuf)) 2105 execute(t, XXCOM | XERROK, NULL); 2106 if (vp) 2107 strdupx(cp, str_val(vp), ap); 2108 quitenv(NULL); 2109 2110 return (cp); 2111 } Let's look again at the invocation that caused the crash: x=q; e=1; x=${ echo a; typeset e=2; return 3; echo x$e;}; echo 3:y$x,$e,$?. This one does not crash: x=q; e=1; x=${ echo a; typeset e=2; echo x$e;}; echo 2:y$x,$e,$?. The difference here is that 'return' is used in the crash case, which executes a kshlongjmp(), that is siglongjmp(); kshsetjmp(x) is sigsetjmp(x,0), which klibc defines as: 34 #define sigsetjmp(__env, __save) \ 35 ({ \ 36 struct __sigjmp_buf *__e = (__env); \ 37 sigprocmask(0, NULL, &__e->__sigs); \ 38 setjmp(__e->__jmpbuf); \ 39 }) This apparently has two problems: - the __save argument is ignored, contrary to sigsetjmp docs: If, and only if, the savesigs argument provided to sigsetjmp() is non- zero, the process's current signal mask is saved in env and will be re- stored if a siglongjmp() is later performed with this env. - it appears as if the combination of sigsetjmp/siglongjmp does not restore all callee-saved variables correctly on s390x; comparing with glibc shows that the wrong FPU registers seem to be saved but mksh does not use the FPU anyway Setting breakpoints to lines 1608 (valsub call) and 1609: Breakpoint 3, comsub (fn=14, cp=0x3fffdfe476d "\\echo a ; \\typeset e=2 ; \\return 3 ; \\echo x$e ", xp=<synthetic pointer>) at ../../eval.c:1608 1608 valsub(t, NULL); (gdb) print shf $5 = (struct shf *) 0x3fffdfe5de8 (gdb) print &shf Address requested for identifier "shf" which is in register $v10 (gdb) info r pswm 0x705200180000000 505845723963588608 pswa 0x1007c06 16808966 r0 0x11f 287 r1 0xfffffffffffff000 18446744073709547520 r2 0x1 1 r3 0x102dea0 16965280 r4 0x0 0 r5 0x120 288 r6 0x3ff0000000e 4393751543822 r7 0x1020 4128 r8 0x0 0 r9 0xe 14 r10 0x0 0 r11 0xc 12 r12 0x3fffdfe5708 4398012847880 r13 0x102ee90 16969360 r14 0x1007c06 16808966 r15 0x3ffffffea90 4398046505616 acr0 0x3ff 1023 acr1 0xfdff7710 4261377808 acr2 0x0 0 acr3 0x0 0 acr4 0x0 0 acr5 0x0 0 acr6 0x0 0 acr7 0x0 0 acr8 0x0 0 acr9 0x0 0 acr10 0x0 0 acr11 0x0 0 acr12 0x0 0 acr13 0x0 0 acr14 0x0 0 acr15 0x0 0 fpc 0x0 0 orig_r2 0xb 11 last_break 0x101d89c 0x101d89c <ksh_dup2+68> system_call 0x0 0 tdb0 <unavailable> tac <unavailable> tct <unavailable> atia <unavailable> tr0 <unavailable> tr1 <unavailable> tr2 <unavailable> tr3 <unavailable> tr4 <unavailable> tr5 <unavailable> tr6 <unavailable> tr7 <unavailable> tr8 <unavailable> tr9 <unavailable> tr10 <unavailable> tr11 <unavailable> tr12 <unavailable> tr13 <unavailable> tr14 <unavailable> tr15 <unavailable> gsd <unavailable> gssm <unavailable> gsepla <unavailable> bc_gsd <unavailable> bc_gssm <unavailable> bc_gsepla <unavailable> pc 0x1007c06 0x1007c06 <expand+2342> cc 0x2 2 ... uhm, $v10 does not appear here? (gdb) print $v10 $6 = {v4_float = {1.43352833e-42, -4.22639375e+37, 0, 0}, v2_double = {2.1729070589754877e-311, 0}, v16_int8 = { 0, 0, 3, -1, -3, -2, 93, -24, 0, 0, 0, 0, 0, 0, 0, 0}, v8_int16 = {0, 1023, -514, 24040, 0, 0, 0, 0}, v4_int32 = {1023, -33661464, 0, 0}, v2_int64 = {4398012849640, 0}, uint128 = 81129017470195127308370827018240} 0x3FFFDFE5DE8 is 4398012849640 which is in v2_int64, found. I have a feeling... anyway: (gdb) c Continuing. Breakpoint 2, comsub (fn=14, cp=0x0, xp=<synthetic pointer>) at ../../eval.c:1609 1609 subst_exstat = exstat & 0xFF; (gdb) info r pswm 0x705100180000000 505828131777544192 pswa 0x1007c14 16808980 r0 0xffffffffffffffff 18446744073709551615 r1 0x10fc0 69568 r2 0x0 0 r3 0x9fc0 40896 r4 0xfc0 4032 r5 0x0 0 r6 0x3ff0000000e 4393751543822 r7 0x1020 4128 r8 0x0 0 r9 0xe 14 r10 0x0 0 r11 0xc 12 r12 0x3fffdfe5708 4398012847880 r13 0x102ee90 16969360 r14 0x1007c14 16808980 r15 0x3ffffffea90 4398046505616 acr0 0x3ff 1023 acr1 0xfdff7710 4261377808 acr2 0x0 0 acr3 0x0 0 acr4 0x0 0 acr5 0x0 0 acr6 0x0 0 acr7 0x0 0 acr8 0x0 0 acr9 0x0 0 acr10 0x0 0 acr11 0x0 0 acr12 0x0 0 acr13 0x0 0 acr14 0x0 0 acr15 0x0 0 fpc 0x0 0 orig_r2 0x2 2 last_break 0x10066d0 0x10066d0 <valsub+160> system_call 0x0 0 tdb0 <unavailable> tac <unavailable> tct <unavailable> atia <unavailable> tr0 <unavailable> tr1 <unavailable> tr2 <unavailable> tr3 <unavailable> tr4 <unavailable> tr5 <unavailable> tr6 <unavailable> tr7 <unavailable> tr8 <unavailable> tr9 <unavailable> tr10 <unavailable> tr11 <unavailable> tr12 <unavailable> tr13 <unavailable> tr14 <unavailable> tr15 <unavailable> gsd <unavailable> gssm <unavailable> gsepla <unavailable> bc_gsd <unavailable> bc_gssm <unavailable> bc_gsepla <unavailable> pc 0x1007c14 0x1007c14 <expand+2356> cc 0x1 1 (gdb) print $v10 $7 = {v4_float = {0, 0, 0, 0}, v2_double = {0, 0}, v16_int8 = {0 <repeats 16 times>}, v8_int16 = {0, 0, 0, 0, 0, 0, 0, 0}, v4_int32 = {0, 0, 0, 0}, v2_int64 = {0, 0}, uint128 = 0} -- System Information: Debian Release: 11.0 APT prefers unstable-debug APT policy: (500, 'unstable-debug'), (500, 'unstable') Architecture: s390x Kernel: Linux 4.19.0-16-s390x (SMP w/2 CPU threads) Locale: LANG=C, LC_CTYPE=C.UTF-8 (charmap=UTF-8), LANGUAGE not set Shell: /bin/sh linked to /bin/dash Init: unable to detect Versions of packages libklibc-dev depends on: ii libklibc 2.0.8-6 ii linux-libc-dev 5.10.28-1 libklibc-dev recommends no packages. libklibc-dev suggests no packages. -- no debconf information