Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.debian.kernel > #71205 > unrolled thread

Bug#943425: klibc: [s390x] SIGSEGV in mksh testcase funsub-2

Started byThorsten Glaser <tg@debian.org>
First post2021-05-03 22:20 +0200
Last post2021-05-06 00:30 +0200
Articles 5 — 3 participants

Back to article view | Back to linux.debian.kernel

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Bug#943425: klibc: [s390x] SIGSEGV in mksh testcase funsub-2 Thorsten Glaser <tg@debian.org> - 2021-05-03 22:20 +0200
    Bug#943425: Use of $v10 register (was Re: klibc: [s390x] SIGSEGV in mksh testcase funsub-2) Thorsten Glaser <tg@debian.org> - 2021-05-03 23:00 +0200
      Processed: Use of $v10 register (was Re: klibc: [s390x] SIGSEGV  in mksh testcase funsub-2) "Debian Bug Tracking System" <owner@bugs.debian.org> - 2021-05-03 23:00 +0200
      Bug#943425: Debian #943425: [s390x] setjmp/longjmp do not save/restore all registers in use Thorsten Glaser <tg@mirbsd.de> - 2021-05-05 05:00 +0200
        Bug#943425: [klibc] Bug#943425: Debian #943425: klibc: [s390x] setjmp/longjmp do not save/restore all registers in use Thorsten Glaser <tg@mirbsd.de> - 2021-05-06 00:30 +0200

#71205 — Bug#943425: klibc: [s390x] SIGSEGV in mksh testcase funsub-2

FromThorsten Glaser <tg@debian.org>
Date2021-05-03 22:20 +0200
SubjectBug#943425: klibc: [s390x] SIGSEGV in mksh testcase funsub-2
Message-ID<CaNcS-1DV-13@gated-at.bofh.it>
Package: libklibc-dev
Version: 2.0.8-6
Followup-For: Bug #943425
X-Debbugs-Cc: tg@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

[toc] | [next] | [standalone]


#71207 — Bug#943425: Use of $v10 register (was Re: klibc: [s390x] SIGSEGV in mksh testcase funsub-2)

FromThorsten Glaser <tg@debian.org>
Date2021-05-03 23:00 +0200
SubjectBug#943425: Use of $v10 register (was Re: klibc: [s390x] SIGSEGV in mksh testcase funsub-2)
Message-ID<CaNPA-1R6-7@gated-at.bofh.it>
In reply to#71205
retitle 943425 klibc: [s390x] setjmp/longjmp do not save/restore all registers in use
# because this affects a release architecture
severity 943425 serious
thanks

Recapping for the benefit of d-s390@l.d.o:

> The code in question (where it crashes) is thus:

>    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);

> 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():

[…]
>    2104         if (!kshsetjmp(e->jbuf))
>    2105                 execute(t, XXCOM | XERROK, NULL);
[…]

kshsetjmp(x) is sigsetjmp(x,0) (though klibc ignores the 0).

execute() calls siglongjmp().

> - 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:

[…]
> 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) 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.
[…]
> Breakpoint 2, comsub (fn=14, cp=0x0, xp=<synthetic pointer>) at ../../eval.c:1609
> 1609                    subst_exstat = exstat & 0xFF;
[…]
> (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}

------------------------------------------------------------------

So, setjmp/longjmp in klibc save f1/f3/f5/f7 (as shown on Wikipedia
https://en.wikipedia.org/wiki/Calling_convention#IBM_System/360_and_successors
“the z/Architecture ABI,[11] used in Linux” a page down), while
glibc’s save f8–f15 instead.

https://share.confex.com/share/124/webprogram/Handout/Session16897/SHARE_Seattle_2015_SIMD.pdf
shows that the vector registers overlap and extend the FPU registers.

(gdb) info float
[…]
f10            2.172907066248134e-311 (raw 0x000003fffdfe9768)
(gdb) print shf
$2 = (struct shf *) 0x3fffdfe9768

The real questions here are:

• is register v10 (vector extension) even supposed to be used?
• klibc does not really support the FPU anyway
• the half of v10 that equals f10 just HAPPENS to be saved by
  glibc, but what if the upper half, that is outside of the FPU,
  is used?
• where *is* the s390x̲ ABI documented anyway? syscall(2) has the
  kernel side only

Building with -mno-vx does not seem to help, %f* are still in
the .s files generated by gcc.

So I assume klibc should save registers f8–15 on s390x but what
happened to f1/f3/f5/f7?

Thanks,
//mirabilos
-- 
[17:15:07] Lukas Degener: Kleines Asterix-Latinum für Softwaretechniker:
	   veni, vidi, fixi(t) ;-)

[toc] | [prev] | [next] | [standalone]


#71208 — Processed: Use of $v10 register (was Re: klibc: [s390x] SIGSEGV in mksh testcase funsub-2)

From"Debian Bug Tracking System" <owner@bugs.debian.org>
Date2021-05-03 23:00 +0200
SubjectProcessed: Use of $v10 register (was Re: klibc: [s390x] SIGSEGV in mksh testcase funsub-2)
Message-ID<CaNPA-1R6-11@gated-at.bofh.it>
In reply to#71207
Processing commands for control@bugs.debian.org:

> retitle 943425 klibc: [s390x] setjmp/longjmp do not save/restore all registers in use
Bug #943425 [libklibc-dev] klibc: [s390x] SIGSEGV in mksh testcase funsub-2
Changed Bug title to 'klibc: [s390x] setjmp/longjmp do not save/restore all registers in use' from 'klibc: [s390x] SIGSEGV in mksh testcase funsub-2'.
> # because this affects a release architecture
> severity 943425 serious
Bug #943425 [libklibc-dev] klibc: [s390x] setjmp/longjmp do not save/restore all registers in use
Severity set to 'serious' from 'normal'
> thanks
Stopping processing here.

Please contact me if you need assistance.
-- 
943425: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=943425
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems

[toc] | [prev] | [next] | [standalone]


#71222 — Bug#943425: Debian #943425: [s390x] setjmp/longjmp do not save/restore all registers in use

FromThorsten Glaser <tg@mirbsd.de>
Date2021-05-05 05:00 +0200
SubjectBug#943425: Debian #943425: [s390x] setjmp/longjmp do not save/restore all registers in use
Message-ID<CbfVv-21l-1@gated-at.bofh.it>
In reply to#71207
Dixi quod…

>Jessica Clarke brought out docs saying f8‥f15 must be saved, the
>other FPU registers not:

This needs to be fixed in klibc.

>>• klibc does not really support the FPU anyway
>
>… GCC chooses to allocate an FPU register for a pointer value.

This is a curiosity.

>>• the half of v10 that equals f10 just HAPPENS to be saved by
>>  glibc, but what if the upper half, that is outside of the FPU,
>>  is used?
>
>The question here is, does GCC only use the halves of the half
>of the vector registers that match the FPU registers?

04:41⎜«jrtc27:#debian-x32» hephaistor: re s390x vector registers, reading the gcc and llvm sources they're
     ⎜    all call-clobbered by default, only the float parts are call-saved
04:41⎜«jrtc27:#debian-x32» so that's why setjmp/longjmp don't need to save/restore them
04:42⎜«jrtc27:#debian-x32» there *is* a vector calling convention, but it's not the default for the ABI,
     ⎜    it's opt-in, and setjmp/longjmp won't be annotated as such

So we indeed need to only save the registers glibc does.

>@klibc list: as indicated earlier, I can provide a patch if needed
>(though it should be obvious).

bye,
//mirabilos
-- 
[00:02] <Vutral> gecko: benutzt du emacs ?
[00:03] <gecko> nö          [00:03] <gecko> nur n normalen mac
[00:04] <Vutral> argl       [00:04] <Vutral> ne den editor
	-- Vutral und gecko2 in #deutsch (NB: Editor? Betriebssystem.)

[toc] | [prev] | [next] | [standalone]


#71224 — Bug#943425: [klibc] Bug#943425: Debian #943425: klibc: [s390x] setjmp/longjmp do not save/restore all registers in use

FromThorsten Glaser <tg@mirbsd.de>
Date2021-05-06 00:30 +0200
SubjectBug#943425: [klibc] Bug#943425: Debian #943425: klibc: [s390x] setjmp/longjmp do not save/restore all registers in use
Message-ID<CbybL-4Iv-3@gated-at.bofh.it>
In reply to#71222

[Multipart message — attachments visible in raw view] — view raw

tags 943425 + patch
tags 988027 + patch
thanks

Dixi quod…

>Patches for klibc upstream git attched; I’m currently trying to test
>them, will report.

This was really tricky given we can’t install patched B-Ds on
porterboxen, but I managed. I can confirm this fixes my issue.

bye,
//mirabilos
-- 
<diogenese> Beware of ritual lest you forget the meaning behind it.
<igli> yeah but it means if you really care about something, don't
    ritualise it, or you will lose it. don't fetishise it, don't
    obsess. or you'll forget why you love it in the first place.

[toc] | [prev] | [standalone]


Back to top | Article view | linux.debian.kernel


csiph-web