From patchwork Sat Jan 21 21:23:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: linted X-Patchwork-Id: 1730089 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=uclibc-ng.org (client-ip=2a00:1828:2000:679::23; helo=helium.openadk.org; envelope-from=devel-bounces@uclibc-ng.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20210112 header.b=pSFFIgaI; dkim-atps=neutral Received: from helium.openadk.org (helium.openadk.org [IPv6:2a00:1828:2000:679::23]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4NzqDJ6cmtz23gM for ; Sun, 22 Jan 2023 08:26:06 +1100 (AEDT) Received: from helium.openadk.org (localhost [IPv6:::1]) by helium.openadk.org (Postfix) with ESMTP id D65453529FDA; Sat, 21 Jan 2023 22:25:49 +0100 (CET) Authentication-Results: helium.openadk.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20210112 header.b=pSFFIgaI; dkim-atps=neutral Received: from mail-pj1-f47.google.com (mail-pj1-f47.google.com [209.85.216.47]) by helium.openadk.org (Postfix) with ESMTPS id 0CB813529FD1 for ; Sat, 21 Jan 2023 22:24:27 +0100 (CET) Received: by mail-pj1-f47.google.com with SMTP id k10-20020a17090a590a00b0022ba875a1a4so5189977pji.3 for ; Sat, 21 Jan 2023 13:24:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=CTZxv65GUIgRAixdRPPM/LhH+ncQmu05NfpZ20XDghQ=; b=pSFFIgaIj50798ie5APx9qW/jWJMwfky8mlYWdlPSMyNVByhE2rReBae4dluaE83Kb qRHP/4vsPdj6rfemXA202Muj2eZ1kc0k8hIiy6tJmDgWS0BoRAy1z5mwsTcknVCj3QJS piN0+g3vvVmKFYl6ztPZ+1bJz0sKWTXJ5rt+G/LdtrV9PwvD1DJiqOfXRUy75IrCJHx9 juLk5JhFjoO+RdOabuUivSoUA/SytlPOsVKgfIi/EKw2HL9RirxberuZJPAVZXcG8uZb A5HBgDE7/gi0CfoBtdogI0JgznynSw1zdN44vAV4qvIUOPu6JTmLOB+wCR+bh+9RtR7s c8CA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=CTZxv65GUIgRAixdRPPM/LhH+ncQmu05NfpZ20XDghQ=; b=rnbLkJarMaUNFO8NfC1zN7/FdNNYL/p4Gha7IbqSye+3oujEshhUWsEZZVlftR0DPk LsaTVJc4VV5Lq4Sx1kt1krn2cNO9gwtV5/a5rx2Zleok8nNSej0EB5HGJvd5rM4baOFQ Chh1QMf6x1nlvPLGzZD7oilti6JOOkfJzDQDxyKVC2yixl/idfRg8MLmsa1wh5nepPwO 7jS699xKbZi5AKFeyZBewGEEBWmD7jKZOuLnwl7XqZrhvO7pd2DYtv1qn2htlE06DIS/ vomCS4xDgfCxA2qXsdMgOvlgofM/aIqBRBuWxG1PbBaD2n3eSDGqUTLYgxWU7Ikn6K5+ yzSw== X-Gm-Message-State: AFqh2kpmvZHco810mckwbdZW7edp7mcDythtPOPn3KW/Cf8KvdddMdWQ MwHdDBcBqfCgdA37Yp0iNdJ7CV2lC/cXfrvvKqXf8JHnJW5QDjDm X-Google-Smtp-Source: AMrXdXsMuv2kqqx5EWnY8eBmojtzmgKSyGfjtSXhpmC5PinEoEvKCwYQmJHub0jw4h8oXT3Gga3No1DqJxSRPqz6Wxc= X-Received: by 2002:a17:90a:3043:b0:22b:b888:c52f with SMTP id q3-20020a17090a304300b0022bb888c52fmr736801pjl.39.1674336264578; Sat, 21 Jan 2023 13:24:24 -0800 (PST) MIME-Version: 1.0 From: linted Date: Sat, 21 Jan 2023 16:23:41 -0500 Message-ID: To: devel@uclibc-ng.org Message-ID-Hash: IULDUGKDYTAN4N5NJWNROU42NG75I2ZS X-Message-ID-Hash: IULDUGKDYTAN4N5NJWNROU42NG75I2ZS X-MailFrom: linted90@gmail.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.3 Precedence: list Subject: [uclibc-ng-devel] [PATCH 1/2] fix for CVE-2022-29503 List-Id: uClibc-ng Development Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Hello, Attached is a patch addressing CVE-2022-29503. After extensive testing, I wasn't able to trigger the bug as described in the reference articles. In my testing, the only way to trigger this bug is to modify PTHREAD_THREADS_MAX to allow enough threads to exhaust the address space. It is however possible that some custom configurations have small enough memory spaces which allow this to become an issue. Since this is a problem of mmap'ing overtop of existing mapped pages, I have elected to take advantage of the new MAP_FIXED_NOREPLACE flag and its associated guidance for backporting. I define it to 0 at the top of manager.c if it isn't defined to support older kernels. From 2b11aa00bd3b637c5c96db39538952dd12514085 Mon Sep 17 00:00:00 2001 From: linted Date: Sat, 21 Jan 2023 15:22:48 -0500 Subject: [PATCH 1/2] Fix for CVE-2022-29503. Changed linux thread's stack allocation mmap to use new MAP_FIXED_NOREPLACE flag on kernels >4.17. For older kernels, a check is added to see if requested address matches the address received. If the addresses don't match, an error is returned and thread creation is aborted. Signed-off-by: linted --- libpthread/linuxthreads/manager.c | 35 ++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) + return -2; + } /* We manage to get a stack. Now see whether we need a guard and allocate it if necessary. Notice that the default attributes (stack_size = STACK_SIZE - pagesize) do not need @@ -496,9 +512,10 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, return EAGAIN; if (__pthread_handles[sseg].h_descr != NULL) continue; - if (pthread_allocate_stack(attr, thread_segment(sseg), pagesize, + int res = pthread_allocate_stack(attr, thread_segment(sseg), pagesize, &new_thread, &new_thread_bottom, - &guardaddr, &guardsize) == 0) + &guardaddr, &guardsize); + if ( res == 0) break; #ifndef __ARCH_USE_MMU__ else @@ -507,6 +524,14 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, * use the next one. However, when there is no MMU, malloc () is used. * It's waste of CPU cycles to continue to try if it fails. */ return EAGAIN; +#else + else if (res == -2) + /* When there is an MMU, if pthread_allocate_stack failed with -2, + * it indicates that we are attempting to mmap in address space which + * is already allocated. Any additional attempts will result in failure + * since we have exhausted our stack area. + */ + return EAGAIN; #endif } __pthread_handles_num++; From 2b11aa00bd3b637c5c96db39538952dd12514085 Mon Sep 17 00:00:00 2001 From: linted Date: Sat, 21 Jan 2023 15:22:48 -0500 Subject: [PATCH 1/2] Fix for CVE-2022-29503. Changed linux thread's stack allocation mmap to use new MAP_FIXED_NOREPLACE flag on kernels >4.17. For older kernels, a check is added to see if requested address matches the address received. If the addresses don't match, an error is returned and thread creation is aborted. Signed-off-by: linted --- libpthread/linuxthreads/manager.c | 35 ++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/libpthread/linuxthreads/manager.c b/libpthread/linuxthreads/manager.c index 2a1ee62af..122997b10 100644 --- a/libpthread/linuxthreads/manager.c +++ b/libpthread/linuxthreads/manager.c @@ -47,6 +47,15 @@ # define USE_SELECT #endif +/* MAP_FIXED_NOREPLACE is not supported in kernel <= 4.17 + * If it's not already defined, define it to 0. + * We check the results of mmap to ensure the correct + * results, and error out otherwise. + */ +#ifndef MAP_FIXED_NOREPLACE +#define MAP_FIXED_NOREPLACE 0 +#endif + /* Array of active threads. Entry 0 is reserved for the initial thread. */ struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] = { { __LOCK_INITIALIZER, &__pthread_initial_thread, 0}, @@ -371,12 +380,19 @@ static int pthread_allocate_stack(const pthread_attr_t *attr, /* Allocate space for stack and thread descriptor at default address */ new_thread = default_new_thread; new_thread_bottom = (char *) (new_thread + 1) - stacksize; - if (mmap((caddr_t)((char *)(new_thread + 1) - INITIAL_STACK_SIZE), + void * new_stack_addr = NULL; + new_stack_addr = mmap((caddr_t)((char *)(new_thread + 1) - INITIAL_STACK_SIZE), INITIAL_STACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN, - -1, 0) == MAP_FAILED) + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE | MAP_GROWSDOWN, + -1, 0); + if (new_stack_addr == MAP_FAILED){ /* Bad luck, this segment is already mapped. */ return -1; + } else if ( new_stack_addr != (caddr_t)((char *)(new_thread + 1) - INITIAL_STACK_SIZE)) { + /* Worse luck, we almost overwrote an existing page */ + munmap(new_stack_addr, INITIAL_STACK_SIZE); + return -2; + } /* We manage to get a stack. Now see whether we need a guard and allocate it if necessary. Notice that the default attributes (stack_size = STACK_SIZE - pagesize) do not need @@ -496,9 +512,10 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, return EAGAIN; if (__pthread_handles[sseg].h_descr != NULL) continue; - if (pthread_allocate_stack(attr, thread_segment(sseg), pagesize, + int res = pthread_allocate_stack(attr, thread_segment(sseg), pagesize, &new_thread, &new_thread_bottom, - &guardaddr, &guardsize) == 0) + &guardaddr, &guardsize); + if ( res == 0) break; #ifndef __ARCH_USE_MMU__ else @@ -507,6 +524,14 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr, * use the next one. However, when there is no MMU, malloc () is used. * It's waste of CPU cycles to continue to try if it fails. */ return EAGAIN; +#else + else if (res == -2) + /* When there is an MMU, if pthread_allocate_stack failed with -2, + * it indicates that we are attempting to mmap in address space which + * is already allocated. Any additional attempts will result in failure + * since we have exhausted our stack area. + */ + return EAGAIN; #endif } __pthread_handles_num++; -- 2.34.1