#994510 libunwind8 abuses setcontext() causing SIGSEGV on i386 with glibc >= 2.32

Package:
libunwind8
Source:
libunwind
Description:
library to determine the call-chain of a program - runtime
Submitter:
Aurelien Jarno
Date:
2025-04-30 13:03:01 UTC
Severity:
grave
Tags:
#994510#5
Date:
2021-09-16 20:12:56 UTC
From:
To:
Following the glibc 2.32 upload to unstable, the autopkgtest of the
rspamd package fails on i386, due to a segmentation fault when starting
the daemon [1].

After digging, it appears that the problem is due to libunwind and the
following upstream glibc change [2]:

| commit 15eab1e3e89129ab3ed03f5bdc3415b26e9caeb9 (master)
| Author: H.J. Lu <hjl.tools@gmail.com>
| Date:   Sat Feb 1 05:44:55 2020 -0800
|
|     i386: Don't unnecessarily save and restore EAX, ECX and EDX [BZ# 25262]
|
|     On i386, since EAX, ECX and EDX are caller-saved, there are no need
|     to save and restore EAX, ECX and EDX in getcontext, setcontext and
|     swapcontext.  They just need to clear EAX on success.  The extra
|     scratch registers are needed to enable CET.
|
|     Tested on i386.
|
|     Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>


Basically EAX, ECX and EDX and are not saved anymore across a
getcontext() / setcontext() sequence, and more importantly they are not
restored in setcontext() which is used by libunwind to restore a context
after an exception. In that case, all the registers have to be restored,
including the caller-saved one.

It happens that libunwind shall not have used setcontext() there, but
rather defined its own implementation like its already done for
getcontext() as the behaviour of setcontext() is unspecified when passed
an ucp argument obtained from different sources than getcontext() or
makecontext(). Quoting the GNU libc manual:

| If the context was created by a call to a signal handler or from any
| other source then the behaviour of setcontext is unspecified.

Quoting POSIX.1-2004 (last version before it got removed):

| The effects of passing a ucp argument obtained from any other source
| are unspecified.

Note that upstream bug #69 might be relevant there [3].


[1] https://ci.debian.net/data/autopkgtest/testing/i386/r/rspamd/15290363/log.gz
[2] https://sourceware.org/git/?p=glibc.git;a=commit;h=15eab1e3e89129ab3ed03f5bdc3415b26e9caeb9
[3] https://github.com/libunwind/libunwind/issues/69

#994510#18
Date:
2025-04-26 13:43:05 UTC
From:
To:
tags 994510 + patch
thanks

Hi,

I've attached a patch that does the same difference as the glibc change.

An alternative is that we also create a setcontext.

I can't reproduce the original issue, so I can't check if this fixed
anything.


Kurt

#994510#25
Date:
2025-04-27 10:58:06 UTC
From:
To:
tags 994510 - sid trixie experimental
tags 994510 + bullseye
thanks

Thinking about this some more, I don't see why the patch would fix
anything. But it also shoudln't hurt. Without the patch we just
store things that aren't restored by setcontext anymore.

I also don't see a CI problem in rspamd in testing or unstable,
only in stable or unstable.


Kurt

#994510#34
Date:
2025-04-27 20:28:24 UTC
From:
To:
I don't think it is correct. Contrary to the getcontext/setcontext
functions, an exception can happen at any moment, and not always around
a function call. Therefore it is not possible to rely on that to not
restore caller-saved registers.

Sounds indeed the way to go.

Regards
Aurelien

#994510#39
Date:
2025-04-28 19:59:23 UTC
From:
To:
I have just checked the status using a trixie system, and rebuilding
glibc without i386/local-setcontext-revert-eax-ecx-edx.patch.

I am able to reproduce the issue with the rspamd version from bookworm
(3.4-1), but not with the version from trixie (3.8.1-1.2) or sid
(3.11.1-2).

Regards
Aurelien