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 79218C433FE for ; Mon, 28 Mar 2022 11:20:58 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 0F4FF8D0003; Mon, 28 Mar 2022 07:20:58 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 0A42E8D0001; Mon, 28 Mar 2022 07:20:58 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id EAE368D0003; Mon, 28 Mar 2022 07:20:57 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0122.hostedemail.com [216.40.44.122]) by kanga.kvack.org (Postfix) with ESMTP id DE9078D0001 for ; Mon, 28 Mar 2022 07:20:57 -0400 (EDT) Received: from smtpin17.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay01.hostedemail.com (Postfix) with ESMTP id 93E04182751AF for ; Mon, 28 Mar 2022 11:20:57 +0000 (UTC) X-FDA: 79293552954.17.5BDD96E Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by imf22.hostedemail.com (Postfix) with ESMTP id 1E804C0033 for ; Mon, 28 Mar 2022 11:20:56 +0000 (UTC) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 210F06114A; Mon, 28 Mar 2022 11:20:56 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1FD78C34110; Mon, 28 Mar 2022 11:20:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1648466455; bh=Y0U/1oukvFPpkPm6qQ6VpXiB5QKiZkyncQiMEoo+SMs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=kqMurqdtlKikrGkUkgSlVqh9B3X/wbZQk6cSiqPlVoQj4wE3SUbEzq5/DE+vAmVVu /8sBOUG5UGo9HmDjXVr98gnmjgoXY6trS7dJtd7EJwsfxYMullLoB90VSAXyT32fo4 jf2fHX5vU0F5CcHOr/QGxsU3qfkkB42ZEj96KnZMqanwrRO6T95krT6G85yJoDXs8P U+bCcxTnXMquU/G+RVJXpDTL7m7TLRQ2A6al38/8DWt55PjM+bI2+QndPCxVFsrQhY 24AVmfM4NAu9jo7dEjhXyoQTz3Fx+p1FdfAKiWFwfxBP8TA8+KxIH9EvwWq218mAjC Ka+uFT328HdKg== From: Sasha Levin To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Akira Kawata , kernel test robot , Kees Cook , Sasha Levin , viro@zeniv.linux.org.uk, linux-fsdevel@vger.kernel.org, linux-mm@kvack.org Subject: [PATCH AUTOSEL 5.16 22/35] fs/binfmt_elf: Fix AT_PHDR for unusual ELF files Date: Mon, 28 Mar 2022 07:19:58 -0400 Message-Id: <20220328112011.1555169-22-sashal@kernel.org> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220328112011.1555169-1-sashal@kernel.org> References: <20220328112011.1555169-1-sashal@kernel.org> MIME-Version: 1.0 X-stable: review X-Patchwork-Hint: Ignore Authentication-Results: imf22.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=kqMurqdt; spf=pass (imf22.hostedemail.com: domain of sashal@kernel.org designates 139.178.84.217 as permitted sender) smtp.mailfrom=sashal@kernel.org; dmarc=pass (policy=none) header.from=kernel.org X-Stat-Signature: qwajnmxqyeo4exk98yhwnidodqx5yi4q X-Rspam-User: X-Rspamd-Server: rspam12 X-Rspamd-Queue-Id: 1E804C0033 X-HE-Tag: 1648466456-541569 Content-Transfer-Encoding: quoted-printable 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: From: Akira Kawata [ Upstream commit 0da1d5002745cdc721bc018b582a8a9704d56c42 ] BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=3D197921 As pointed out in the discussion of buglink, we cannot calculate AT_PHDR as the sum of load_addr and exec->e_phoff. : The AT_PHDR of ELF auxiliary vectors should point to the memory address : of program header. But binfmt_elf.c calculates this address as follows: : : NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff); : : which is wrong since e_phoff is the file offset of program header and : load_addr is the memory base address from PT_LOAD entry. : : The ld.so uses AT_PHDR as the memory address of program header. In norm= al : case, since the e_phoff is usually 64 and in the first PT_LOAD region, = it : is the correct program header address. : : But if the address of program header isn't equal to the first PT_LOAD : address + e_phoff (e.g. Put the program header in other non-consecutiv= e : PT_LOAD region), ld.so will try to read program header from wrong addre= ss : then crash or use incorrect program header. This is because exec->e_phoff is the offset of PHDRs in the file and the address of PHDRs in the memory may differ from it. This patch fixes the bug by calculating the address of program headers from PT_LOADs directly. Signed-off-by: Akira Kawata Reported-by: kernel test robot Acked-by: Kees Cook Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20220127124014.338760-2-akirakawata1@gmai= l.com Signed-off-by: Sasha Levin --- fs/binfmt_elf.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index d19762dc90fe..c4de845f86c8 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -170,8 +170,8 @@ static int padzero(unsigned long elf_bss) =20 static int create_elf_tables(struct linux_binprm *bprm, const struct elfhdr *exec, - unsigned long load_addr, unsigned long interp_load_addr, - unsigned long e_entry) + unsigned long interp_load_addr, + unsigned long e_entry, unsigned long phdr_addr) { struct mm_struct *mm =3D current->mm; unsigned long p =3D bprm->p; @@ -257,7 +257,7 @@ create_elf_tables(struct linux_binprm *bprm, const st= ruct elfhdr *exec, NEW_AUX_ENT(AT_HWCAP, ELF_HWCAP); NEW_AUX_ENT(AT_PAGESZ, ELF_EXEC_PAGESIZE); NEW_AUX_ENT(AT_CLKTCK, CLOCKS_PER_SEC); - NEW_AUX_ENT(AT_PHDR, load_addr + exec->e_phoff); + NEW_AUX_ENT(AT_PHDR, phdr_addr); NEW_AUX_ENT(AT_PHENT, sizeof(struct elf_phdr)); NEW_AUX_ENT(AT_PHNUM, exec->e_phnum); NEW_AUX_ENT(AT_BASE, interp_load_addr); @@ -823,7 +823,7 @@ static int parse_elf_properties(struct file *f, const= struct elf_phdr *phdr, static int load_elf_binary(struct linux_binprm *bprm) { struct file *interpreter =3D NULL; /* to shut gcc up */ - unsigned long load_addr =3D 0, load_bias =3D 0; + unsigned long load_addr, load_bias =3D 0, phdr_addr =3D 0; int load_addr_set =3D 0; unsigned long error; struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata =3D NULL; @@ -1180,6 +1180,17 @@ static int load_elf_binary(struct linux_binprm *bp= rm) reloc_func_desc =3D load_bias; } } + + /* + * Figure out which segment in the file contains the Program + * Header table, and map to the associated memory address. + */ + if (elf_ppnt->p_offset <=3D elf_ex->e_phoff && + elf_ex->e_phoff < elf_ppnt->p_offset + elf_ppnt->p_filesz) { + phdr_addr =3D elf_ex->e_phoff - elf_ppnt->p_offset + + elf_ppnt->p_vaddr; + } + k =3D elf_ppnt->p_vaddr; if ((elf_ppnt->p_flags & PF_X) && k < start_code) start_code =3D k; @@ -1215,6 +1226,7 @@ static int load_elf_binary(struct linux_binprm *bpr= m) } =20 e_entry =3D elf_ex->e_entry + load_bias; + phdr_addr +=3D load_bias; elf_bss +=3D load_bias; elf_brk +=3D load_bias; start_code +=3D load_bias; @@ -1278,8 +1290,8 @@ static int load_elf_binary(struct linux_binprm *bpr= m) goto out; #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ =20 - retval =3D create_elf_tables(bprm, elf_ex, - load_addr, interp_load_addr, e_entry); + retval =3D create_elf_tables(bprm, elf_ex, interp_load_addr, + e_entry, phdr_addr); if (retval < 0) goto out; =20 --=20 2.34.1