From patchwork Tue Apr 28 03:27:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jann Horn X-Patchwork-Id: 11513701 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8A19D92A for ; Tue, 28 Apr 2020 03:28:04 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 48A862073C for ; Tue, 28 Apr 2020 03:28:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="X8ZXo00l" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 48A862073C Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 489C58E0006; Mon, 27 Apr 2020 23:28:03 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 460CB8E0001; Mon, 27 Apr 2020 23:28:03 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 39D398E0006; Mon, 27 Apr 2020 23:28:03 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0212.hostedemail.com [216.40.44.212]) by kanga.kvack.org (Postfix) with ESMTP id 20A968E0001 for ; Mon, 27 Apr 2020 23:28:03 -0400 (EDT) Received: from smtpin05.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay04.hostedemail.com (Postfix) with ESMTP id DC05B45AA for ; Tue, 28 Apr 2020 03:28:02 +0000 (UTC) X-FDA: 76755830004.05.quiet78_463adce21c532 X-Spam-Summary: 2,0,0,998e53c4c8402555,d41d8cd98f00b204,3waknxgukckajannhgoogle.comlinux-mmkvack.org@flex--jannh.bounces.google.com,,RULES_HIT:41:69:152:355:379:541:800:960:966:973:981:988:989:1260:1277:1313:1314:1345:1359:1437:1516:1518:1535:1544:1593:1594:1711:1730:1747:1777:1792:2196:2199:2393:2559:2562:2898:2899:3138:3139:3140:3141:3142:3152:3354:3865:3866:3867:3868:3870:3871:3872:3874:4118:4250:4321:4385:4605:5007:6261:6653:6742:7875:7903:7974:9592:9969:10004:11026:11473:11658:11914:12043:12291:12296:12297:12438:12555:12683:12895:12986:14096:14097:14181:14394:14659:14721:21080:21444:21627:21795:21990:22047:30003:30012:30051:30054:30070,0,RBL:209.85.219.202:@flex--jannh.bounces.google.com:.lbl8.mailshell.net-66.100.201.100 62.18.0.100,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:fp,MSBL:0,DNSBL:neutral,Custom_rules:0:0:0,LFtime:24,LUA_SUMMARY:none X-HE-Tag: quiet78_463adce21c532 X-Filterd-Recvd-Size: 7226 Received: from mail-yb1-f202.google.com (mail-yb1-f202.google.com [209.85.219.202]) by imf39.hostedemail.com (Postfix) with ESMTP for ; Tue, 28 Apr 2020 03:28:02 +0000 (UTC) Received: by mail-yb1-f202.google.com with SMTP id y8so23351769ybn.5 for ; Mon, 27 Apr 2020 20:28:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=I4RZCdzOpcoMpbDN2LqRR4S1SmcrD2Kj55dT+NEDBbE=; b=X8ZXo00ljasm7AZ1Els7stZGHbJUjQ3cYCjBhSxX4NYkV1i4GJ8fn/Dn9b7txZrs4Y rk4PVdLrWzKGTy55PbNAV14mS8eAapCE7OP5rLPuuiM96DTFmYOd2R8B3N+gg8WSfGWv YySTyNNFFpF2KM5Vtkzo4AKQytmhpqKUa3MnS/7ninMjf0Ix4zkRnSJbjAH3lccQA0+j z266kabr7WqjlEia0jfQlMB5LrckgW/C1smlQe3Lthb8du2UNtYHiw6qieDHzFuWydw/ 71omd7lOenbwJeViL3RPuetWYMY3l4GO7BSCZeqf3sihWLUx95KaDb3dnQkMoSwjUg3f 4X1Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=I4RZCdzOpcoMpbDN2LqRR4S1SmcrD2Kj55dT+NEDBbE=; b=Tszzw4LcE0jEXGAXM/+pSS7nCpYN95IqeXL4poiZ5N88Sp6Re6SDzp/M80Vucu1LgZ tC/FVJ/3V8BYCONVivBNFIV+r0+A0HuAzpQkLFUf0nzW5GYtFiXQYGN9UEYZ3iepGLAC lUuBYypZdVhz/SuTHqekx3F0q7DjPkzLA7iAhBtspoILRwiiPQI3PRXGCuyi3gOYc7q6 pXW2lVMiIknA4W/1b6dXqkNw5IlANtzX3x9uusuF/q6D054O4jchVdX+cF/Wtm82A/uy uGCFUksjoATnuZTEReXoQaNVrueAQ7E3KYgS6yru/KjaIpafZUAVeaSeDIuOf37hvFSM b/LA== X-Gm-Message-State: AGi0Pub+kAk7pk38GEsmmm7Ds9y5IopYUjzN4DHQigYXMxNwQb/8C4ve aRobLx99ZGvFg+0c7wIGEVUQ/xWtUg== X-Google-Smtp-Source: APiQypIcdn/JR5PlTDtT8WHtlwDwffUFy2NKOR9VROQaek1qOXSfTSnx9Q8ThU+1UmQujkYLWnXr/liimA== X-Received: by 2002:a25:c402:: with SMTP id u2mr41378105ybf.82.1588044481799; Mon, 27 Apr 2020 20:28:01 -0700 (PDT) Date: Tue, 28 Apr 2020 05:27:41 +0200 In-Reply-To: <20200428032745.133556-1-jannh@google.com> Message-Id: <20200428032745.133556-2-jannh@google.com> Mime-Version: 1.0 References: <20200428032745.133556-1-jannh@google.com> X-Mailer: git-send-email 2.26.2.303.gf8c07b1a785-goog Subject: [PATCH 1/5] binfmt_elf_fdpic: Stop using dump_emit() on user pointers on !MMU From: Jann Horn To: Andrew Morton Cc: Linus Torvalds , Christoph Hellwig , linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org, Alexander Viro , "Eric W . Biederman" , Oleg Nesterov , Russell King , linux-arm-kernel@lists.infradead.org, Mark Salter , Aurelien Jacquiot , linux-c6x-dev@linux-c6x.org, Yoshinori Sato , Rich Felker , linux-sh@vger.kernel.org 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: dump_emit() is for kernel pointers, and VMAs describe userspace memory. Let's be tidy here and avoid accessing userspace pointers under KERNEL_DS, even if it probably doesn't matter much on !MMU systems - especially given that it looks like we can just use the same get_dump_page() as on MMU if we move it out of the CONFIG_MMU block. Signed-off-by: Jann Horn --- fs/binfmt_elf_fdpic.c | 8 ------ mm/gup.c | 58 +++++++++++++++++++++---------------------- 2 files changed, 29 insertions(+), 37 deletions(-) diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index c62c17a5c34a9..f5b47076fa762 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1495,14 +1495,11 @@ static bool elf_fdpic_dump_segments(struct coredump_params *cprm) struct vm_area_struct *vma; for (vma = current->mm->mmap; vma; vma = vma->vm_next) { -#ifdef CONFIG_MMU unsigned long addr; -#endif if (!maydump(vma, cprm->mm_flags)) continue; -#ifdef CONFIG_MMU for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE) { bool res; @@ -1518,11 +1515,6 @@ static bool elf_fdpic_dump_segments(struct coredump_params *cprm) if (!res) return false; } -#else - if (!dump_emit(cprm, (void *) vma->vm_start, - vma->vm_end - vma->vm_start)) - return false; -#endif } return true; } diff --git a/mm/gup.c b/mm/gup.c index 50681f0286ded..76080c4dbff05 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -1490,35 +1490,6 @@ int __mm_populate(unsigned long start, unsigned long len, int ignore_errors) up_read(&mm->mmap_sem); return ret; /* 0 or negative error code */ } - -/** - * get_dump_page() - pin user page in memory while writing it to core dump - * @addr: user address - * - * Returns struct page pointer of user page pinned for dump, - * to be freed afterwards by put_page(). - * - * Returns NULL on any kind of failure - a hole must then be inserted into - * the corefile, to preserve alignment with its headers; and also returns - * NULL wherever the ZERO_PAGE, or an anonymous pte_none, has been found - - * allowing a hole to be left in the corefile to save diskspace. - * - * Called without mmap_sem, but after all other threads have been killed. - */ -#ifdef CONFIG_ELF_CORE -struct page *get_dump_page(unsigned long addr) -{ - struct vm_area_struct *vma; - struct page *page; - - if (__get_user_pages(current, current->mm, addr, 1, - FOLL_FORCE | FOLL_DUMP | FOLL_GET, &page, &vma, - NULL) < 1) - return NULL; - flush_cache_page(vma, addr, page_to_pfn(page)); - return page; -} -#endif /* CONFIG_ELF_CORE */ #else /* CONFIG_MMU */ static long __get_user_pages_locked(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, @@ -1565,6 +1536,35 @@ static long __get_user_pages_locked(struct task_struct *tsk, } #endif /* !CONFIG_MMU */ +/** + * get_dump_page() - pin user page in memory while writing it to core dump + * @addr: user address + * + * Returns struct page pointer of user page pinned for dump, + * to be freed afterwards by put_page(). + * + * Returns NULL on any kind of failure - a hole must then be inserted into + * the corefile, to preserve alignment with its headers; and also returns + * NULL wherever the ZERO_PAGE, or an anonymous pte_none, has been found - + * allowing a hole to be left in the corefile to save diskspace. + * + * Called without mmap_sem, but after all other threads have been killed. + */ +#ifdef CONFIG_ELF_CORE +struct page *get_dump_page(unsigned long addr) +{ + struct vm_area_struct *vma; + struct page *page; + + if (__get_user_pages(current, current->mm, addr, 1, + FOLL_FORCE | FOLL_DUMP | FOLL_GET, &page, &vma, + NULL) < 1) + return NULL; + flush_cache_page(vma, addr, page_to_pfn(page)); + return page; +} +#endif /* CONFIG_ELF_CORE */ + #if defined(CONFIG_FS_DAX) || defined (CONFIG_CMA) static bool check_dax_vmas(struct vm_area_struct **vmas, long nr_pages) { From patchwork Tue Apr 28 03:27:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jann Horn X-Patchwork-Id: 11513707 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id F0FE692A for ; Tue, 28 Apr 2020 03:28:07 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id BCE602073C for ; Tue, 28 Apr 2020 03:28:07 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="I3TqNZ+o" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org BCE602073C Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id DFF8A8E0007; Mon, 27 Apr 2020 23:28:06 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id DAEE08E0001; Mon, 27 Apr 2020 23:28:06 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id CED0A8E0007; Mon, 27 Apr 2020 23:28:06 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0107.hostedemail.com [216.40.44.107]) by kanga.kvack.org (Postfix) with ESMTP id BC0E08E0001 for ; Mon, 27 Apr 2020 23:28:06 -0400 (EDT) Received: from smtpin13.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay04.hostedemail.com (Postfix) with ESMTP id 77388582D for ; Tue, 28 Apr 2020 03:28:06 +0000 (UTC) X-FDA: 76755830172.13.ducks21_46c1b1107ae2a X-Spam-Summary: 2,0,0,20e02a0dc62a8a56,d41d8cd98f00b204,3xaknxgukckqnerrlksskpi.gsqpmryb-qqozego.svk@flex--jannh.bounces.google.com,,RULES_HIT:41:152:355:379:541:800:960:973:988:989:1260:1277:1313:1314:1345:1359:1437:1516:1518:1534:1539:1568:1593:1594:1711:1714:1730:1747:1777:1792:2393:2559:2562:2895:3138:3139:3140:3141:3142:3152:3865:3866:3867:4321:5007:6261:6653:6742:9969:10004:10400:11658:11914:12296:12297:12555:12679:12895:13069:13311:13357:14181:14394:14659:14721:21080:21444:21451:21627:21990:30054:30070,0,RBL:209.85.219.73:@flex--jannh.bounces.google.com:.lbl8.mailshell.net-62.18.0.100 66.100.201.100,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:fp,MSBL:0,DNSBL:neutral,Custom_rules:0:0:0,LFtime:24,LUA_SUMMARY:none X-HE-Tag: ducks21_46c1b1107ae2a X-Filterd-Recvd-Size: 3758 Received: from mail-qv1-f73.google.com (mail-qv1-f73.google.com [209.85.219.73]) by imf02.hostedemail.com (Postfix) with ESMTP for ; Tue, 28 Apr 2020 03:28:06 +0000 (UTC) Received: by mail-qv1-f73.google.com with SMTP id r10so21071222qvw.23 for ; Mon, 27 Apr 2020 20:28:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=oz1fQ07v4YKej2hlWP6qWEvyAtsuOx0qHOmBf6H8EEU=; b=I3TqNZ+omoMhei62DCjjFhvToBgLQ/mzKXtTiQk26/Z5mE9W3slhueOYb+z8GilAMC uJiJnXNo6zMWUJK5fxe8p2Clt0BrANXorqf5ejL3fjOyojaAeijiBitnGvTxkfmUvtk5 Oo7NlfGIo6V3y/5pocLkkx6t8Ss8qBGDmgrARr+67qmzWEXVLYp/RFVVh/KoqwASWwPE LeSD+Oj61O/Z74sMssGhSL5Fu1c3GwuoL3JonPdkpa7ffE2p5AG02vHLj7jS4QiYw7q5 cGhGmYlwlCMnZ+TzyelO2CkY4EzLolMoho7DCGot0I1FyuWa+tJ3zOEFil++xSYeEETq eZBQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=oz1fQ07v4YKej2hlWP6qWEvyAtsuOx0qHOmBf6H8EEU=; b=n75wfsN/t0Ck8AGvW9cFHgFM4h/VWFxBuhYiKx4B4kdIYP0HnER61KAqveosJGIVKN IzSk20mtZffMREOKwdl5xRY7LSXna1W3oSkZlT+VVrK747apQqvXVG7q3xYBVLAXHl4O f1FbJKbp2VnEqeIBQdQvYDY30qSIX1Up09HSh0cW0zN3iRQVlKi6aiZASAvTyThFJ9Eu 9BSpXViXMIuzOUm5/z/c2W6xXBizqty3ClG1Qps/CjcTU5ipOTl6lxGrC4Y1nNYrNONG bAqMCOKnvYy1hxhaZB3s1OcDq50p7kj7F49MH5FZ7W8aCcBOuDr1zlPZKFPStkqiTCV0 7XZw== X-Gm-Message-State: AGi0Puaej8tEsfwrRdnn+90XKMVrdAiOJ7rQJWsTQuTlvk99yqAvnsHs S64wicSnrlwLe4vtidx0lYWMKLGirQ== X-Google-Smtp-Source: APiQypJE2oducFJ7QqE/S1GqpExEa0j+XC+oVynygSXLNhNvPC4n0hoqiHIFqgoaUYcyeTNIUgqu5F2EbA== X-Received: by 2002:a0c:8b48:: with SMTP id d8mr26408306qvc.195.1588044485433; Mon, 27 Apr 2020 20:28:05 -0700 (PDT) Date: Tue, 28 Apr 2020 05:27:42 +0200 In-Reply-To: <20200428032745.133556-1-jannh@google.com> Message-Id: <20200428032745.133556-3-jannh@google.com> Mime-Version: 1.0 References: <20200428032745.133556-1-jannh@google.com> X-Mailer: git-send-email 2.26.2.303.gf8c07b1a785-goog Subject: [PATCH 2/5] coredump: Fix handling of partial writes in dump_emit() From: Jann Horn To: Andrew Morton Cc: Linus Torvalds , Christoph Hellwig , linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org, Alexander Viro , "Eric W . Biederman" , Oleg Nesterov , Russell King , linux-arm-kernel@lists.infradead.org, Mark Salter , Aurelien Jacquiot , linux-c6x-dev@linux-c6x.org, Yoshinori Sato , Rich Felker , linux-sh@vger.kernel.org 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: After a partial write, we have to update the input buffer pointer. Fixes: 2507a4fbd48a ("make dump_emit() use vfs_write() instead of banging at ->f_op->write directly") Cc: stable@vger.kernel.org Signed-off-by: Jann Horn --- fs/coredump.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/coredump.c b/fs/coredump.c index 408418e6aa131..047f5a11dbee7 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -833,6 +833,7 @@ int dump_emit(struct coredump_params *cprm, const void *addr, int nr) cprm->written += n; cprm->pos += n; nr -= n; + addr += n; } return 1; } From patchwork Tue Apr 28 03:27:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jann Horn X-Patchwork-Id: 11513715 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9406A92A for ; Tue, 28 Apr 2020 03:28:11 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 51DD72137B for ; Tue, 28 Apr 2020 03:28:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="sLC5sUwQ" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 51DD72137B Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 797348E0008; Mon, 27 Apr 2020 23:28:10 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 76DDD8E0001; Mon, 27 Apr 2020 23:28:10 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 6B2FA8E0008; Mon, 27 Apr 2020 23:28:10 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0198.hostedemail.com [216.40.44.198]) by kanga.kvack.org (Postfix) with ESMTP id 527448E0001 for ; Mon, 27 Apr 2020 23:28:10 -0400 (EDT) Received: from smtpin21.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay01.hostedemail.com (Postfix) with ESMTP id 08597180AD807 for ; Tue, 28 Apr 2020 03:28:10 +0000 (UTC) X-FDA: 76755830340.21.tiger80_4743adb7c941b X-Spam-Summary: 2,0,0,db4871baa4dc2473,d41d8cd98f00b204,3ykknxgukckcqhuuonvvnsl.jvtspube-ttrchjr.vyn@flex--jannh.bounces.google.com,,RULES_HIT:41:69:152:355:379:541:800:960:973:988:989:1260:1277:1313:1314:1345:1359:1437:1516:1518:1535:1544:1593:1594:1711:1730:1747:1777:1792:2393:2559:2562:2693:2898:3138:3139:3140:3141:3142:3152:3355:3865:3866:3867:3868:3874:4119:4250:4321:4605:5007:6261:6653:6742:7974:9592:9969:10004:11026:11473:11658:11914:12043:12291:12294:12296:12297:12438:12555:12683:12895:12986:13161:13229:14096:14097:14181:14394:14659:14721:21080:21444:21611:21627:21990:30003:30054:30070,0,RBL:209.85.160.201:@flex--jannh.bounces.google.com:.lbl8.mailshell.net-62.18.0.100 66.100.201.100,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:fp,MSBL:0,DNSBL:neutral,Custom_rules:0:0:0,LFtime:24,LUA_SUMMARY:none X-HE-Tag: tiger80_4743adb7c941b X-Filterd-Recvd-Size: 8036 Received: from mail-qt1-f201.google.com (mail-qt1-f201.google.com [209.85.160.201]) by imf34.hostedemail.com (Postfix) with ESMTP for ; Tue, 28 Apr 2020 03:28:09 +0000 (UTC) Received: by mail-qt1-f201.google.com with SMTP id n22so22974519qtp.15 for ; Mon, 27 Apr 2020 20:28:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=JjVJ6bVnkDD22Kug2lLArucLeDH63cpRkRDdCvmUsgw=; b=sLC5sUwQCO5H8VpQfbr0H4yolym1MeU6fcyvl0GX1tVdSTKXplkYJVOUSPeObsdt1J JNFx6+q7V/UcdjF9kl6aGAwR+65DA5naHvrPlRhD9971fShW/szwPgWHYDi486Wz2jsk 4n54HzCwbsCTB0brNiYnCd28IVesQuXtCTGd1S+kk4pCbbakqRMd6Yy+wfjsX6mVg9Ul 5/piBlog/ScC96XdEuOmAWtCjjJytAI/OBS1H/Vf1cjHyX7mQZbuEwfvfZYYxbhWQwJV 4OaucR4dIV8MFcI9nfy1JhV0PUihfy76zcj3UWEktQgJ9dZEPvmmOG5zdCRO4l3kcB+A iXGA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=JjVJ6bVnkDD22Kug2lLArucLeDH63cpRkRDdCvmUsgw=; b=pj5c6jEeQcbAPYenLEzqI4VEcIzb6jezwSmgWaMmso0K+9n2Z+3ybRPtK1N6WXnAok 9O+aRCwTRebgJBTs8LiaAJzwXsTJr73t1gq+tZTQqT7nYFXrdcLfAc2f/l5bzWhqo/iX m3GNQJjF5wayB7AnFIvRj0DPIwWR5bSkU7dTOhdAmShu1qYIuZzhYpKmz10x0bnl6esm ZykO2WmVJixhrvqsSCyJ8Pjf9BUkGBkG8Szw9lnaMUEjChJjyOOsMeLYmEm82LiRXw3I TnST1dHFXtLW4iMJ9iX+ZQml6b3Wp7gOuVfSRmvQJ0dgZdqJR3gJX9YXY4lnjXWfZgL+ Oriw== X-Gm-Message-State: AGi0PubU4bgLHM9V4T0AerZXAhKb0tq3L7zfQypcjYzxi0KTckoUKqeg hS044l+xQrOa1d+KVIJE6f9t0ekFWQ== X-Google-Smtp-Source: APiQypK8E6BiAXKEVW3TpfVgfPj6v9qslU6kHK+WktRMaanVdj0UoaQeTgjCIkPDaA7t5NniPYjJ3E4kEw== X-Received: by 2002:a0c:f1d1:: with SMTP id u17mr26207196qvl.146.1588044488930; Mon, 27 Apr 2020 20:28:08 -0700 (PDT) Date: Tue, 28 Apr 2020 05:27:43 +0200 In-Reply-To: <20200428032745.133556-1-jannh@google.com> Message-Id: <20200428032745.133556-4-jannh@google.com> Mime-Version: 1.0 References: <20200428032745.133556-1-jannh@google.com> X-Mailer: git-send-email 2.26.2.303.gf8c07b1a785-goog Subject: [PATCH 3/5] coredump: Refactor page range dumping into common helper From: Jann Horn To: Andrew Morton Cc: Linus Torvalds , Christoph Hellwig , linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org, Alexander Viro , "Eric W . Biederman" , Oleg Nesterov , Russell King , linux-arm-kernel@lists.infradead.org, Mark Salter , Aurelien Jacquiot , linux-c6x-dev@linux-c6x.org, Yoshinori Sato , Rich Felker , linux-sh@vger.kernel.org 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: Both fs/binfmt_elf.c and fs/binfmt_elf_fdpic.c need to dump ranges of pages into the coredump file. Extract that logic into a common helper. Any other binfmt that actually wants to create coredumps will probably need the same function; so stop making get_dump_page() depend on CONFIG_ELF_CORE. Signed-off-by: Jann Horn --- fs/binfmt_elf.c | 22 ++-------------------- fs/binfmt_elf_fdpic.c | 18 +++--------------- fs/coredump.c | 33 +++++++++++++++++++++++++++++++++ include/linux/coredump.h | 2 ++ mm/gup.c | 2 -- 5 files changed, 40 insertions(+), 37 deletions(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index b29b84595b09f..fb36469848323 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -2323,26 +2323,8 @@ static int elf_core_dump(struct coredump_params *cprm) for (i = 0, vma = first_vma(current, gate_vma); vma != NULL; vma = next_vma(vma, gate_vma)) { - unsigned long addr; - unsigned long end; - - end = vma->vm_start + vma_filesz[i++]; - - for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) { - struct page *page; - int stop; - - page = get_dump_page(addr); - if (page) { - void *kaddr = kmap(page); - stop = !dump_emit(cprm, kaddr, PAGE_SIZE); - kunmap(page); - put_page(page); - } else - stop = !dump_skip(cprm, PAGE_SIZE); - if (stop) - goto cleanup; - } + if (!dump_user_range(cprm, vma->vm_start, vma_filesz[i++])) + goto cleanup; } dump_truncate(cprm); diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index f5b47076fa762..938f66f4de9b2 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1500,21 +1500,9 @@ static bool elf_fdpic_dump_segments(struct coredump_params *cprm) if (!maydump(vma, cprm->mm_flags)) continue; - for (addr = vma->vm_start; addr < vma->vm_end; - addr += PAGE_SIZE) { - bool res; - struct page *page = get_dump_page(addr); - if (page) { - void *kaddr = kmap(page); - res = dump_emit(cprm, kaddr, PAGE_SIZE); - kunmap(page); - put_page(page); - } else { - res = dump_skip(cprm, PAGE_SIZE); - } - if (!res) - return false; - } + if (!dump_user_range(cprm, vma->vm_start, + vma->vma_end - vma->vm_start)) + return false; } return true; } diff --git a/fs/coredump.c b/fs/coredump.c index 047f5a11dbee7..3385de8a62302 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -860,6 +860,39 @@ int dump_skip(struct coredump_params *cprm, size_t nr) } EXPORT_SYMBOL(dump_skip); +#ifdef CONFIG_ELF_CORE +int dump_user_range(struct coredump_params *cprm, unsigned long start, + unsigned long len) +{ + unsigned long addr; + + for (addr = start; addr < start + len; addr += PAGE_SIZE) { + struct page *page; + int stop; + + /* + * To avoid having to allocate page tables for virtual address + * ranges that have never been used yet, use a helper that + * returns NULL when encountering an empty page table entry that + * would otherwise have been filled with the zero page. + */ + page = get_dump_page(addr); + if (page) { + void *kaddr = kmap(page); + + stop = !dump_emit(cprm, kaddr, PAGE_SIZE); + kunmap(page); + put_page(page); + } else { + stop = !dump_skip(cprm, PAGE_SIZE); + } + if (stop) + return 0; + } + return 1; +} +#endif + int dump_align(struct coredump_params *cprm, int align) { unsigned mod = cprm->pos & (align - 1); diff --git a/include/linux/coredump.h b/include/linux/coredump.h index abf4b4e65dbb9..4289dc21c04ff 100644 --- a/include/linux/coredump.h +++ b/include/linux/coredump.h @@ -16,6 +16,8 @@ extern int dump_skip(struct coredump_params *cprm, size_t nr); extern int dump_emit(struct coredump_params *cprm, const void *addr, int nr); extern int dump_align(struct coredump_params *cprm, int align); extern void dump_truncate(struct coredump_params *cprm); +int dump_user_range(struct coredump_params *cprm, unsigned long start, + unsigned long len); #ifdef CONFIG_COREDUMP extern void do_coredump(const kernel_siginfo_t *siginfo); #else diff --git a/mm/gup.c b/mm/gup.c index 76080c4dbff05..9a7e83772f1fe 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -1550,7 +1550,6 @@ static long __get_user_pages_locked(struct task_struct *tsk, * * Called without mmap_sem, but after all other threads have been killed. */ -#ifdef CONFIG_ELF_CORE struct page *get_dump_page(unsigned long addr) { struct vm_area_struct *vma; @@ -1563,7 +1562,6 @@ struct page *get_dump_page(unsigned long addr) flush_cache_page(vma, addr, page_to_pfn(page)); return page; } -#endif /* CONFIG_ELF_CORE */ #if defined(CONFIG_FS_DAX) || defined (CONFIG_CMA) static bool check_dax_vmas(struct vm_area_struct **vmas, long nr_pages) From patchwork Tue Apr 28 03:27:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jann Horn X-Patchwork-Id: 11513721 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5435392A for ; Tue, 28 Apr 2020 03:28:15 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id EDC302137B for ; Tue, 28 Apr 2020 03:28:14 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="h6sItOR6" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org EDC302137B Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 0B84B8E0009; Mon, 27 Apr 2020 23:28:14 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 06A778E0001; Mon, 27 Apr 2020 23:28:14 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id EC1108E0009; Mon, 27 Apr 2020 23:28:13 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0103.hostedemail.com [216.40.44.103]) by kanga.kvack.org (Postfix) with ESMTP id D01398E0001 for ; Mon, 27 Apr 2020 23:28:13 -0400 (EDT) Received: from smtpin27.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay04.hostedemail.com (Postfix) with ESMTP id 89B0E582D for ; Tue, 28 Apr 2020 03:28:13 +0000 (UTC) X-FDA: 76755830466.27.card53_47c5fdf3a571c X-Spam-Summary: 2,0,0,d6bfcbc57127622e,d41d8cd98f00b204,3zkknxgukcksulyysrzzrwp.nzxwtyfi-xxvglnv.zcr@flex--jannh.bounces.google.com,,RULES_HIT:41:69:152:327:355:379:541:800:960:966:973:988:989:1260:1277:1313:1314:1345:1359:1431:1437:1516:1518:1593:1594:1605:1730:1747:1777:1792:2196:2198:2199:2200:2393:2553:2559:2562:2693:2892:2898:3138:3139:3140:3141:3142:3152:3865:3866:3867:3868:3870:3871:3872:3873:3874:4250:4321:4385:4605:5007:6119:6261:6653:6742:7875:7903:7974:8603:9010:9012:9592:9969:10004:10226:10954:11026:11232:11473:11658:11914:12043:12294:12296:12297:12438:12555:12663:12679:12681:12683:12895:12986:13149:13230:13869:13972:14096:14097:14394:14659:21080:21220:21222:21324:21325:21433:21444:21450:21451:21611:21627:21939:21983:21987:21990:30005:30012:30034:30045:30051:30054:30070:30075:30090,0,RBL:209.85.160.201:@flex--jannh.bounces.google.com:.lbl8.mailshell.net-66.100.201.100 62.18.0.100,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:fp,MSB L:0,DNSB X-HE-Tag: card53_47c5fdf3a571c X-Filterd-Recvd-Size: 22679 Received: from mail-qt1-f201.google.com (mail-qt1-f201.google.com [209.85.160.201]) by imf37.hostedemail.com (Postfix) with ESMTP for ; Tue, 28 Apr 2020 03:28:13 +0000 (UTC) Received: by mail-qt1-f201.google.com with SMTP id x24so23029283qta.4 for ; Mon, 27 Apr 2020 20:28:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=w+hbcu739HmI811AIn8u188RMugp30gOckHL/I31PIs=; b=h6sItOR6gIl8yMZtGsc+KvsVlI+KhsruQRIe6oh58cLsmVum5l9wKxoTmyIdqtVdgo yEc6kD5sqRR/gS4NL718J6TSkezc4OKHlfKLFCIwKVdpDxxfZV5MgFT0Mzu+vZhVAKQt 052RL8teyQBHk0lq1AYF9MPxf3zL4XPU9gw0NGE7zoQITVg5AUzMQ+UOBM2Vb2y9IDCz B3jF2efq3YASKtJJX63zyanU6b2+yy/AnyRpkInxMz6doYJxWhk3dh7JIZQZB6lBC35u bKk19vYh8vIeH0+8DufEIqzAmRArX1Gf0ujFrXP9p963UhX8+N7F8FMpPTOacony2GWd XZKA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=w+hbcu739HmI811AIn8u188RMugp30gOckHL/I31PIs=; b=cjaP9kS6hYySEk3VBb0OGIaSPE1Uxmh3ttPb31NT2lB692JZUXetWoF8gRuK9SSmpS y+8OFGiEJ8dGebY1lRrAhoUzuCCrXqUwOXJuhW3axn3ggGCXQD0lD0hxdkzZQxhoaurW k5yqDcTe1puo57uLd7CyGLaRcuBScuD7bZrAtFSVi/7536xxuAdniEQwiqHP0GzO2Yn0 PWkxa+vPd96nCYBFyMGVq3y2ef8HT44nT48K64T+zrT2Ep5DxdR+TPI0nBt6IUo8gyTA S7YaoqEN9f8r2KbC5ceTagC6Pspe3srFm839CIKy5pKZ3oPo1EstFXCMBha0O0EXwLxy 8h8w== X-Gm-Message-State: AGi0PublNlbKe7hZnzJNHxAwZugHkOxcDHIMGLRHh7e0y2PiExcNRme2 4TdExnN6Rug3iWjMnciMrIL23THpoA== X-Google-Smtp-Source: APiQypJOYW9IMSHyn80lvF9/d8mmeHLcI3xVGJ4nLfSki9gusCiLdI6vfYSG9/6bobsr6VbBiD3ICbBGtw== X-Received: by 2002:a0c:b797:: with SMTP id l23mr26280786qve.204.1588044492423; Mon, 27 Apr 2020 20:28:12 -0700 (PDT) Date: Tue, 28 Apr 2020 05:27:44 +0200 In-Reply-To: <20200428032745.133556-1-jannh@google.com> Message-Id: <20200428032745.133556-5-jannh@google.com> Mime-Version: 1.0 References: <20200428032745.133556-1-jannh@google.com> X-Mailer: git-send-email 2.26.2.303.gf8c07b1a785-goog Subject: [PATCH 4/5] binfmt_elf, binfmt_elf_fdpic: Use a VMA list snapshot From: Jann Horn To: Andrew Morton Cc: Linus Torvalds , Christoph Hellwig , linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org, Alexander Viro , "Eric W . Biederman" , Oleg Nesterov , Russell King , linux-arm-kernel@lists.infradead.org, Mark Salter , Aurelien Jacquiot , linux-c6x-dev@linux-c6x.org, Yoshinori Sato , Rich Felker , linux-sh@vger.kernel.org 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: In both binfmt_elf and binfmt_elf_fdpic, use a new helper dump_vma_snapshot() to take a snapshot of the VMA list (including the gate VMA, if we have one) while protected by the mmap_sem, and then use that snapshot instead of walking the VMA list without locking. An alternative approach would be to keep the mmap_sem held across the entire core dumping operation; however, keeping the mmap_sem locked while we may be blocked for an unbounded amount of time (e.g. because we're dumping to a FUSE filesystem or so) isn't really optimal; the mmap_sem blocks things like the ->release handler of userfaultfd, and we don't really want critical system daemons to grind to a halt just because someone "gifted" them SCM_RIGHTS to an eternally-locked userfaultfd, or something like that. Since both the normal ELF code and the FDPIC ELF code need this functionality (and if any other binfmt wants to add coredump support in the future, they'd probably need it, too), implement this with a common helper in fs/coredump.c. A downside of this approach is that we now need a bigger amount of kernel memory per userspace VMA in the normal ELF case, and that we need O(n) kernel memory in the FDPIC ELF case at all; but 40 bytes per VMA shouldn't be terribly bad. Signed-off-by: Jann Horn --- fs/binfmt_elf.c | 152 +++++++++++++-------------------------- fs/binfmt_elf_fdpic.c | 86 ++++++++++------------ fs/coredump.c | 68 ++++++++++++++++++ include/linux/coredump.h | 10 +++ 4 files changed, 168 insertions(+), 148 deletions(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index fb36469848323..dffe9dc8497ca 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1292,8 +1292,12 @@ static bool always_dump_vma(struct vm_area_struct *vma) return false; } +#define DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER 1 + /* * Decide what to dump of a segment, part, all or none. + * The result must be fixed up via vma_dump_size_fixup() once we're in a context + * that's allowed to sleep arbitrarily long. */ static unsigned long vma_dump_size(struct vm_area_struct *vma, unsigned long mm_flags) @@ -1348,30 +1352,15 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma, /* * If this looks like the beginning of a DSO or executable mapping, - * check for an ELF header. If we find one, dump the first page to - * aid in determining what was mapped here. + * we'll check for an ELF header. If we find one, we'll dump the first + * page to aid in determining what was mapped here. + * However, we shouldn't sleep on userspace reads while holding the + * mmap_sem, so we just return a placeholder for now that will be fixed + * up later in vma_dump_size_fixup(). */ if (FILTER(ELF_HEADERS) && - vma->vm_pgoff == 0 && (vma->vm_flags & VM_READ)) { - u32 __user *header = (u32 __user *) vma->vm_start; - u32 word; - /* - * Doing it this way gets the constant folded by GCC. - */ - union { - u32 cmp; - char elfmag[SELFMAG]; - } magic; - BUILD_BUG_ON(SELFMAG != sizeof word); - magic.elfmag[EI_MAG0] = ELFMAG0; - magic.elfmag[EI_MAG1] = ELFMAG1; - magic.elfmag[EI_MAG2] = ELFMAG2; - magic.elfmag[EI_MAG3] = ELFMAG3; - if (unlikely(get_user(word, header))) - word = 0; - if (word == magic.cmp) - return PAGE_SIZE; - } + vma->vm_pgoff == 0 && (vma->vm_flags & VM_READ)) + return DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER; #undef FILTER @@ -1381,6 +1370,22 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma, return vma->vm_end - vma->vm_start; } +/* Fix up the result from vma_dump_size(), now that we're allowed to sleep. */ +static void vma_dump_size_fixup(struct core_vma_metadata *meta) +{ + char elfmag[SELFMAG]; + + if (meta->dump_size != DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER) + return; + + if (copy_from_user(elfmag, (void __user *)meta->start, SELFMAG)) { + meta->dump_size = 0; + return; + } + meta->dump_size = + (memcmp(elfmag, ELFMAG, SELFMAG) == 0) ? PAGE_SIZE : 0; +} + /* An ELF note in memory */ struct memelfnote { @@ -2124,32 +2129,6 @@ static void free_note_info(struct elf_note_info *info) #endif -static struct vm_area_struct *first_vma(struct task_struct *tsk, - struct vm_area_struct *gate_vma) -{ - struct vm_area_struct *ret = tsk->mm->mmap; - - if (ret) - return ret; - return gate_vma; -} -/* - * Helper function for iterating across a vma list. It ensures that the caller - * will visit `gate_vma' prior to terminating the search. - */ -static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma, - struct vm_area_struct *gate_vma) -{ - struct vm_area_struct *ret; - - ret = this_vma->vm_next; - if (ret) - return ret; - if (this_vma == gate_vma) - return NULL; - return gate_vma; -} - static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, elf_addr_t e_shoff, int segs) { @@ -2176,9 +2155,8 @@ static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, static int elf_core_dump(struct coredump_params *cprm) { int has_dumped = 0; - int segs, i; + int vma_count, segs, i; size_t vma_data_size = 0; - struct vm_area_struct *vma, *gate_vma; struct elfhdr elf; loff_t offset = 0, dataoff; struct elf_note_info info = { }; @@ -2186,30 +2164,21 @@ static int elf_core_dump(struct coredump_params *cprm) struct elf_shdr *shdr4extnum = NULL; Elf_Half e_phnum; elf_addr_t e_shoff; - elf_addr_t *vma_filesz = NULL; + struct core_vma_metadata *vma_meta; + + if (dump_vma_snapshot(cprm, &vma_count, &vma_meta, vma_dump_size)) + return 0; + + for (i = 0; i < vma_count; i++) { + vma_dump_size_fixup(vma_meta + i); + vma_data_size += vma_meta[i].dump_size; + } - /* - * We no longer stop all VM operations. - * - * This is because those proceses that could possibly change map_count - * or the mmap / vma pages are now blocked in do_exit on current - * finishing this core dump. - * - * Only ptrace can touch these memory addresses, but it doesn't change - * the map_count or the pages allocated. So no possibility of crashing - * exists while dumping the mm->vm_next areas to the core file. - */ - /* * The number of segs are recored into ELF header as 16bit value. * Please check DEFAULT_MAX_MAP_COUNT definition when you modify here. */ - segs = current->mm->map_count; - segs += elf_core_extra_phdrs(); - - gate_vma = get_gate_vma(current->mm); - if (gate_vma != NULL) - segs++; + segs = vma_count + elf_core_extra_phdrs(); /* for notes section */ segs++; @@ -2247,24 +2216,6 @@ static int elf_core_dump(struct coredump_params *cprm) dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); - /* - * Zero vma process will get ZERO_SIZE_PTR here. - * Let coredump continue for register state at least. - */ - vma_filesz = kvmalloc(array_size(sizeof(*vma_filesz), (segs - 1)), - GFP_KERNEL); - if (!vma_filesz) - goto cleanup; - - for (i = 0, vma = first_vma(current, gate_vma); vma != NULL; - vma = next_vma(vma, gate_vma)) { - unsigned long dump_size; - - dump_size = vma_dump_size(vma, cprm->mm_flags); - vma_filesz[i++] = dump_size; - vma_data_size += dump_size; - } - offset += vma_data_size; offset += elf_core_extra_data_size(); e_shoff = offset; @@ -2285,22 +2236,20 @@ static int elf_core_dump(struct coredump_params *cprm) goto cleanup; /* Write program headers for segments dump */ - for (i = 0, vma = first_vma(current, gate_vma); vma != NULL; - vma = next_vma(vma, gate_vma)) { + for (i = 0; i < vma_count; i++) { + struct core_vma_metadata *meta = vma_meta + i; struct elf_phdr phdr; phdr.p_type = PT_LOAD; phdr.p_offset = offset; - phdr.p_vaddr = vma->vm_start; + phdr.p_vaddr = meta->start; phdr.p_paddr = 0; - phdr.p_filesz = vma_filesz[i++]; - phdr.p_memsz = vma->vm_end - vma->vm_start; + phdr.p_filesz = meta->dump_size; + phdr.p_memsz = meta->end - meta->start; offset += phdr.p_filesz; - phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; - if (vma->vm_flags & VM_WRITE) - phdr.p_flags |= PF_W; - if (vma->vm_flags & VM_EXEC) - phdr.p_flags |= PF_X; + phdr.p_flags = meta->flags & VM_READ ? PF_R : 0; + phdr.p_flags |= meta->flags & VM_WRITE ? PF_W : 0; + phdr.p_flags |= meta->flags & VM_EXEC ? PF_X : 0; phdr.p_align = ELF_EXEC_PAGESIZE; if (!dump_emit(cprm, &phdr, sizeof(phdr))) @@ -2321,9 +2270,10 @@ static int elf_core_dump(struct coredump_params *cprm) if (!dump_skip(cprm, dataoff - cprm->pos)) goto cleanup; - for (i = 0, vma = first_vma(current, gate_vma); vma != NULL; - vma = next_vma(vma, gate_vma)) { - if (!dump_user_range(cprm, vma->vm_start, vma_filesz[i++])) + for (i = 0; i < vma_count; i++) { + struct core_vma_metadata *meta = vma_meta + i; + + if (!dump_user_range(cprm, meta->start, meta->dump_size)) goto cleanup; } dump_truncate(cprm); @@ -2339,7 +2289,7 @@ static int elf_core_dump(struct coredump_params *cprm) cleanup: free_note_info(&info); kfree(shdr4extnum); - kvfree(vma_filesz); + kvfree(vma_meta); kfree(phdr4note); return has_dumped; } diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 938f66f4de9b2..bde51f40085b9 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -1190,7 +1190,8 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params, * * I think we should skip something. But I am not sure how. H.J. */ -static int maydump(struct vm_area_struct *vma, unsigned long mm_flags) +static unsigned long vma_dump_size(struct vm_area_struct *vma, + unsigned long mm_flags) { int dump_ok; @@ -1219,7 +1220,7 @@ static int maydump(struct vm_area_struct *vma, unsigned long mm_flags) kdcore("%08lx: %08lx: %s (DAX private)", vma->vm_start, vma->vm_flags, dump_ok ? "yes" : "no"); } - return dump_ok; + goto out; } /* By default, dump shared memory if mapped from an anonymous file. */ @@ -1228,13 +1229,13 @@ static int maydump(struct vm_area_struct *vma, unsigned long mm_flags) dump_ok = test_bit(MMF_DUMP_ANON_SHARED, &mm_flags); kdcore("%08lx: %08lx: %s (share)", vma->vm_start, vma->vm_flags, dump_ok ? "yes" : "no"); - return dump_ok; + goto out; } dump_ok = test_bit(MMF_DUMP_MAPPED_SHARED, &mm_flags); kdcore("%08lx: %08lx: %s (share)", vma->vm_start, vma->vm_flags, dump_ok ? "yes" : "no"); - return dump_ok; + goto out; } #ifdef CONFIG_MMU @@ -1243,14 +1244,16 @@ static int maydump(struct vm_area_struct *vma, unsigned long mm_flags) dump_ok = test_bit(MMF_DUMP_MAPPED_PRIVATE, &mm_flags); kdcore("%08lx: %08lx: %s (!anon)", vma->vm_start, vma->vm_flags, dump_ok ? "yes" : "no"); - return dump_ok; + goto out; } #endif dump_ok = test_bit(MMF_DUMP_ANON_PRIVATE, &mm_flags); kdcore("%08lx: %08lx: %s", vma->vm_start, vma->vm_flags, dump_ok ? "yes" : "no"); - return dump_ok; + +out: + return dump_ok ? vma->vm_end - vma->vm_start : 0; } /* An ELF note in memory */ @@ -1490,31 +1493,30 @@ static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum, /* * dump the segments for an MMU process */ -static bool elf_fdpic_dump_segments(struct coredump_params *cprm) +static bool elf_fdpic_dump_segments(struct coredump_params *cprm, + struct core_vma_metadata *vma_meta, + int vma_count) { - struct vm_area_struct *vma; + int i; - for (vma = current->mm->mmap; vma; vma = vma->vm_next) { - unsigned long addr; + for (i = 0; i < vma_count; i++) { + struct core_vma_metadata *meta = vma_meta + i; - if (!maydump(vma, cprm->mm_flags)) - continue; - - if (!dump_user_range(cprm, vma->vm_start, - vma->vma_end - vma->vm_start)) + if (!dump_user_range(cprm, meta->start, meta->dump_size)) return false; } return true; } -static size_t elf_core_vma_data_size(unsigned long mm_flags) +static size_t elf_core_vma_data_size(unsigned long mm_flags, + struct core_vma_metadata *vma_meta, + int vma_count) { - struct vm_area_struct *vma; size_t size = 0; + int i; - for (vma = current->mm->mmap; vma; vma = vma->vm_next) - if (maydump(vma, mm_flags)) - size += vma->vm_end - vma->vm_start; + for (i = 0; i < vma_count; i++) + size += vma_meta[i].dump_size; return size; } @@ -1529,9 +1531,8 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) { #define NUM_NOTES 6 int has_dumped = 0; - int segs; + int vma_count, segs; int i; - struct vm_area_struct *vma; struct elfhdr *elf = NULL; loff_t offset = 0, dataoff; int numnote; @@ -1552,18 +1553,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) elf_addr_t e_shoff; struct core_thread *ct; struct elf_thread_status *tmp; - - /* - * We no longer stop all VM operations. - * - * This is because those proceses that could possibly change map_count - * or the mmap / vma pages are now blocked in do_exit on current - * finishing this core dump. - * - * Only ptrace can touch these memory addresses, but it doesn't change - * the map_count or the pages allocated. So no possibility of crashing - * exists while dumping the mm->vm_next areas to the core file. - */ + struct core_vma_metadata *vma_meta = NULL; /* alloc memory for large data structures: too large to be on stack */ elf = kmalloc(sizeof(*elf), GFP_KERNEL); @@ -1588,6 +1578,9 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) goto cleanup; #endif + if (dump_vma_snapshot(cprm, &vma_count, &vma_meta, vma_dump_size)) + goto cleanup; + for (ct = current->mm->core_state->dumper.next; ct; ct = ct->next) { tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); @@ -1611,8 +1604,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) fill_prstatus(prstatus, current, cprm->siginfo->si_signo); elf_core_copy_regs(&prstatus->pr_reg, cprm->regs); - segs = current->mm->map_count; - segs += elf_core_extra_phdrs(); + segs = vma_count + elf_core_extra_phdrs(); /* for notes section */ segs++; @@ -1680,7 +1672,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) /* Page-align dumped data */ dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE); - offset += elf_core_vma_data_size(cprm->mm_flags); + offset += elf_core_vma_data_size(cprm->mm_flags, vma_meta, vma_count); offset += elf_core_extra_data_size(); e_shoff = offset; @@ -1700,24 +1692,23 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) goto cleanup; /* write program headers for segments dump */ - for (vma = current->mm->mmap; vma; vma = vma->vm_next) { + for (i = 0; i < vma_count; i++) { + struct core_vma_metadata *meta = vma_meta + i; struct elf_phdr phdr; size_t sz; - sz = vma->vm_end - vma->vm_start; + sz = meta->end - meta->start; phdr.p_type = PT_LOAD; phdr.p_offset = offset; - phdr.p_vaddr = vma->vm_start; + phdr.p_vaddr = meta->start; phdr.p_paddr = 0; - phdr.p_filesz = maydump(vma, cprm->mm_flags) ? sz : 0; + phdr.p_filesz = meta->dump_size; phdr.p_memsz = sz; offset += phdr.p_filesz; - phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; - if (vma->vm_flags & VM_WRITE) - phdr.p_flags |= PF_W; - if (vma->vm_flags & VM_EXEC) - phdr.p_flags |= PF_X; + phdr.p_flags = meta->flags & VM_READ ? PF_R : 0; + phdr.p_flags |= meta->flags & VM_WRITE ? PF_W : 0; + phdr.p_flags |= meta->flags & VM_EXEC ? PF_X : 0; phdr.p_align = ELF_EXEC_PAGESIZE; if (!dump_emit(cprm, &phdr, sizeof(phdr))) @@ -1745,7 +1736,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) if (!dump_skip(cprm, dataoff - cprm->pos)) goto cleanup; - if (!elf_fdpic_dump_segments(cprm)) + if (!elf_fdpic_dump_segments(cprm, vma_meta, vma_count)) goto cleanup; if (!elf_core_write_extra_data(cprm)) @@ -1769,6 +1760,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm) list_del(tmp); kfree(list_entry(tmp, struct elf_thread_status, list)); } + kvfree(vma_meta); kfree(phdr4note); kfree(elf); kfree(prstatus); diff --git a/fs/coredump.c b/fs/coredump.c index 3385de8a62302..f1efa0c93b3af 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -919,3 +919,71 @@ void dump_truncate(struct coredump_params *cprm) } } EXPORT_SYMBOL(dump_truncate); + +static struct vm_area_struct *first_vma(struct task_struct *tsk, + struct vm_area_struct *gate_vma) +{ + struct vm_area_struct *ret = tsk->mm->mmap; + + if (ret) + return ret; + return gate_vma; +} +/* + * Helper function for iterating across a vma list. It ensures that the caller + * will visit `gate_vma' prior to terminating the search. + */ +static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma, + struct vm_area_struct *gate_vma) +{ + struct vm_area_struct *ret; + + ret = this_vma->vm_next; + if (ret) + return ret; + if (this_vma == gate_vma) + return NULL; + return gate_vma; +} + +/* + * Under the mmap_sem, take a snapshot of relevant information about the task's + * VMAs. + */ +int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count, + struct core_vma_metadata **vma_meta, + unsigned long (*dump_size_cb)(struct vm_area_struct *, unsigned long)) +{ + struct vm_area_struct *vma, *gate_vma; + struct mm_struct *mm = current->mm; + int i; + + if (down_read_killable(&mm->mmap_sem)) + return -EINTR; + + gate_vma = get_gate_vma(mm); + *vma_count = mm->map_count + (gate_vma ? 1 : 0); + + *vma_meta = kvmalloc_array(*vma_count, sizeof(**vma_meta), GFP_KERNEL); + if (!*vma_meta) { + up_read(&mm->mmap_sem); + return -ENOMEM; + } + + for (i = 0, vma = first_vma(current, gate_vma); vma != NULL; + vma = next_vma(vma, gate_vma)) { + (*vma_meta)[i++] = (struct core_vma_metadata) { + .start = vma->vm_start, + .end = vma->vm_end, + .flags = vma->vm_flags, + .dump_size = dump_size_cb(vma, cprm->mm_flags) + }; + } + + up_read(&mm->mmap_sem); + + if (WARN_ON(i != *vma_count)) + return -EFAULT; + + return 0; +} diff --git a/include/linux/coredump.h b/include/linux/coredump.h index 4289dc21c04ff..d3387866dce7b 100644 --- a/include/linux/coredump.h +++ b/include/linux/coredump.h @@ -7,6 +7,13 @@ #include #include +struct core_vma_metadata { + unsigned long start, end; + unsigned long filesize; + unsigned long flags; + unsigned long dump_size; +}; + /* * These are the only things you should do on a core-file: use only these * functions to write out all the necessary info. @@ -18,6 +25,9 @@ extern int dump_align(struct coredump_params *cprm, int align); extern void dump_truncate(struct coredump_params *cprm); int dump_user_range(struct coredump_params *cprm, unsigned long start, unsigned long len); +int dump_vma_snapshot(struct coredump_params *cprm, int *vma_count, + struct core_vma_metadata **vma_meta, + unsigned long (*dump_size_cb)(struct vm_area_struct *, unsigned long)); #ifdef CONFIG_COREDUMP extern void do_coredump(const kernel_siginfo_t *siginfo); #else From patchwork Tue Apr 28 03:27:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jann Horn X-Patchwork-Id: 11513731 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 86B9F1667 for ; Tue, 28 Apr 2020 03:28:18 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 510AA206D6 for ; Tue, 28 Apr 2020 03:28:18 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="IidsVYIW" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 510AA206D6 Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 4FF348E000A; Mon, 27 Apr 2020 23:28:17 -0400 (EDT) Delivered-To: linux-mm-outgoing@kvack.org Received: by kanga.kvack.org (Postfix, from userid 40) id 4AEAC8E0001; Mon, 27 Apr 2020 23:28:17 -0400 (EDT) X-Original-To: int-list-linux-mm@kvack.org X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 39CE58E000A; Mon, 27 Apr 2020 23:28:17 -0400 (EDT) X-Original-To: linux-mm@kvack.org X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0244.hostedemail.com [216.40.44.244]) by kanga.kvack.org (Postfix) with ESMTP id 275898E0001 for ; Mon, 27 Apr 2020 23:28:17 -0400 (EDT) Received: from smtpin28.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay02.hostedemail.com (Postfix) with ESMTP id DC72D584C for ; Tue, 28 Apr 2020 03:28:16 +0000 (UTC) X-FDA: 76755830592.28.end63_4845610d8fd2b X-Spam-Summary: 2,0,0,39763041b98ac314,d41d8cd98f00b204,3z6knxgukck4xobbvuccuzs.qcazwbil-aayjoqy.cfu@flex--jannh.bounces.google.com,,RULES_HIT:41:152:355:379:541:800:960:973:981:988:989:1260:1277:1313:1314:1345:1359:1437:1516:1518:1535:1542:1593:1594:1711:1730:1747:1777:1792:2393:2559:2562:3138:3139:3140:3141:3142:3152:3353:3865:3867:3868:3870:3871:3872:4250:4321:4605:5007:6261:6653:6742:7903:9969:10004:10400:11026:11232:11233:11473:11658:11914:12043:12296:12297:12438:12555:12679:12895:12986:13161:13229:14096:14097:14181:14394:14659:14721:21080:21444:21627:21987:21990:30012:30054:30070,0,RBL:209.85.219.73:@flex--jannh.bounces.google.com:.lbl8.mailshell.net-66.100.201.100 62.18.0.100,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:fp,MSBL:0,DNSBL:neutral,Custom_rules:0:0:0,LFtime:24,LUA_SUMMARY:none X-HE-Tag: end63_4845610d8fd2b X-Filterd-Recvd-Size: 5270 Received: from mail-qv1-f73.google.com (mail-qv1-f73.google.com [209.85.219.73]) by imf14.hostedemail.com (Postfix) with ESMTP for ; Tue, 28 Apr 2020 03:28:16 +0000 (UTC) Received: by mail-qv1-f73.google.com with SMTP id ck5so21070223qvb.18 for ; Mon, 27 Apr 2020 20:28:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=S74qc3gT0+GaAOfxP9OW8h7LX2dHXzF9FcHNnI79iRU=; b=IidsVYIWxuA6ZMq4mduyFOFvGK2ppYXoJH0wqJkIqqc+oYorXd4D8TC5648uk83yp9 Wk6TRGHazyI7/dl0YaKYN69J4JYYCXH0CXmm45CYpg5crMvD0sBEhoVk0OCbke9ON03l t++54shNE4fldweicnAFUG7BlPQRKlLvBj3ELH6NgoiG7tKyqU09KfhIbfcLrXBCqA5+ ERaEY1qXQhMRhOoex9Yt2JzsgbxA1o9//qxW7Rl64iVEwEvm2M5aNBfC/sbBWFTgc2W9 OB2UUdMDfKlny1MscN1lZUlNUVq8y5d3lfxTGrfnTL+k4Xh6lfcXpgzN0XvkrZqCgzwF SQ4g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=S74qc3gT0+GaAOfxP9OW8h7LX2dHXzF9FcHNnI79iRU=; b=WMnYNv4HyHqjFdiuC2EQFSws9E1zgYFkG+KXbqSb/hi77AykI+khf8dJ4t7K3twxcI f/sxDGdErSQDE74m8NnR59g9It2kYzWyG0Mu5vFzSQ8YKbW6K8iykooNyRUg+N7nNUJs j7mgskgvrWA5T45kkwQm4+/ZsOY0EQkro6pdHHFryF1PtDYLenCYG1cTg4j9wkzvA+r5 XaKt4pma4mZAj7EJKDujsXTEejTlcnl/TeUUiIo3yIq+IzeSC+RWPVS/xgXfqD048Gzd 0OsunNPaujaxfVtUOwVNGtEf+PW8oFu92ryTyL6Tb69hI56/sBvO+ZJsGhXfx7KX2v3m Qfdg== X-Gm-Message-State: AGi0PuYEuapYNEeSHbUBJujd1Q2qHdgY2rJJbPGrrOMQgHPXP//kcbOU OO5U7P6eNoF2Q+8kQpo3Nx4vQ0WX1w== X-Google-Smtp-Source: APiQypKNWrwmeyovNjE39gEB3tk3kbcuILr7RYV7vdkJNUwXcv+LEB33zDblKbOqInzqOcSp3nptjlK/lg== X-Received: by 2002:a0c:99ca:: with SMTP id y10mr18997354qve.217.1588044495889; Mon, 27 Apr 2020 20:28:15 -0700 (PDT) Date: Tue, 28 Apr 2020 05:27:45 +0200 In-Reply-To: <20200428032745.133556-1-jannh@google.com> Message-Id: <20200428032745.133556-6-jannh@google.com> Mime-Version: 1.0 References: <20200428032745.133556-1-jannh@google.com> X-Mailer: git-send-email 2.26.2.303.gf8c07b1a785-goog Subject: [PATCH 5/5] mm/gup: Take mmap_sem in get_dump_page() From: Jann Horn To: Andrew Morton Cc: Linus Torvalds , Christoph Hellwig , linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-fsdevel@vger.kernel.org, Alexander Viro , "Eric W . Biederman" , Oleg Nesterov , Russell King , linux-arm-kernel@lists.infradead.org, Mark Salter , Aurelien Jacquiot , linux-c6x-dev@linux-c6x.org, Yoshinori Sato , Rich Felker , linux-sh@vger.kernel.org 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: Properly take the mmap_sem before calling into the GUP code from get_dump_page(); and play nice, allowing __get_user_pages_locked() to drop the mmap_sem if it has to sleep. This requires adjusting the check in __get_user_pages_locked() to be slightly less strict: While `vmas != NULL` is normally incompatible with the lock-dropping retry logic, it's fine if we only want a single page, because then retries can only happen when we haven't grabbed any pages yet. Signed-off-by: Jann Horn --- mm/gup.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/mm/gup.c b/mm/gup.c index 9a7e83772f1fe..4bb4149c0e259 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -1261,7 +1261,8 @@ static __always_inline long __get_user_pages_locked(struct task_struct *tsk, if (locked) { /* if VM_FAULT_RETRY can be returned, vmas become invalid */ - BUG_ON(vmas); + if (WARN_ON(vmas && nr_pages != 1)) + return -EFAULT; /* check caller initialized locked */ BUG_ON(*locked != 1); } @@ -1548,18 +1549,28 @@ static long __get_user_pages_locked(struct task_struct *tsk, * NULL wherever the ZERO_PAGE, or an anonymous pte_none, has been found - * allowing a hole to be left in the corefile to save diskspace. * - * Called without mmap_sem, but after all other threads have been killed. + * Called without mmap_sem (takes and releases the mmap_sem by itself). */ struct page *get_dump_page(unsigned long addr) { + struct mm_struct *mm = current->mm; struct vm_area_struct *vma; struct page *page; + int locked = 1; + int ret; - if (__get_user_pages(current, current->mm, addr, 1, - FOLL_FORCE | FOLL_DUMP | FOLL_GET, &page, &vma, - NULL) < 1) + if (down_read_killable(&mm->mmap_sem)) + return NULL; + ret = __get_user_pages_locked(current, mm, addr, 1, &page, &vma, + &locked, + FOLL_FORCE | FOLL_DUMP | FOLL_GET); + if (ret != 1) { + if (locked) + up_read(&mm->mmap_sem); return NULL; + } flush_cache_page(vma, addr, page_to_pfn(page)); + up_read(&mm->mmap_sem); return page; }