[v4] aarch64: enforce >=64K guard size

Message ID 1eee5f05-74f3-3396-6e2a-bfb149657a41@arm.com
State New, archived
Headers

Commit Message

Szabolcs Nagy July 12, 2018, 9:06 a.m. UTC
  previous discussion:
https://sourceware.org/ml/libc-alpha/2018-01/msg00267.html
i'd like to backport this to 2.28 if the gcc patches are accepted.

v4:
- gcc patches are now under review:
https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00538.html
https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00542.html
- update commit message (64K probing is the default abi).
- add riscv, remove tile.
- rebase.
v3:
- more comment in allocate_stack.
- define ARCH_MIN_GUARD_SIZE explicitly for all targets.
- rebase on top of master.
v2:
- only change guard size on aarch64
- don't report the inflated guard size

There are several compiler implementations that allow large stack
allocations to jump over the guard page at the end of the stack and
corrupt memory beyond that. See CVE-2017-1000364.

Compilers can emit code to probe the stack such that the guard page
cannot be skipped, but on aarch64 the probe interval is 64K by default
instead of the minimum supported page size (4K).

This patch enforces at least 64K guard on aarch64 unless the guard
is disabled by setting its size to 0.  For backward compatibility
reasons the increased guard is not reported, so it is only observable
by exhausting the address space or parsing /proc/self/maps on linux.

On other targets the patch has no effect.

The patch does not affect threads with user allocated stacks.

2018-07-12  Szabolcs Nagy  <szabolcs.nagy@arm.com>

	* nptl/allocatestack.c (allocate_stack): Use ARCH_MIN_GUARD_SIZE.
	* sysdeps/aarch64/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
	* sysdeps/alpha/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
	* sysdeps/arm/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
	* sysdeps/hppa/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
	* sysdeps/i386/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
	* sysdeps/ia64/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
	* sysdeps/m68k/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
	* sysdeps/microblaze/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
	* sysdeps/mips/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
	* sysdeps/nios2/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
	* sysdeps/powerpc/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
	* sysdeps/riscv/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
	* sysdeps/s390/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
	* sysdeps/sh/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
	* sysdeps/sparc/sparc32/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
	* sysdeps/sparc/sparc64/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
	* sysdeps/x86_64/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
  

Comments

Florian Weimer July 14, 2018, 2:02 p.m. UTC | #1
* Szabolcs Nagy:

> There are several compiler implementations that allow large stack
> allocations to jump over the guard page at the end of the stack and
> corrupt memory beyond that. See CVE-2017-1000364.
>
> Compilers can emit code to probe the stack such that the guard page
> cannot be skipped, but on aarch64 the probe interval is 64K by default
> instead of the minimum supported page size (4K).
>
> This patch enforces at least 64K guard on aarch64 unless the guard
> is disabled by setting its size to 0.  For backward compatibility
> reasons the increased guard is not reported, so it is only observable
> by exhausting the address space or parsing /proc/self/maps on linux.

Is there anything special in the aarch64 probing sequence that
*requires* that the guard is 64 KiB, or is it just that it is not
effective if it is not?
  
Szabolcs Nagy July 16, 2018, 8:42 a.m. UTC | #2
On 14/07/18 15:02, Florian Weimer wrote:
> * Szabolcs Nagy:
> 
>> There are several compiler implementations that allow large stack
>> allocations to jump over the guard page at the end of the stack and
>> corrupt memory beyond that. See CVE-2017-1000364.
>>
>> Compilers can emit code to probe the stack such that the guard page
>> cannot be skipped, but on aarch64 the probe interval is 64K by default
>> instead of the minimum supported page size (4K).
>>
>> This patch enforces at least 64K guard on aarch64 unless the guard
>> is disabled by setting its size to 0.  For backward compatibility
>> reasons the increased guard is not reported, so it is only observable
>> by exhausting the address space or parsing /proc/self/maps on linux.
> 
> Is there anything special in the aarch64 probing sequence that
> *requires* that the guard is 64 KiB, or is it just that it is not
> effective if it is not?
> 

it's not effective (the probe interval is 64k)
  
Florian Weimer July 16, 2018, 9:35 a.m. UTC | #3
* Szabolcs Nagy:

> On 14/07/18 15:02, Florian Weimer wrote:
>> * Szabolcs Nagy:
>> 
>>> There are several compiler implementations that allow large stack
>>> allocations to jump over the guard page at the end of the stack and
>>> corrupt memory beyond that. See CVE-2017-1000364.
>>>
>>> Compilers can emit code to probe the stack such that the guard page
>>> cannot be skipped, but on aarch64 the probe interval is 64K by default
>>> instead of the minimum supported page size (4K).
>>>
>>> This patch enforces at least 64K guard on aarch64 unless the guard
>>> is disabled by setting its size to 0.  For backward compatibility
>>> reasons the increased guard is not reported, so it is only observable
>>> by exhausting the address space or parsing /proc/self/maps on linux.
>> 
>> Is there anything special in the aarch64 probing sequence that
>> *requires* that the guard is 64 KiB, or is it just that it is not
>> effective if it is not?
>> 
>
> it's not effective (the probe interval is 64k)

Then I don't understand why it's necessary to override an explicitly
specified guard size.  Changing the default should be sufficient.
  
Szabolcs Nagy July 16, 2018, 10:39 a.m. UTC | #4
On 16/07/18 10:35, Florian Weimer wrote:
> * Szabolcs Nagy:
> 
>> On 14/07/18 15:02, Florian Weimer wrote:
>>> * Szabolcs Nagy:
>>>
>>>> There are several compiler implementations that allow large stack
>>>> allocations to jump over the guard page at the end of the stack and
>>>> corrupt memory beyond that. See CVE-2017-1000364.
>>>>
>>>> Compilers can emit code to probe the stack such that the guard page
>>>> cannot be skipped, but on aarch64 the probe interval is 64K by default
>>>> instead of the minimum supported page size (4K).
>>>>
>>>> This patch enforces at least 64K guard on aarch64 unless the guard
>>>> is disabled by setting its size to 0.  For backward compatibility
>>>> reasons the increased guard is not reported, so it is only observable
>>>> by exhausting the address space or parsing /proc/self/maps on linux.
>>>
>>> Is there anything special in the aarch64 probing sequence that
>>> *requires* that the guard is 64 KiB, or is it just that it is not
>>> effective if it is not?
>>>
>>
>> it's not effective (the probe interval is 64k)
> 
> Then I don't understand why it's necessary to override an explicitly
> specified guard size.  Changing the default should be sufficient.
> 

on aarch64 safe behaviour is only guaranteed if the
guard is >=64k, a smaller guard does not guard against
stack overflow, so what's the point of a smaller guard?

user code cannot reason about stack usage in any sensible
way so it cannot be smart about the guard size, yet there
is lot of existing code setting the guard size explicitly
to a single page.  the only effect of granting those
settings is to make code unsafe on systems with smaller
than 64k page size.

with the proposed patch all conforming posix code is safe
in case of stack overflow (segfaults), except code that
runs on user allocated stack, i think this is a reasonable
guarantee to provide.
  
Alexander Monakov July 16, 2018, 12:59 p.m. UTC | #5
On Mon, 16 Jul 2018, Szabolcs Nagy wrote:
> on aarch64 safe behaviour is only guaranteed if the
> guard is >=64k, a smaller guard does not guard against
> stack overflow, so what's the point of a smaller guard?
> 
> user code cannot reason about stack usage in any sensible
> way so it cannot be smart about the guard size, yet there
> is lot of existing code setting the guard size explicitly
> to a single page.  the only effect of granting those
> settings is to make code unsafe on systems with smaller
> than 64k page size.

I think a better explanation is required here, because user code
can, at least in principle, ensure the following guarantees:

 - no signals will be delivered to that thread
 - no recursive call chains are possible
 - no variable-size on-stack allocations exist

in which case it is possible to compute an upper bound on worst-case
stack consumption by dumping per-function stack usage and the call graph.

I understand the "no signals" clause is not so simple, as setXid calls
implicitly deliver a signal to each thread, and it's easy to miss that.

I think there's no readily available tool to perform the above
computation, which suggests that people rarely do that in practice.

Alexander
  
Siddhesh Poyarekar July 16, 2018, 1:05 p.m. UTC | #6
On 07/16/2018 04:09 PM, Szabolcs Nagy wrote:
> on aarch64 safe behaviour is only guaranteed if the
> guard is >=64k, a smaller guard does not guard against
> stack overflow, so what's the point of a smaller guard?
> 
> user code cannot reason about stack usage in any sensible
> way so it cannot be smart about the guard size, yet there
> is lot of existing code setting the guard size explicitly
> to a single page.  the only effect of granting those
> settings is to make code unsafe on systems with smaller
> than 64k page size.

To elaborate, aarch64 has two configurations in the wild; RHEL does 64K 
pages and Debian does 4K pages but the probe interval seems to be fixed 
at 64K.  RHEL won't be affected because any stack allocation requests < 
64K will simply be rounded to 64K but Debian systems with 4K sizes will 
need this hack.

This should however also include a note in the manual to warn users 
about this behaviour.

Siddhesh
  
Siddhesh Poyarekar July 16, 2018, 1:09 p.m. UTC | #7
On 07/16/2018 06:35 PM, Siddhesh Poyarekar wrote:
> To elaborate, aarch64 has two configurations in the wild; RHEL does 64K 
> pages and Debian does 4K pages but the probe interval seems to be fixed 
> at 64K.  RHEL won't be affected because any stack allocation requests < 

Sorry, that should be guard size requests, not stack allocation requests.

Siddhesh
  
Szabolcs Nagy July 16, 2018, 1:34 p.m. UTC | #8
On 16/07/18 13:59, Alexander Monakov wrote:
> On Mon, 16 Jul 2018, Szabolcs Nagy wrote:
>> on aarch64 safe behaviour is only guaranteed if the
>> guard is >=64k, a smaller guard does not guard against
>> stack overflow, so what's the point of a smaller guard?
>>
>> user code cannot reason about stack usage in any sensible
>> way so it cannot be smart about the guard size, yet there
>> is lot of existing code setting the guard size explicitly
>> to a single page.  the only effect of granting those
>> settings is to make code unsafe on systems with smaller
>> than 64k page size.
> 
> I think a better explanation is required here, because user code
> can, at least in principle, ensure the following guarantees:
> 
>   - no signals will be delivered to that thread
>   - no recursive call chains are possible
>   - no variable-size on-stack allocations exist
> 
> in which case it is possible to compute an upper bound on worst-case
> stack consumption by dumping per-function stack usage and the call graph.
> 

(recursion is actually not an issue for the guard as it does not
affect the maximum stack increment.)

such bound can only be computed for a particular code generation,
(so relying on it is very fragile: same target abi, same compiler,
different cflags and the user computed guard size is no longer
valid) and it requires complete control of the code running on
the thread, including the c runtime, which an application cannot
do (unless the c runtime gives guarantees about worst-case stack
increment for its entry points, which glibc does not do)

> I understand the "no signals" clause is not so simple, as setXid calls
> implicitly deliver a signal to each thread, and it's easy to miss that.
> 
> I think there's no readily available tool to perform the above
> computation, which suggests that people rarely do that in practice.
> 

implementation internal things can always consume stack in
undefined ways (be it signals or whatever) because the stack
is not part of the language standard and stack usage is not
observable in any portable way.

of course in practice it would be bad if the implementation
randomly allocated large chunks of stack space, but users
should not make assumptions about stack usage.

but the real reason why it's ok to round up the user setting
is that there is no practical difference between a 4k and 64k
address space hole on aarch64: it won't cause resource
exhaustion issues, so i see no drawback, it only makes things
safer.

> Alexander
>
  
Szabolcs Nagy July 16, 2018, 2:10 p.m. UTC | #9
On 16/07/18 10:35, Florian Weimer wrote:
> * Szabolcs Nagy:
> 
>> On 14/07/18 15:02, Florian Weimer wrote:
>>> * Szabolcs Nagy:
>>>
>>>> There are several compiler implementations that allow large stack
>>>> allocations to jump over the guard page at the end of the stack and
>>>> corrupt memory beyond that. See CVE-2017-1000364.
>>>>
>>>> Compilers can emit code to probe the stack such that the guard page
>>>> cannot be skipped, but on aarch64 the probe interval is 64K by default
>>>> instead of the minimum supported page size (4K).
>>>>
>>>> This patch enforces at least 64K guard on aarch64 unless the guard
>>>> is disabled by setting its size to 0.  For backward compatibility
>>>> reasons the increased guard is not reported, so it is only observable
>>>> by exhausting the address space or parsing /proc/self/maps on linux.
>>>
>>> Is there anything special in the aarch64 probing sequence that
>>> *requires* that the guard is 64 KiB, or is it just that it is not
>>> effective if it is not?
>>>
>>
>> it's not effective (the probe interval is 64k)
> 
> Then I don't understand why it's necessary to override an explicitly
> specified guard size.  Changing the default should be sufficient.
> 

oh and earlier posix standards required the default
guard size to be 1 page, which is observable via
current pthread_{get}attr* apis.
(nptl/tst-attr2.c even tests for this)

so changing the default would break conforming code
unless we change the logic around how the attr apis
report the size.
  
Szabolcs Nagy Oct. 4, 2018, 1:23 p.m. UTC | #10
On 12/07/18 10:06, Szabolcs Nagy wrote:
> previous discussion:
> https://sourceware.org/ml/libc-alpha/2018-01/msg00267.html
> i'd like to backport this to 2.28 if the gcc patches are accepted.
> 
> v4:
> - gcc patches are now under review:
> https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00538.html
> https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00542.html
> - update commit message (64K probing is the default abi).
> - add riscv, remove tile.
> - rebase.

ping.

gcc patches are committed at r264757

> v3:
> - more comment in allocate_stack.
> - define ARCH_MIN_GUARD_SIZE explicitly for all targets.
> - rebase on top of master.
> v2:
> - only change guard size on aarch64
> - don't report the inflated guard size
> 
> There are several compiler implementations that allow large stack
> allocations to jump over the guard page at the end of the stack and
> corrupt memory beyond that. See CVE-2017-1000364.
> 
> Compilers can emit code to probe the stack such that the guard page
> cannot be skipped, but on aarch64 the probe interval is 64K by default
> instead of the minimum supported page size (4K).
> 
> This patch enforces at least 64K guard on aarch64 unless the guard
> is disabled by setting its size to 0.  For backward compatibility
> reasons the increased guard is not reported, so it is only observable
> by exhausting the address space or parsing /proc/self/maps on linux.
> 
> On other targets the patch has no effect.
> 
> The patch does not affect threads with user allocated stacks.
> 
> 2018-07-12  Szabolcs Nagy  <szabolcs.nagy@arm.com>
> 
>     * nptl/allocatestack.c (allocate_stack): Use ARCH_MIN_GUARD_SIZE.
>     * sysdeps/aarch64/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>     * sysdeps/alpha/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>     * sysdeps/arm/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>     * sysdeps/hppa/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>     * sysdeps/i386/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>     * sysdeps/ia64/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>     * sysdeps/m68k/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>     * sysdeps/microblaze/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>     * sysdeps/mips/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>     * sysdeps/nios2/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>     * sysdeps/powerpc/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>     * sysdeps/riscv/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>     * sysdeps/s390/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>     * sysdeps/sh/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>     * sysdeps/sparc/sparc32/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>     * sysdeps/sparc/sparc64/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>     * sysdeps/x86_64/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
  
Szabolcs Nagy Oct. 19, 2018, 4:12 p.m. UTC | #11
On 04/10/18 14:23, Szabolcs Nagy wrote:
> On 12/07/18 10:06, Szabolcs Nagy wrote:
>> previous discussion:
>> https://sourceware.org/ml/libc-alpha/2018-01/msg00267.html
>> i'd like to backport this to 2.28 if the gcc patches are accepted.
>>
>> v4:
>> - gcc patches are now under review:
>> https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00538.html
>> https://gcc.gnu.org/ml/gcc-patches/2018-07/msg00542.html
>> - update commit message (64K probing is the default abi).
>> - add riscv, remove tile.
>> - rebase.
> 
> ping.
> 
> gcc patches are committed at r264757
> 

ping.

this is needed for correctness on aarch64 with gcc-9.

>> v3:
>> - more comment in allocate_stack.
>> - define ARCH_MIN_GUARD_SIZE explicitly for all targets.
>> - rebase on top of master.
>> v2:
>> - only change guard size on aarch64
>> - don't report the inflated guard size
>>
>> There are several compiler implementations that allow large stack
>> allocations to jump over the guard page at the end of the stack and
>> corrupt memory beyond that. See CVE-2017-1000364.
>>
>> Compilers can emit code to probe the stack such that the guard page
>> cannot be skipped, but on aarch64 the probe interval is 64K by default
>> instead of the minimum supported page size (4K).
>>
>> This patch enforces at least 64K guard on aarch64 unless the guard
>> is disabled by setting its size to 0.  For backward compatibility
>> reasons the increased guard is not reported, so it is only observable
>> by exhausting the address space or parsing /proc/self/maps on linux.
>>
>> On other targets the patch has no effect.
>>
>> The patch does not affect threads with user allocated stacks.
>>
>> 2018-07-12  Szabolcs Nagy  <szabolcs.nagy@arm.com>
>>
>>     * nptl/allocatestack.c (allocate_stack): Use ARCH_MIN_GUARD_SIZE.
>>     * sysdeps/aarch64/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>>     * sysdeps/alpha/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>>     * sysdeps/arm/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>>     * sysdeps/hppa/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>>     * sysdeps/i386/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>>     * sysdeps/ia64/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>>     * sysdeps/m68k/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>>     * sysdeps/microblaze/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>>     * sysdeps/mips/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>>     * sysdeps/nios2/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>>     * sysdeps/powerpc/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>>     * sysdeps/riscv/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>>     * sysdeps/s390/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>>     * sysdeps/sh/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>>     * sysdeps/sparc/sparc32/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>>     * sysdeps/sparc/sparc64/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>>     * sysdeps/x86_64/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
>
  
Florian Weimer Sept. 30, 2020, 1:11 p.m. UTC | #12
* Szabolcs Nagy:

> 2018-07-12  Szabolcs Nagy  <szabolcs.nagy@arm.com>
>
> 	* nptl/allocatestack.c (allocate_stack): Use ARCH_MIN_GUARD_SIZE.
> 	* sysdeps/aarch64/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
> 	* sysdeps/alpha/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
> 	* sysdeps/arm/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
> 	* sysdeps/hppa/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
> 	* sysdeps/i386/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
> 	* sysdeps/ia64/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
> 	* sysdeps/m68k/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
> 	* sysdeps/microblaze/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
> 	* sysdeps/mips/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
> 	* sysdeps/nios2/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
> 	* sysdeps/powerpc/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
> 	* sysdeps/riscv/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
> 	* sysdeps/s390/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
> 	* sysdeps/sh/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
> 	* sysdeps/sparc/sparc32/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
> 	* sysdeps/sparc/sparc64/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.
> 	* sysdeps/x86_64/nptl/pthreaddef.h (ARCH_MIN_GUARD_SIZE): Define.

Would you be able to repost this against the current tree?

Given the realities on the GCC side (probe interval is 64 KiB even with
4 KiB pages), I think there's little choice left here.

Hopefully I will be able to review the implementation in a timely
manner.  I don't have any conceptual objections anymore.

Thanks,
Florian
  

Patch

diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
index f9e053f9e5..90fa3ed000 100644
--- a/nptl/allocatestack.c
+++ b/nptl/allocatestack.c
@@ -520,6 +520,7 @@  allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
     {
       /* Allocate some anonymous memory.  If possible use the cache.  */
       size_t guardsize;
+      size_t reported_guardsize;
       size_t reqsize;
       void *mem;
       const int prot = (PROT_READ | PROT_WRITE
@@ -530,8 +531,17 @@  allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
       assert (size != 0);
 
       /* Make sure the size of the stack is enough for the guard and
-	 eventually the thread descriptor.  */
+	 eventually the thread descriptor.  On some targets there is
+	 a minimum guard size requirement, ARCH_MIN_GUARD_SIZE, so
+	 internally enforce it (unless the guard was disabled), but
+	 report the original guard size for backward compatibility:
+	 before POSIX 2008 the guardsize was specified to be one page
+	 by default which is observable via pthread_attr_getguardsize
+	 and pthread_getattr_np.  */
       guardsize = (attr->guardsize + pagesize_m1) & ~pagesize_m1;
+      reported_guardsize = guardsize;
+      if (guardsize > 0 && guardsize < ARCH_MIN_GUARD_SIZE)
+	guardsize = ARCH_MIN_GUARD_SIZE;
       if (guardsize < attr->guardsize || size + guardsize < guardsize)
 	/* Arithmetic overflow.  */
 	return EINVAL;
@@ -737,7 +747,7 @@  allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
       /* The pthread_getattr_np() calls need to get passed the size
 	 requested in the attribute, regardless of how large the
 	 actually used guardsize is.  */
-      pd->reported_guardsize = guardsize;
+      pd->reported_guardsize = reported_guardsize;
     }
 
   /* Initialize the lock.  We have to do this unconditionally since the
diff --git a/sysdeps/aarch64/nptl/pthreaddef.h b/sysdeps/aarch64/nptl/pthreaddef.h
index 32f729ada1..da2c5de317 100644
--- a/sysdeps/aarch64/nptl/pthreaddef.h
+++ b/sysdeps/aarch64/nptl/pthreaddef.h
@@ -19,6 +19,9 @@ 
 /* Default stack size.  */
 #define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024)
 
+/* Minimum guard size.  */
+#define ARCH_MIN_GUARD_SIZE (64 * 1024)
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN 16
 
diff --git a/sysdeps/alpha/nptl/pthreaddef.h b/sysdeps/alpha/nptl/pthreaddef.h
index f505583600..c0ad663f1c 100644
--- a/sysdeps/alpha/nptl/pthreaddef.h
+++ b/sysdeps/alpha/nptl/pthreaddef.h
@@ -18,6 +18,9 @@ 
 /* Default stack size.  */
 #define ARCH_STACK_DEFAULT_SIZE	(4 * 1024 * 1024)
 
+/* Minimum guard size.  */
+#define ARCH_MIN_GUARD_SIZE 0
+
 /* Required stack pointer alignment at beginning.  The ABI requires 16.  */
 #define STACK_ALIGN		16
 
diff --git a/sysdeps/arm/nptl/pthreaddef.h b/sysdeps/arm/nptl/pthreaddef.h
index f8d821d6f2..22d128d75f 100644
--- a/sysdeps/arm/nptl/pthreaddef.h
+++ b/sysdeps/arm/nptl/pthreaddef.h
@@ -18,6 +18,9 @@ 
 /* Default stack size.  */
 #define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024)
 
+/* Minimum guard size.  */
+#define ARCH_MIN_GUARD_SIZE 0
+
 /* Required stack pointer alignment at beginning.  SSE requires 16
    bytes.  */
 #define STACK_ALIGN		16
diff --git a/sysdeps/hppa/nptl/pthreaddef.h b/sysdeps/hppa/nptl/pthreaddef.h
index cdb55687f5..251513f60a 100644
--- a/sysdeps/hppa/nptl/pthreaddef.h
+++ b/sysdeps/hppa/nptl/pthreaddef.h
@@ -18,6 +18,9 @@ 
 /* Default stack size.  */
 #define ARCH_STACK_DEFAULT_SIZE	(8 * 1024 * 1024)
 
+/* Minimum guard size.  */
+#define ARCH_MIN_GUARD_SIZE 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN		64
 
diff --git a/sysdeps/i386/nptl/pthreaddef.h b/sysdeps/i386/nptl/pthreaddef.h
index deacd92edf..51e098dbcd 100644
--- a/sysdeps/i386/nptl/pthreaddef.h
+++ b/sysdeps/i386/nptl/pthreaddef.h
@@ -19,6 +19,9 @@ 
 /* Default stack size.  */
 #define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024)
 
+/* Minimum guard size.  */
+#define ARCH_MIN_GUARD_SIZE 0
+
 /* Required stack pointer alignment at beginning.  SSE requires 16
    bytes.  */
 #define STACK_ALIGN		16
diff --git a/sysdeps/ia64/nptl/pthreaddef.h b/sysdeps/ia64/nptl/pthreaddef.h
index 09f9acf25c..2c5a2da373 100644
--- a/sysdeps/ia64/nptl/pthreaddef.h
+++ b/sysdeps/ia64/nptl/pthreaddef.h
@@ -18,6 +18,9 @@ 
 /* Default stack size.  */
 #define ARCH_STACK_DEFAULT_SIZE	(32 * 1024 * 1024)
 
+/* Minimum guard size.  */
+#define ARCH_MIN_GUARD_SIZE 0
+
 /* IA-64 uses a normal stack and a register stack.  */
 #define NEED_SEPARATE_REGISTER_STACK
 
diff --git a/sysdeps/m68k/nptl/pthreaddef.h b/sysdeps/m68k/nptl/pthreaddef.h
index 68fc37a394..84092356e4 100644
--- a/sysdeps/m68k/nptl/pthreaddef.h
+++ b/sysdeps/m68k/nptl/pthreaddef.h
@@ -19,6 +19,9 @@ 
 /* Default stack size.  */
 #define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024)
 
+/* Minimum guard size.  */
+#define ARCH_MIN_GUARD_SIZE 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN		16
 
diff --git a/sysdeps/microblaze/nptl/pthreaddef.h b/sysdeps/microblaze/nptl/pthreaddef.h
index 12fac81398..377f751b5e 100644
--- a/sysdeps/microblaze/nptl/pthreaddef.h
+++ b/sysdeps/microblaze/nptl/pthreaddef.h
@@ -22,6 +22,9 @@ 
 /* Default stack size.  */
 #define ARCH_STACK_DEFAULT_SIZE  (2 * 1024 * 1024)
 
+/* Minimum guard size.  */
+#define ARCH_MIN_GUARD_SIZE 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN         16
 
diff --git a/sysdeps/mips/nptl/pthreaddef.h b/sysdeps/mips/nptl/pthreaddef.h
index 7b1283ae64..936e517593 100644
--- a/sysdeps/mips/nptl/pthreaddef.h
+++ b/sysdeps/mips/nptl/pthreaddef.h
@@ -18,6 +18,9 @@ 
 /* Default stack size.  */
 #define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024)
 
+/* Minimum guard size.  */
+#define ARCH_MIN_GUARD_SIZE 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN		16
 
diff --git a/sysdeps/nios2/nptl/pthreaddef.h b/sysdeps/nios2/nptl/pthreaddef.h
index b70d1d17b3..34862beebf 100644
--- a/sysdeps/nios2/nptl/pthreaddef.h
+++ b/sysdeps/nios2/nptl/pthreaddef.h
@@ -19,6 +19,9 @@ 
 /* Default stack size.  */
 #define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024)
 
+/* Minimum guard size.  */
+#define ARCH_MIN_GUARD_SIZE 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN		4
 
diff --git a/sysdeps/powerpc/nptl/pthreaddef.h b/sysdeps/powerpc/nptl/pthreaddef.h
index 83416849ee..e7f0617d51 100644
--- a/sysdeps/powerpc/nptl/pthreaddef.h
+++ b/sysdeps/powerpc/nptl/pthreaddef.h
@@ -18,6 +18,9 @@ 
 /* Default stack size.  */
 #define ARCH_STACK_DEFAULT_SIZE	(4 * 1024 * 1024)
 
+/* Minimum guard size.  */
+#define ARCH_MIN_GUARD_SIZE 0
+
 /* Required stack pointer alignment at beginning.  The ABI requires 16
    bytes (for both 32-bit and 64-bit PowerPC).  */
 #define STACK_ALIGN		16
diff --git a/sysdeps/riscv/nptl/pthreaddef.h b/sysdeps/riscv/nptl/pthreaddef.h
index 442422aefb..3891b26a36 100644
--- a/sysdeps/riscv/nptl/pthreaddef.h
+++ b/sysdeps/riscv/nptl/pthreaddef.h
@@ -19,6 +19,9 @@ 
 /* Default stack size.  */
 #define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024)
 
+/* Minimum guard size.  */
+#define ARCH_MIN_GUARD_SIZE 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN		16
 
diff --git a/sysdeps/s390/nptl/pthreaddef.h b/sysdeps/s390/nptl/pthreaddef.h
index 410ae7b896..7aa0fc7617 100644
--- a/sysdeps/s390/nptl/pthreaddef.h
+++ b/sysdeps/s390/nptl/pthreaddef.h
@@ -18,6 +18,9 @@ 
 /* Default stack size.  */
 #define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024)
 
+/* Minimum guard size.  */
+#define ARCH_MIN_GUARD_SIZE 0
+
 /* Required stack pointer alignment at beginning.  SSE requires 16
    bytes.  */
 #define STACK_ALIGN		16
diff --git a/sysdeps/sh/nptl/pthreaddef.h b/sysdeps/sh/nptl/pthreaddef.h
index 97c7e07100..8a295a991c 100644
--- a/sysdeps/sh/nptl/pthreaddef.h
+++ b/sysdeps/sh/nptl/pthreaddef.h
@@ -20,6 +20,9 @@ 
 /* Default stack size.  */
 #define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024)
 
+/* Minimum guard size.  */
+#define ARCH_MIN_GUARD_SIZE 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN		8
 
diff --git a/sysdeps/sparc/sparc32/pthreaddef.h b/sysdeps/sparc/sparc32/pthreaddef.h
index 57fe5fd514..798c8837ea 100644
--- a/sysdeps/sparc/sparc32/pthreaddef.h
+++ b/sysdeps/sparc/sparc32/pthreaddef.h
@@ -18,6 +18,9 @@ 
 /* Default stack size.  */
 #define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024)
 
+/* Minimum guard size.  */
+#define ARCH_MIN_GUARD_SIZE 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN		16
 
diff --git a/sysdeps/sparc/sparc64/pthreaddef.h b/sysdeps/sparc/sparc64/pthreaddef.h
index 62e2290b23..b9f738f6a9 100644
--- a/sysdeps/sparc/sparc64/pthreaddef.h
+++ b/sysdeps/sparc/sparc64/pthreaddef.h
@@ -18,6 +18,9 @@ 
 /* Default stack size.  */
 #define ARCH_STACK_DEFAULT_SIZE	(4 * 1024 * 1024)
 
+/* Minimum guard size.  */
+#define ARCH_MIN_GUARD_SIZE 0
+
 /* Required stack pointer alignment at beginning.  */
 #define STACK_ALIGN		16
 
diff --git a/sysdeps/x86_64/nptl/pthreaddef.h b/sysdeps/x86_64/nptl/pthreaddef.h
index 036deb5772..0188113fb7 100644
--- a/sysdeps/x86_64/nptl/pthreaddef.h
+++ b/sysdeps/x86_64/nptl/pthreaddef.h
@@ -19,6 +19,9 @@ 
 /* Default stack size.  */
 #define ARCH_STACK_DEFAULT_SIZE	(2 * 1024 * 1024)
 
+/* Minimum guard size.  */
+#define ARCH_MIN_GUARD_SIZE 0
+
 /* Required stack pointer alignment at beginning.  SSE requires 16
    bytes.  */
 #define STACK_ALIGN		16