From patchwork Mon Oct 7 22:55:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jann Horn X-Patchwork-Id: 13825361 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 67BB8CED247 for ; Mon, 7 Oct 2024 22:55:58 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id BA39A6B0083; Mon, 7 Oct 2024 18:55:57 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id B53C06B0085; Mon, 7 Oct 2024 18:55:57 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 9F4446B0088; Mon, 7 Oct 2024 18:55:57 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0011.hostedemail.com [216.40.44.11]) by kanga.kvack.org (Postfix) with ESMTP id 7C8996B0083 for ; Mon, 7 Oct 2024 18:55:57 -0400 (EDT) Received: from smtpin01.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id 96D29140F2D for ; Mon, 7 Oct 2024 22:55:56 +0000 (UTC) X-FDA: 82648315512.01.0E06D69 Received: from mail-wm1-f48.google.com (mail-wm1-f48.google.com [209.85.128.48]) by imf02.hostedemail.com (Postfix) with ESMTP id D336180012 for ; Mon, 7 Oct 2024 22:55:54 +0000 (UTC) Authentication-Results: imf02.hostedemail.com; dkim=pass header.d=google.com header.s=20230601 header.b=hIJWbqQV; spf=pass (imf02.hostedemail.com: domain of jannh@google.com designates 209.85.128.48 as permitted sender) smtp.mailfrom=jannh@google.com; dmarc=pass (policy=reject) header.from=google.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1728341620; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding:in-reply-to: references:dkim-signature; bh=KRtn8t3j7whUUfZUQGOBh9/Ux+u7T3Ja2jMsVhYhxY8=; b=XfNPKzr/VfMOhnG3eVLm3sq98PXb0CTqWYBm/V2GqMTeQARGq0eoeK93+VGTzDfgpPYd3M bhtPsLOJgopv2yuj02cj4HlDiBJviP0gBvWUZGI4XnQAldTdGbMgqw+n3zBhZW4oxZwWaT 42vbNIpAsVn4ynGDF+NOhzANDDWiQV4= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1728341620; a=rsa-sha256; cv=none; b=SnVFv8aVewczaV8tBZZqe8NSRHUDdwk6qPJmXSIM4b9Nbb7WSra0iDUwTN64aSScoWcZf/ lGLJ1kbTeGxLUrW9HldpzaCJI1qqXJt7YZRv93DwnnJxf6sVofccmYom5bycAMxAXx8uTe 4SRhoHoOJuLIcnq4DigoScA5m2qUSYY= ARC-Authentication-Results: i=1; imf02.hostedemail.com; dkim=pass header.d=google.com header.s=20230601 header.b=hIJWbqQV; spf=pass (imf02.hostedemail.com: domain of jannh@google.com designates 209.85.128.48 as permitted sender) smtp.mailfrom=jannh@google.com; dmarc=pass (policy=reject) header.from=google.com Received: by mail-wm1-f48.google.com with SMTP id 5b1f17b1804b1-42f6995dab8so100845e9.0 for ; Mon, 07 Oct 2024 15:55:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1728341753; x=1728946553; darn=kvack.org; h=cc:to:message-id:content-transfer-encoding:mime-version:subject :date:from:from:to:cc:subject:date:message-id:reply-to; bh=KRtn8t3j7whUUfZUQGOBh9/Ux+u7T3Ja2jMsVhYhxY8=; b=hIJWbqQVLAD5N95RIb9RPHmEyKJsyK6Z1S0FAprIN44eRcuuaW4IEx5mPkZd4p2iF1 GknfPzhd7ngZzJ4nugCCKixSWoynVlEipAaRxMd1R1RDd/eALOGYVhcZfA48I6jjWD23 Sj8yDJGoBHBJF2m3JXlFCZbWlX5iUFv6Eza0ltMBVRCcEL3dc1l24kjc9DGUS8Z3HRnS YQtAyo6jpZXk9QT8h7aR5AGQQuBAUQbBxk5IWo2KU1O/3TaqWvxgO49QbPJ/dN7Atp02 iwuPRZlnsGeM692To0K+IOmVSXWam487p9vgftHYfk6uxW92vo//wR68RnUnm3geDfwz Cotg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1728341753; x=1728946553; h=cc:to:message-id:content-transfer-encoding:mime-version:subject :date:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=KRtn8t3j7whUUfZUQGOBh9/Ux+u7T3Ja2jMsVhYhxY8=; b=szMFR382SdLJOTrGoSvoULgYlzZh3vLBRYu07owKZuZF6f5g8yZKTAGVO8DdZZzOPP QNklUaLA4JcLZR+K4Baod/IsHHQbB1GCOo6Hqw4CFXQ3YQVbop0ffZ17E88aWBCtTN/j yMSxCyqfbBir7oN5y72kiQbt21MNFSRloCmesMeBNmUOJ74h+f9X+420ZtKWTReh2VxH KtVa+1ZybRUMwPoNye8arRl73rIgyptCnov6u1/4wZs3v16w9Ns+MjM02xCsd4valH8E 2iNHvT2Cr6d5apbegO+Z/VPGqDHieZ+clWtJnGmiEUzAd3wsBt4X4/bHYJc/8TZnX3Gg ru1A== X-Forwarded-Encrypted: i=1; AJvYcCXInlEQAER6L3qyjfpAgbE9NFrHLux+Zmo0VOeu5Py7FwJ3S8m7wLw/gZuigvsRAB3t1pLGJvJ65Q==@kvack.org X-Gm-Message-State: AOJu0YwMe82aa2ho0FhRyNv1H0GfnNw2vcY/5sGKqjrxp0+7iQ4qpufC OcMbsOCJ8mMN0NSsa3uaGz5x9m3spVCOUWhhQqcENZbUh2tH2AKGwdye9ZnLGQ== X-Google-Smtp-Source: AGHT+IHlDvzelBdkA5qpz8fIAQDStRDvKx0t6Pxm0mdU1tfYyX8BXXl+49Z6jy3NewrGS1ig5GLLNg== X-Received: by 2002:a05:600c:c8a:b0:42c:9e35:cde6 with SMTP id 5b1f17b1804b1-42fc83dfc65mr1881355e9.2.1728341752879; Mon, 07 Oct 2024 15:55:52 -0700 (PDT) Received: from localhost ([2a00:79e0:9d:4:39d2:ccab:c4ec:585b]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-37d16920be2sm6645143f8f.60.2024.10.07.15.55.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Oct 2024 15:55:52 -0700 (PDT) From: Jann Horn Date: Tue, 08 Oct 2024 00:55:39 +0200 Subject: [PATCH] mm: Enforce a minimal stack gap even against inaccessible VMAs MIME-Version: 1.0 Message-Id: <20241008-stack-gap-inaccessible-v1-1-848d4d891f21@google.com> X-B4-Tracking: v=1; b=H4sIAOpmBGcC/x3MSwqAMAwA0atI1gZaFfxcRVy0MWpQqjQignh3i 8u3mHlAOQordNkDkS9R2UOCzTOgxYWZUcZkKExRWWMa1NPRirM7UIIjYlXxGyPVpW2neqy89ZD iI/Ik9z/uh/f9ABdgS85oAAAA To: Andrew Morton Cc: Hugh Dickins , Oleg Nesterov , Michal Hocko , Helge Deller , Vlastimil Babka , Ben Hutchings , Willy Tarreau , Rik van Riel , linux-mm@kvack.org, linux-kernel@vger.kernel.org, stable@vger.kernel.org, Jann Horn X-Mailer: b4 0.15-dev X-Developer-Signature: v=1; a=ed25519-sha256; t=1728341748; l=4473; i=jannh@google.com; s=20240730; h=from:subject:message-id; bh=n52Zcjng97SR7V16E/kiNd9Ad8nOMx616zmfBspy7bA=; b=ekJkZXJWcbs+tPc806Tv4AxKiW8KTdjWR/I4EIwAEUjpjvC2nP+AnDfJ8Dy2Pq8BjY1IDootY Zikmp+VX8bACCd1mpHA6Vhzri5fZQbYZoX/vJBWVsJMyEcS0TCMOPEX X-Developer-Key: i=jannh@google.com; a=ed25519; pk=AljNtGOzXeF6khBXDJVVvwSEkVDGnnZZYqfWhP1V+C8= X-Rspam-User: X-Rspamd-Server: rspam04 X-Rspamd-Queue-Id: D336180012 X-Stat-Signature: tfkn9dpxs17rhhn9s8qhxnzfrqa9tdss X-HE-Tag: 1728341754-311081 X-HE-Meta: U2FsdGVkX18WH0OBnpK7Ny9We/iqDwS/8GykqjuJSqt1MkVoxFhdm9xjd8Su0QFBIbPqIlZXtNEjaEGf3P9QcjSfmSatR3dGejdRpr7GLxpVxxNb/XgTqux4AtD/E6wMDJegNsnyJ9gliklxWzW0QS8MXZ2SNWPd3Y43kwTeAQ0FWfwWBc12vrRREGI3exS1sL57qZM8QIZe5lKi4b2TzT47lv031koiCNvW6EHbIhENOOex6Lurif/9F9f49v9Rtb56J2L8rxgXeH+/1gMvzD0DoVmijfd2uOifwdGxYn7l/NUPNwNzaASmnA85Bug3xezTDIXd2zIjj5h083kFrHrz0yaBpmJU6STV1H2VnjZ6+JiL1dvBnFaj//Ozu+Yj2Kx3+NBYeiXCYZBw9DYjsmIsuA1tyks1mzhlFPZuzR0VoFIVoe5E5tItHPEZOKFWLjW/rB6isdepUm+mrWJwq4+4QO2jfJ4K2vmZt8RSsTCU/QYmJrXy8VBnblDo4OmLPwes51aQXoQgbw/ZK2rTa1OlYlDW683nrLQ9O6Y2rgVO0wL4EK3Omwv+SmEhSZSwQhILg+cBl7Ah3/Q72krX9aVl6q724xIzQLNhmFkpOaDXZAAesmjZKvMdRRoht4K4WSFwxsFmDsIZoxPIm+mZQ5sr5CGAsyEHZFNJ51xNlSGb3VIU40KteNfKt7fSqHg++pJFbUSh5yJPdP2b6c1JJgePPTkezbEXb+SuAPto7d47ywF/WTDjIuOPq0vNEkDXd281yg7oXQvRlKrzBaw9L/oq42F0GLJUqxLIkdErLGU/9E5x80SBtyBHUJsN1IxlFZOZMflBmaZqc1VitLw0OwW8HT92dCySDELcH4FLV08H6Jmv1CG8O3KW+TA4zNBcmRdWfuIZ3yM4nsY8Awg3vvXwrEaEb307aHVa0uRUQ2XzRpCNOn2CD2QtkZABs8q6chPVz+AQwpCz4TVlZFf 6CcDqWZ3 acPpjizgs83mxwJlcyUAqW8pa2VW5MXrjPTgGe8i4HKXdtFaNdn+2freF2NkG60dPfLYKhVwhSOuYgCbUVs0LN2lRXdzBm1GFil92ioWan8u4VOWtIXtzkA0brEDH5OOzzT34a8R2y+wIELuvrDIFHzdpIu+8T0JfJt1cZTIzlVE2eJZtMekIrxV3QhMGUnnbc2rAYn0OuPqQwJNFPOXcWqsApa2tI8sRbaKwL9Dl2ZpXE7QrkJ/RawOtfEL8KtwbdZKavPYyE0/2/paAmm/EgHo/VWlHpP/La9RTCI146uuhvCOI6iEqn/KxoDPFnZ+VBO2Zkte72O9sO8lvMiXwOPhmHAwqebV4THlx X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: As explained in the comment block this change adds, we can't tell what userspace's intent is when the stack grows towards an inaccessible VMA. I have a (highly contrived) C testcase for 32-bit x86 userspace with glibc that mixes malloc(), pthread creation, and recursion in just the right way such that the main stack overflows into malloc() arena memory. (Let me know if you want me to share that.) I don't know of any specific scenario where this is actually exploitable, but it seems like it could be a security problem for sufficiently unlucky userspace. I believe we should ensure that, as long as code is compiled with something like -fstack-check, a stack overflow in it can never cause the main stack to overflow into adjacent heap memory. My fix effectively reverts the behavior for !vma_is_accessible() VMAs to the behavior before commit 1be7107fbe18 ("mm: larger stack guard gap, between vmas"), so I think it should be a fairly safe change even in case A. Fixes: 561b5e0709e4 ("mm/mmap.c: do not blow on PROT_NONE MAP_FIXED holes in the stack") Cc: stable@vger.kernel.org Signed-off-by: Jann Horn --- I have tested that Libreoffice still launches after this change, though I don't know if that means anything. Note that I haven't tested the growsup code. --- mm/mmap.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 7 deletions(-) --- base-commit: 8cf0b93919e13d1e8d4466eb4080a4c4d9d66d7b change-id: 20241008-stack-gap-inaccessible-c7319f7d4b1b diff --git a/mm/mmap.c b/mm/mmap.c index dd4b35a25aeb..971bfd6c1cea 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1064,10 +1064,12 @@ static int expand_upwards(struct vm_area_struct *vma, unsigned long address) gap_addr = TASK_SIZE; next = find_vma_intersection(mm, vma->vm_end, gap_addr); - if (next && vma_is_accessible(next)) { - if (!(next->vm_flags & VM_GROWSUP)) + if (next && !(next->vm_flags & VM_GROWSUP)) { + /* see comments in expand_downwards() */ + if (vma_is_accessible(prev)) + return -ENOMEM; + if (address == next->vm_start) return -ENOMEM; - /* Check that both stack segments have the same anon_vma? */ } if (next) @@ -1155,10 +1157,47 @@ int expand_downwards(struct vm_area_struct *vma, unsigned long address) /* Enforce stack_guard_gap */ prev = vma_prev(&vmi); /* Check that both stack segments have the same anon_vma? */ - if (prev) { - if (!(prev->vm_flags & VM_GROWSDOWN) && - vma_is_accessible(prev) && - (address - prev->vm_end < stack_guard_gap)) + if (prev && !(prev->vm_flags & VM_GROWSDOWN) && + (address - prev->vm_end < stack_guard_gap)) { + /* + * If the previous VMA is accessible, this is the normal case + * where the main stack is growing down towards some unrelated + * VMA. Enforce the full stack guard gap. + */ + if (vma_is_accessible(prev)) + return -ENOMEM; + + /* + * If the previous VMA is not accessible, we have a problem: + * We can't tell what userspace's intent is. + * + * Case A: + * Maybe userspace wants to use the previous VMA as a + * "guard region" at the bottom of the main stack, in which case + * userspace wants us to grow the stack until it is adjacent to + * the guard region. Apparently some Java runtime environments + * and Rust do that? + * That is kind of ugly, and in that case userspace really ought + * to ensure that the stack is fully expanded immediately, but + * we have to handle this case. + * + * Case B: + * But maybe the previous VMA is entirely unrelated to the stack + * and is only *temporarily* PROT_NONE. For example, glibc + * malloc arenas create a big PROT_NONE region and then + * progressively mark parts of it as writable. + * In that case, we must not let the stack become adjacent to + * the previous VMA. Otherwise, after the region later becomes + * writable, a stack overflow will cause the stack to grow into + * the previous VMA, and we won't have any stack gap to protect + * against this. + * + * As an ugly tradeoff, enforce a single-page gap. + * A single page will hopefully be small enough to not be + * noticed in case A, while providing the same level of + * protection in case B that normal userspace threads get. + */ + if (address == prev->vm_end) return -ENOMEM; }