[v5] aarch64: enforce >=64K guard size
Commit Message
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. If the stack probe interval
is larger than a page size on a target then ARCH_MIN_GUARD_SIZE can
be defined to get large enough stack guard on libc allocated stacks.
The patch does not affect threads with user allocated stacks.
---
v5:
- rebased on master.
- remove ChangeLog, mention ARCH_MIN_GUARD_SIZE in the commit.
- define ARCH_MIN_GUARD_SIZE on new targets (csky and arc).
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
---
nptl/allocatestack.c | 14 ++++++++++++--
sysdeps/aarch64/nptl/pthreaddef.h | 3 +++
sysdeps/alpha/nptl/pthreaddef.h | 3 +++
sysdeps/arc/nptl/pthreaddef.h | 3 +++
sysdeps/arm/nptl/pthreaddef.h | 3 +++
sysdeps/csky/nptl/pthreaddef.h | 3 +++
sysdeps/hppa/nptl/pthreaddef.h | 3 +++
sysdeps/i386/nptl/pthreaddef.h | 3 +++
sysdeps/ia64/nptl/pthreaddef.h | 3 +++
sysdeps/m68k/nptl/pthreaddef.h | 3 +++
sysdeps/microblaze/nptl/pthreaddef.h | 3 +++
sysdeps/mips/nptl/pthreaddef.h | 3 +++
sysdeps/nios2/nptl/pthreaddef.h | 3 +++
sysdeps/powerpc/nptl/pthreaddef.h | 3 +++
sysdeps/riscv/nptl/pthreaddef.h | 3 +++
sysdeps/s390/nptl/pthreaddef.h | 3 +++
sysdeps/sh/nptl/pthreaddef.h | 3 +++
sysdeps/sparc/sparc32/pthreaddef.h | 3 +++
sysdeps/sparc/sparc64/pthreaddef.h | 3 +++
sysdeps/x86_64/nptl/pthreaddef.h | 3 +++
20 files changed, 69 insertions(+), 2 deletions(-)
Comments
* 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.
>
> On other targets the patch has no effect. If the stack probe interval
> is larger than a page size on a target then ARCH_MIN_GUARD_SIZE can
> be defined to get large enough stack guard on libc allocated stacks.
>
> The patch does not affect threads with user allocated stacks.
I think this is okay. I checked that all architectures still build.
I filed bug 26691 to help with tracking the backports. Would you please
reference this bug in your commit message?
Thanks,
Florian
The 10/01/2020 17:13, 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.
> >
> > On other targets the patch has no effect. If the stack probe interval
> > is larger than a page size on a target then ARCH_MIN_GUARD_SIZE can
> > be defined to get large enough stack guard on libc allocated stacks.
> >
> > The patch does not affect threads with user allocated stacks.
>
> I think this is okay. I checked that all architectures still build.
> I filed bug 26691 to help with tracking the backports. Would you please
> reference this bug in your commit message?
ok, committed at 238032ead6f34c41542890b968d973eb5c839673
thanks for checking.
@@ -521,6 +521,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
@@ -531,8 +532,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;
@@ -740,7 +750,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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 8
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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