Message ID | 20201001094458.16060-1-szabolcs.nagy@arm.com |
---|---|
State | New |
Headers | show |
Series | [v5] aarch64: enforce >=64K guard size | expand |
* 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.
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c index 4ae4b5a986..4b45f8c884 100644 --- a/nptl/allocatestack.c +++ b/nptl/allocatestack.c @@ -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 diff --git a/sysdeps/aarch64/nptl/pthreaddef.h b/sysdeps/aarch64/nptl/pthreaddef.h index 892b869fc2..b865fd5fab 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 6ec8f49f39..c710b04845 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/arc/nptl/pthreaddef.h b/sysdeps/arc/nptl/pthreaddef.h index 5c2b752bec..844b213729 100644 --- a/sysdeps/arc/nptl/pthreaddef.h +++ b/sysdeps/arc/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/arm/nptl/pthreaddef.h b/sysdeps/arm/nptl/pthreaddef.h index 5b05f2a8bd..3e21cbd39a 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/csky/nptl/pthreaddef.h b/sysdeps/csky/nptl/pthreaddef.h index 98b9546b12..f4b0b4c847 100644 --- a/sysdeps/csky/nptl/pthreaddef.h +++ b/sysdeps/csky/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 8 diff --git a/sysdeps/hppa/nptl/pthreaddef.h b/sysdeps/hppa/nptl/pthreaddef.h index 9fab974e7d..5dd4fec20d 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 65d5bc9b2e..db833351c6 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 42a95e6b24..26c509abe2 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 baca43951d..8d0253ba4c 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 c043372f44..73b4a42971 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 fa232b0c78..8305c23940 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 4ae7d4581c..590e3f8774 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 4abdc480c4..70e55b70f0 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 146c04f63a..b45359faf7 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 e087e1cddf..c218271fc3 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 12106e79e1..50cedcefa6 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 403fa3e340..41de22b3be 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 0a0841262a..363b0f9e41 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 d49848da3c..5554876bfc 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