|
|
Message-ID: <lhuqzj2danc.fsf@oldenburg.str.redhat.com> Date: Wed, 09 Sep 2026 11:41:43 +0200 From: Florian Weimer <fweimer@...hat.com> To: Pavel Labath <labath@...gle.com> Cc: libc-coord@...ts.openwall.com Subject: Re: An async-signal-safe way to get thread’s stack * Pavel Labath: > In Linux, we have pthread_getattr_np as a de-facto standard. This (in > conjunction with pthread_attr_getstack) lets us get the stack > boundary, but this approach has the problem of not working in > async-signal contexts. pthread_getattr_np is a complicated function. > E.g., the GLIBC implementation takes locks, opens files and allocates > memory, all of which are async-signal-unsafe operations. A lot of this > complexity is due to the main thread, which has a kernel-managed > dynamically expanding stack. > > Yet, there are use cases where one needs this information from inside > a signal handler. E.g. an (in process) unwinder or a profiler can use > this information to read the stack quickly, without risking a SIGSEGV. In a signal handler, you also have to deal with the switch to the alternate stack when sigaltstack is used. This information is part of the signal context, so an aysnc-signal-safe function to get stack boundaries would ideally have access to that. There are other complications. GCC supports segmented stacks, originally added for Go. There is makecontext, which can switch stacks. And there are various stackful coroutine libraries. Typically, libcs don't track any of that. We really need to clean this up for the various forms of shadow stack support because libcs are expected to manage that somehow. For the profiling use case, it might be acceptable to check address validity on page change: instead of reading the on-stack value directly, use process_vm_readv (on Linux). Further reads from the same page can be done directly. If top-of-the-stack information is available, it might be beneficial to probe multiple pages between the stack pointer and the assumed top of the stack, optimizing the common case of a contiguous stack. To make this a bit safer, the kernel could provide a process_vm_readv flag that restricts access to anonymous memory (so that the backtracing logic does not accidentally read from device memory). > I’ve added a pthread_getstack_np extension > <https://github.com/llvm/llvm-project/pull/217049> to LLVM-libc. The > function has a pthread_attr_getstack-like API. For the main thread it > behaves similar to Solaris stack_getbounds, except that it sets the > size to zero (PTHREAD_STACK_DYNAMIC_NP) unconditionally. However, > please don’t take this email as a request to adopt this API. This is > something that we created for experimentation and I’d be happy to > change that API if we come up with a better one. In fact, I am hoping > that’s exactly what will happen. I think AT_EXECFN is optional on Linux. But surely it would be possible to record the original stack pointer at the first entry point (dynamic linker startup code or static startup code)? Exposing that information should be relatively straightforward. With the process_vm_readv optimization, maybe that is already helpful? A full API would have to cover the realities of segmented stacks and coroutines, which would be quite involved (but libcs need to track this for shadow stacks at one point). Thanks, Florian
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.