From patchwork Thu Jul 12 09:06:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Szabolcs Nagy X-Patchwork-Id: 28325 Received: (qmail 126652 invoked by alias); 12 Jul 2018 09:07:06 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 126638 invoked by uid 89); 12 Jul 2018 09:07:06 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-25.0 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_PASS, SPF_PASS autolearn=ham version=3.3.2 spammy=inflated, exhausting X-HELO: EUR01-HE1-obe.outbound.protection.outlook.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=armh.onmicrosoft.com; s=selector1-arm-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=U4NArM3cBbQ8824WTUTEzkElvgtD06fOwh76i3fkdEM=; b=qIBI5Ev1FLHVQ8CRVUdGZZFzHtzDCKtgoxioZYGsGeUe+aVzk37dLJLTSAhHgT3RlBJc+4duI3wBMJKaklC4gTtxT08N56vciJ/VMCGMcaaIj4ZV+ojbN6EYVTaAIt4zCT8aF50XvigVCPYul5IyzFvOavIgBcqMdwW2Qc4vzmc= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=Szabolcs.Nagy@arm.com; Cc: nd@arm.com To: GNU C Library From: Szabolcs Nagy Subject: [PATCH v4] aarch64: enforce >=64K guard size Message-ID: <1eee5f05-74f3-3396-6e2a-bfb149657a41@arm.com> Date: Thu, 12 Jul 2018 10:06:55 +0100 User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:52.0) Gecko/20100101 Thunderbird/52.7.0 MIME-Version: 1.0 Return-Path: szabolcs.nagy@arm.com Received-SPF: None (protection.outlook.com: arm.com does not designate permitted sender hosts) 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 * 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. 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