From mboxrd@z Thu Jan 1 00:00:00 1970 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 4545EC4332F for ; Mon, 6 Nov 2023 23:15:29 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id D99516B017F; Mon, 6 Nov 2023 18:15:28 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id D4A3D6B0181; Mon, 6 Nov 2023 18:15:28 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id C115C6B0183; Mon, 6 Nov 2023 18:15:28 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id B16A56B017F for ; Mon, 6 Nov 2023 18:15:28 -0500 (EST) Received: from smtpin01.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay04.hostedemail.com (Postfix) with ESMTP id 8855A1A090E for ; Mon, 6 Nov 2023 23:15:28 +0000 (UTC) X-FDA: 81429087936.01.1FCC3FA Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by imf27.hostedemail.com (Postfix) with ESMTP id 7C6714001F for ; Mon, 6 Nov 2023 23:15:26 +0000 (UTC) Authentication-Results: imf27.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=BpS6pO4A; dmarc=pass (policy=none) header.from=kernel.org; spf=pass (imf27.hostedemail.com: domain of sashal@kernel.org designates 145.40.68.75 as permitted sender) smtp.mailfrom=sashal@kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1699312526; 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:in-reply-to:references:references:dkim-signature; bh=+JTpp5SNGlNV1/3ACmpI15OgIYEpHOUHHv9gp09jmdg=; b=YraMnSKw/tZ0q3UgMSfFg47xCX9NtHmZoLCKeX2PUWZFyIPvkQ6ti4vQYgKBxbXR/bJWW0 atQ+0WvZ8BBTpJWSf6VqbzTxSEF7BEsuSehCGu+o4AlYMsVrOZRqn0wZFcN1lIHtzpTJR+ vp+hTbro23Z6MBTrouMRGUY9yDWuN1M= ARC-Authentication-Results: i=1; imf27.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=BpS6pO4A; dmarc=pass (policy=none) header.from=kernel.org; spf=pass (imf27.hostedemail.com: domain of sashal@kernel.org designates 145.40.68.75 as permitted sender) smtp.mailfrom=sashal@kernel.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1699312526; a=rsa-sha256; cv=none; b=sDdkGXCEDXkDcP82CKg+IttOLEdsL3zIN9/qsjQJtZubPWGLpbVXr4LiDvzAyC+QezAVZ5 y6XF2rbwcVzwsVJQDko+mpsDqM2TARLORQfWi7DIhpkZSDW8vjG7BB/vYbvjuN7edx7sPz BfVTTJeRmJ0kcJ++QvQ89Y2XyjKdMQ8= Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by ams.source.kernel.org (Postfix) with ESMTP id D8931B81201; Mon, 6 Nov 2023 23:15:24 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id DF4F0C433CD; Mon, 6 Nov 2023 23:15:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1699312524; bh=smXqdwtzc/uYhMp6iKmq+3jEMIqR/0Qf0fi7nKT4HkY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=BpS6pO4AWTOpld8T2s6p/rDCFpir5yTrJod6RGfuOtleYLgzWszNI74ZFUjtthYEC WIPJKsjrLLOO/0n7z5UdWtB1JM7DcqQDx3zC/prkOosv9Mo0XM0r7XydShuXJDfuEN PZx25x4A6Wil85wufN8VDjaqjpN6IDYI3PFu1eWHoR2GkeVF18H2klQ+XXJUWezBZW f0dAeX7TzoxQAE/ZD9Au1NvO+R8QWhtnJMHVL8wXB66eXQS7aqY/mk5Ztq1sY1gdh4 5OU8nAvFQVCnN6UlVs4jSlgwC9my8A5z+awAR/X60tbR0jAcRDk7B5C/HAQAHLzU4R v5IojYhXdR92A== From: Sasha Levin To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: "Eric W. Biederman" , Sebastian Ott , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , Pedro Falcato , Kees Cook , Sasha Levin , viro@zeniv.linux.org.uk, brauner@kernel.org, linux-fsdevel@vger.kernel.org, linux-mm@kvack.org Subject: [PATCH AUTOSEL 6.5 05/13] binfmt_elf: Support segments with 0 filesz and misaligned starts Date: Mon, 6 Nov 2023 18:14:58 -0500 Message-ID: <20231106231514.3735077-5-sashal@kernel.org> X-Mailer: git-send-email 2.42.0 In-Reply-To: <20231106231514.3735077-1-sashal@kernel.org> References: <20231106231514.3735077-1-sashal@kernel.org> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 X-stable: review X-Patchwork-Hint: Ignore X-stable-base: Linux 6.5.10 Content-Transfer-Encoding: 8bit X-Rspamd-Server: rspam09 X-Rspamd-Queue-Id: 7C6714001F X-Stat-Signature: ob5jwakyhwuwpbzmhcztetwh8nmu4dn4 X-Rspam-User: X-HE-Tag: 1699312526-676155 X-HE-Meta: U2FsdGVkX1+UFhHvcsj6f8gUEHpaOM+2QA6TPBN+MbsoIFZbE14MUHLdbph3ne1P2qgcizO44EMwnoJXggBDItB9R/Nwb/YoV8HX8s9h+at57dqzG0mX7V7iQkSrpkkT5LWAjyhkgGGGIfdTNjhloukBUVTys00lgSOgjoU++ec7FTBYwYROzBbvX1BZZ0tAQxbDvJSzgpwGZatLSlwEYFsXEqije++9fB7eIgaQ4Y5E9EHCtdx1GNWLckNTpr7cp0A9H4jFwcX+4m1KQY6T3iFeYaTL1vhusb/NwkLwki7mNVB5dZYtfhGHoKeBBW2vv0fg+96z30Dbnu60DIgzQB5g+dIbB8cNoNsfAgB9PNYDpX8SYnfgYTw/OBCbxO8wIjJ16XBqGa3xGBe+GwMu5kcsg5fUULpK1+ZAU9/oYoQ8QOY/Aon2zom/AytVx8O7ddB3LPLI9NbtSIElaYcuSBo7cFkhbDr/xSzcVMTbr12leZ+HAbBkYlOW6/gFkqGCAzsNmRhzJ469x5pzC9nwkhUPfocaEs4+/G3s7+hRKNUEHCd6cGZleTSSNGWWkjzGNibNKGE7Szph2l3igWezCW7dbQOhq1dfjuC74cKaPdfwY8f7LOnhUKWDtt0Noj2VFWoUI1EjGZf+nUAoj+kVauLhmh/Z3ByonrcvgLSkxQG6mkJ6Qd3pUE9Jr/okQB82U3a+fLnNxTb5yzfC6uPQpiDy9Huhyx/E/uRAr32WRxqRgdK2Kit8cDCXsrV/pDaUwD5usqOu+59lfimFxjgpIOnSsvDjoNXFsAC7WnR+dRcuQZq28PSuwVp5KNFQZBcHRkjQ5KFmZ/Iod7Iqmsdav3rds20J9e6DjDFbhz5w7VFALqc+ct/EkKCeqlgs20tKWFxf35pb5Y1Fee11yU+l+P8kX5OZe66jZwlZuj84+U3PrA6JHWu1nhCE8mE5MlvJeln6RihOWGhM4WcPhnh GSaVRj2+ AghbJWFP4Yds136JPimLNmaH7DQjUmwxbnxo38OjKy8OCRXaN47IwxfbOE8MtPdPRFlycNWnhFZzikRO2JTmywpnqEfuJRHLiKSGcGrCzP/8C/y29Rv91lq8vzAEW9hqUeSh4joOnv3kOZnldx0ziASNX5aGd0YZSGkASaZAuKrp0WVO72++reYQDE1bmMWWuwdQDCfM+3kPb8oRsFQ01MSZwkAWu7Iy5iFuZ+sVbH7wPwRcj9QhbwXj0gbV+utOQo2PQwsoeMFaZC6CN5sW2WIypedoE+pi67163F+NKXocm011p1kJ3Tr8ccFVYFu4U/0bUEGTaDvcEMdYy1rovrH8+uUldugzNsaZixkkIEj2XIyWB/v7qrImoxKpiH9hEs2s7y6jSiQ4Pi3BMZ9dXkZ4h2BFsg/arzoOpqe/0z7zeyUNETtN/avrCcwgygv/oiDGKPVrRAYADaQPpFym4RqNhjiT/tauA2GDldzsj+kgNBAvSGEJ9chbb20U6fOxfXRxUIJtJlxed/VOuOfjomEMYym4sqCm3bysBPnEskA5kgMHgCVKyNQjsFLCDe4B7cqVfrjDBkq5RoDOelIk3Wd/q8UItRqgrPuND0O3HNbsx1f8KG7u7lkzxIrCMTVv/TohSlv9LKJGWcHUJB4YqO5WbRmlCtABOjTrV5kwTbq6T/6VvYmEHtUlob9/C0a3w6FGByLAeW0XrptI= 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: From: "Eric W. Biederman" [ Upstream commit 585a018627b4d7ed37387211f667916840b5c5ea ] Implement a helper elf_load() that wraps elf_map() and performs all of the necessary work to ensure that when "memsz > filesz" the bytes described by "memsz > filesz" are zeroed. An outstanding issue is if the first segment has filesz 0, and has a randomized location. But that is the same as today. In this change I replaced an open coded padzero() that did not clear all of the way to the end of the page, with padzero() that does. I also stopped checking the return of padzero() as there is at least one known case where testing for failure is the wrong thing to do. It looks like binfmt_elf_fdpic may have the proper set of tests for when error handling can be safely completed. I found a couple of commits in the old history https://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git, that look very interesting in understanding this code. commit 39b56d902bf3 ("[PATCH] binfmt_elf: clearing bss may fail") commit c6e2227e4a3e ("[SPARC64]: Missing user access return value checks in fs/binfmt_elf.c and fs/compat.c") commit 5bf3be033f50 ("v2.4.10.1 -> v2.4.10.2") Looking at commit 39b56d902bf3 ("[PATCH] binfmt_elf: clearing bss may fail"): > commit 39b56d902bf35241e7cba6cc30b828ed937175ad > Author: Pavel Machek > Date: Wed Feb 9 22:40:30 2005 -0800 > > [PATCH] binfmt_elf: clearing bss may fail > > So we discover that Borland's Kylix application builder emits weird elf > files which describe a non-writeable bss segment. > > So remove the clear_user() check at the place where we zero out the bss. I > don't _think_ there are any security implications here (plus we've never > checked that clear_user() return value, so whoops if it is a problem). > > Signed-off-by: Pavel Machek > Signed-off-by: Andrew Morton > Signed-off-by: Linus Torvalds It seems pretty clear that binfmt_elf_fdpic with skipping clear_user() for non-writable segments and otherwise calling clear_user(), aka padzero(), and checking it's return code is the right thing to do. I just skipped the error checking as that avoids breaking things. And notably, it looks like Borland's Kylix died in 2005 so it might be safe to just consider read-only segments with memsz > filesz an error. Reported-by: Sebastian Ott Reported-by: Thomas Weißschuh Closes: https://lkml.kernel.org/r/20230914-bss-alloc-v1-1-78de67d2c6dd@weissschuh.net Signed-off-by: "Eric W. Biederman" Link: https://lore.kernel.org/r/87sf71f123.fsf@email.froward.int.ebiederm.org Tested-by: Pedro Falcato Signed-off-by: Sebastian Ott Link: https://lore.kernel.org/r/20230929032435.2391507-1-keescook@chromium.org Signed-off-by: Kees Cook Signed-off-by: Sasha Levin --- fs/binfmt_elf.c | 111 +++++++++++++++++++++--------------------------- 1 file changed, 48 insertions(+), 63 deletions(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 7b3d2d4914073..2a615f476e44e 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -110,25 +110,6 @@ static struct linux_binfmt elf_format = { #define BAD_ADDR(x) (unlikely((unsigned long)(x) >= TASK_SIZE)) -static int set_brk(unsigned long start, unsigned long end, int prot) -{ - start = ELF_PAGEALIGN(start); - end = ELF_PAGEALIGN(end); - if (end > start) { - /* - * Map the last of the bss segment. - * If the header is requesting these pages to be - * executable, honour that (ppc32 needs this). - */ - int error = vm_brk_flags(start, end - start, - prot & PROT_EXEC ? VM_EXEC : 0); - if (error) - return error; - } - current->mm->start_brk = current->mm->brk = end; - return 0; -} - /* We need to explicitly zero any fractional pages after the data section (i.e. bss). This would contain the junk from the file that should not @@ -406,6 +387,51 @@ static unsigned long elf_map(struct file *filep, unsigned long addr, return(map_addr); } +static unsigned long elf_load(struct file *filep, unsigned long addr, + const struct elf_phdr *eppnt, int prot, int type, + unsigned long total_size) +{ + unsigned long zero_start, zero_end; + unsigned long map_addr; + + if (eppnt->p_filesz) { + map_addr = elf_map(filep, addr, eppnt, prot, type, total_size); + if (BAD_ADDR(map_addr)) + return map_addr; + if (eppnt->p_memsz > eppnt->p_filesz) { + zero_start = map_addr + ELF_PAGEOFFSET(eppnt->p_vaddr) + + eppnt->p_filesz; + zero_end = map_addr + ELF_PAGEOFFSET(eppnt->p_vaddr) + + eppnt->p_memsz; + + /* Zero the end of the last mapped page */ + padzero(zero_start); + } + } else { + map_addr = zero_start = ELF_PAGESTART(addr); + zero_end = zero_start + ELF_PAGEOFFSET(eppnt->p_vaddr) + + eppnt->p_memsz; + } + if (eppnt->p_memsz > eppnt->p_filesz) { + /* + * Map the last of the segment. + * If the header is requesting these pages to be + * executable, honour that (ppc32 needs this). + */ + int error; + + zero_start = ELF_PAGEALIGN(zero_start); + zero_end = ELF_PAGEALIGN(zero_end); + + error = vm_brk_flags(zero_start, zero_end - zero_start, + prot & PROT_EXEC ? VM_EXEC : 0); + if (error) + map_addr = error; + } + return map_addr; +} + + static unsigned long total_mapping_size(const struct elf_phdr *phdr, int nr) { elf_addr_t min_addr = -1; @@ -829,7 +855,6 @@ static int load_elf_binary(struct linux_binprm *bprm) struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL; struct elf_phdr *elf_property_phdata = NULL; unsigned long elf_bss, elf_brk; - int bss_prot = 0; int retval, i; unsigned long elf_entry; unsigned long e_entry; @@ -1040,33 +1065,6 @@ static int load_elf_binary(struct linux_binprm *bprm) if (elf_ppnt->p_type != PT_LOAD) continue; - if (unlikely (elf_brk > elf_bss)) { - unsigned long nbyte; - - /* There was a PT_LOAD segment with p_memsz > p_filesz - before this one. Map anonymous pages, if needed, - and clear the area. */ - retval = set_brk(elf_bss + load_bias, - elf_brk + load_bias, - bss_prot); - if (retval) - goto out_free_dentry; - nbyte = ELF_PAGEOFFSET(elf_bss); - if (nbyte) { - nbyte = ELF_MIN_ALIGN - nbyte; - if (nbyte > elf_brk - elf_bss) - nbyte = elf_brk - elf_bss; - if (clear_user((void __user *)elf_bss + - load_bias, nbyte)) { - /* - * This bss-zeroing can fail if the ELF - * file specifies odd protections. So - * we don't check the return value - */ - } - } - } - elf_prot = make_prot(elf_ppnt->p_flags, &arch_state, !!interpreter, false); @@ -1162,7 +1160,7 @@ static int load_elf_binary(struct linux_binprm *bprm) } } - error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, + error = elf_load(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags, total_size); if (BAD_ADDR(error)) { retval = IS_ERR_VALUE(error) ? @@ -1217,10 +1215,8 @@ static int load_elf_binary(struct linux_binprm *bprm) if (end_data < k) end_data = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; - if (k > elf_brk) { - bss_prot = elf_prot; + if (k > elf_brk) elf_brk = k; - } } e_entry = elf_ex->e_entry + load_bias; @@ -1232,18 +1228,7 @@ static int load_elf_binary(struct linux_binprm *bprm) start_data += load_bias; end_data += load_bias; - /* Calling set_brk effectively mmaps the pages that we need - * for the bss and break sections. We must do this before - * mapping in the interpreter, to make sure it doesn't wind - * up getting placed where the bss needs to go. - */ - retval = set_brk(elf_bss, elf_brk, bss_prot); - if (retval) - goto out_free_dentry; - if (likely(elf_bss != elf_brk) && unlikely(padzero(elf_bss))) { - retval = -EFAULT; /* Nobody gets to see this, but.. */ - goto out_free_dentry; - } + current->mm->start_brk = current->mm->brk = ELF_PAGEALIGN(elf_brk); if (interpreter) { elf_entry = load_elf_interp(interp_elf_ex, -- 2.42.0