From nobody Tue Jun 30 23:30:08 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6FC31C433EF for ; Thu, 27 Jan 2022 12:42:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241408AbiA0MmS (ORCPT ); Thu, 27 Jan 2022 07:42:18 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52506 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241382AbiA0MmG (ORCPT ); Thu, 27 Jan 2022 07:42:06 -0500 Received: from mail-pj1-x1031.google.com (mail-pj1-x1031.google.com [IPv6:2607:f8b0:4864:20::1031]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D19B8C06174A; Thu, 27 Jan 2022 04:42:05 -0800 (PST) Received: by mail-pj1-x1031.google.com with SMTP id s2-20020a17090ad48200b001b501977b23so7436792pju.2; Thu, 27 Jan 2022 04:42:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Iqi3lBVf+uaBkRIvQ16oY2EMA/KLN24v0OYA9daSmGM=; b=hIHTRqfZGtRmmbe3zGKxBV/yOlJtRteGQnSy+5NIWxIp9AasPD1vvZB97LoIGsIDQc 8KLgUob8fav1Z2/WpNLYRQjnosgaAs3ydKlxir/Xi7b0XH6/e+7XtZP0q8KoN0wDdwJD t3Ayoh7QDuRWqiMv0MPOMD0OPAfkXZJYL+PpIPQl/quq0ealNHTJun1tbbrMJbvC6ZOo FrRV1ZxHp0vBNn5wEx4TqHuoHwNSrndBxbqNcpah94Dp2RgsB8iCoAnSMWLpllcZX2hJ RKWibYa50mbLu0s1vOlf38E4zqCr87CQ/3dcrOMBvOBq5QeeCbFPRh3QhxLe8bYn7noj FDaw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Iqi3lBVf+uaBkRIvQ16oY2EMA/KLN24v0OYA9daSmGM=; b=3+Cuz+T3m6DvY23S9hc+uvMUwWJzOMywiu8IFSFAqvZcUMSSIF7PuNfW8I7/8AxAQL 3jE7IVC1JWa3Ti2w2isifdF35KTe3sy7EncaBkLAXLLO9Cfz/NhUAzHyYxYCcp9upewl BWKuZ4qRBBAH5HJ4HOXkKp8lald83P2jIvdq99+bW5HLR9Uir6PuNtzisZ5KQdktkxFx gIwGV6IFb8bGnckaR8r7F+PUtO0X5DZ+fPWkdOg99wJRtjkS1Z8v5TJ95qVLRCA2sJwj lau+ok2wlbwroWQ4iUnqSCjzv98Ow046yf5T4XQ8nyyaLsk3Qzoo3mmswR9mu6ohtPu+ qmEQ== X-Gm-Message-State: AOAM531NZFWy0JEFeIt2IPVCqsyIzYejUzVmW4a0QbAb2JLuL/S93fY5 cIpvXXJGVSZWmpuMQppwOps= X-Google-Smtp-Source: ABdhPJwukzDWSol7dDsWgIrzDEWgR22ezRZ04Kmn+TUWXtXAFRigDgBhu2UDR7ujUvYrsXGZ9YyiPw== X-Received: by 2002:a17:902:db0b:: with SMTP id m11mr3206717plx.104.1643287325364; Thu, 27 Jan 2022 04:42:05 -0800 (PST) Received: from localhost.localdomain ([2400:2410:93a3:bc00:d205:ec9:b1c6:b9ee]) by smtp.gmail.com with ESMTPSA id m38sm19071298pgl.64.2022.01.27.04.42.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Jan 2022 04:42:04 -0800 (PST) From: Akira Kawata To: akpm@linux-foundation.org, adobriyan@gmail.com, viro@zeniv.linux.org.uk, keescook@chromium.org, linux-fsdevel@vger.kernel.org, lukas.bulwahn@gmail.com Cc: akirakawata1@gmail.com, kernel test robot , Eric Biederman , linux-kernel@vger.kernel.org Subject: [PATCH v5 1/2] fs/binfmt_elf: Fix AT_PHDR for unusual ELF files Date: Thu, 27 Jan 2022 21:40:16 +0900 Message-Id: <20220127124014.338760-2-akirakawata1@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220127124014.338760-1-akirakawata1@gmail.com> References: <20220127124014.338760-1-akirakawata1@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" 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 normal : 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-consecutive : PT_LOAD region), ld.so will try to read program header from wrong address : 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 --- 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 0a25b8049b74..d120ab03795f 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 stru= ct 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); @@ -822,7 +822,7 @@ static int parse_elf_properties(struct file *f, const s= truct 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; @@ -1168,6 +1168,17 @@ static int load_elf_binary(struct linux_binprm *bprm) 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; @@ -1203,6 +1214,7 @@ static int load_elf_binary(struct linux_binprm *bprm) } =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; @@ -1266,8 +1278,8 @@ static int load_elf_binary(struct linux_binprm *bprm) 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.25.1 From nobody Tue Jun 30 23:30:08 2026 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 vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D39A0C433EF for ; Thu, 27 Jan 2022 12:42:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241375AbiA0MmW (ORCPT ); Thu, 27 Jan 2022 07:42:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52562 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S241403AbiA0MmS (ORCPT ); Thu, 27 Jan 2022 07:42:18 -0500 Received: from mail-pj1-x1029.google.com (mail-pj1-x1029.google.com [IPv6:2607:f8b0:4864:20::1029]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5CB4AC061748; Thu, 27 Jan 2022 04:42:18 -0800 (PST) Received: by mail-pj1-x1029.google.com with SMTP id d15-20020a17090a110f00b001b4e7d27474so2826678pja.2; Thu, 27 Jan 2022 04:42:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=65lHAvgIrvaTDpQ8E/8HtbPHAXdF5rPPGyXj5G9Napk=; b=m5J49hSw3xUMpmLDf2fGSGxn0Q5aRF+lgicWZiT0ciapljFaf3uFyfr3KGlNMEzvMU 6HoVCtvRqf/ZO9VNeQM33Giktu8Ps6mZ+LRhzrs1yraKtt+HdckINvUVNFf/LCcGF8V6 YsvjpvUO/M/yek54njRaDuCT3kIPmEvS1uHqe5RNdkA3sW8au6yjnodbmd1gP1gAe6wS yMvdsjfdnHfg8tXckyudtjcLNKUjHJXWHo5mKRAJLD6HSCJ87Si3yGRmMIdve5e+wDOc oNd185layb+NCUlQhllLguOuaoLe51JQRXFcujR4pBxsf8Fbh09BESiSppD24VrsyPu8 FIKQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=65lHAvgIrvaTDpQ8E/8HtbPHAXdF5rPPGyXj5G9Napk=; b=E+eweg//mN8euUx4n7EXrPCbum2WgLIDp8LtywiT6TumlMXF4/9QWoUPg+bvwQodcr OzT8AgcFaW1LvBkeprDaUNgA5gi9ZFnqoXcpt7zXRqaviX5QBbJD5N6Igl2cnfl1pD9F epLUfWe7l1+tN1OcKRuvQ2mD2FhPMl9nz1vfUlvaz/Ak8pOALkqsgba66b1tDBP/XTTq HU+fFj80ejhvBVF6QDeMkksyNraEMlA4XopVG1sldGwhy1ZR+fFjTPxnF3wRTyGP0yBp 9wOher9lMcBtXjcCowMa5nzL4qSh/swyOVeShdRbgG4cmypRZAQ3o1kXaFoM8WHN4Pcv ZqsA== X-Gm-Message-State: AOAM531w3TcP53rqce+J3A0EBNvIYo84QfYEXKaTuYKvadd7P7jF6aJ1 lSlSaewlD7zUqCAF9S0M2Y4= X-Google-Smtp-Source: ABdhPJwTsY+xzKtPDG+leiEAflZIAbiOUmbhEMGb937hqpADqlAhicEQTyVFFRJGC6s3+v4DBGpGYA== X-Received: by 2002:a17:902:9306:: with SMTP id bc6mr3266618plb.93.1643287337888; Thu, 27 Jan 2022 04:42:17 -0800 (PST) Received: from localhost.localdomain ([2400:2410:93a3:bc00:d205:ec9:b1c6:b9ee]) by smtp.gmail.com with ESMTPSA id m38sm19071298pgl.64.2022.01.27.04.42.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Jan 2022 04:42:17 -0800 (PST) From: Akira Kawata To: akpm@linux-foundation.org, adobriyan@gmail.com, viro@zeniv.linux.org.uk, keescook@chromium.org, linux-fsdevel@vger.kernel.org, lukas.bulwahn@gmail.com Cc: akirakawata1@gmail.com, Eric Biederman , linux-kernel@vger.kernel.org Subject: [PATCH v5 2/2] fs/binfmt_elf: Refactor load_elf_binary function Date: Thu, 27 Jan 2022 21:40:17 +0900 Message-Id: <20220127124014.338760-3-akirakawata1@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220127124014.338760-1-akirakawata1@gmail.com> References: <20220127124014.338760-1-akirakawata1@gmail.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" I delete load_addr because it is not used anymore. And I rename load_addr_set to first_pt_load because it is used only to capture the first iteration of the loop. Signed-off-by: Akira Kawata Acked-by: Kees Cook --- fs/binfmt_elf.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index d120ab03795f..3218ebfde409 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -822,8 +822,8 @@ static int parse_elf_properties(struct file *f, const s= truct 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, load_bias =3D 0, phdr_addr =3D 0; - int load_addr_set =3D 0; + unsigned long load_bias =3D 0, phdr_addr =3D 0; + int first_pt_load =3D 1; unsigned long error; struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata =3D NULL; struct elf_phdr *elf_property_phdata =3D NULL; @@ -1073,12 +1073,12 @@ static int load_elf_binary(struct linux_binprm *bpr= m) =20 vaddr =3D elf_ppnt->p_vaddr; /* - * The first time through the loop, load_addr_set is false: + * The first time through the loop, first_pt_load is true: * layout will be calculated. Once set, use MAP_FIXED since * we know we've already safely mapped the entire region with * MAP_FIXED_NOREPLACE in the once-per-binary logic following. */ - if (load_addr_set) { + if (!first_pt_load) { elf_flags |=3D MAP_FIXED; } else if (elf_ex->e_type =3D=3D ET_EXEC) { /* @@ -1138,10 +1138,10 @@ static int load_elf_binary(struct linux_binprm *bpr= m) =20 /* * Calculate the entire size of the ELF mapping (total_size). - * (Note that load_addr_set is set to true later once the + * (Note that first_pt_load is set to false later once the * initial mapping is performed.) */ - if (!load_addr_set) { + if (first_pt_load) { total_size =3D total_mapping_size(elf_phdata, elf_ex->e_phnum); if (!total_size) { @@ -1158,13 +1158,11 @@ static int load_elf_binary(struct linux_binprm *bpr= m) goto out_free_dentry; } =20 - if (!load_addr_set) { - load_addr_set =3D 1; - load_addr =3D (elf_ppnt->p_vaddr - elf_ppnt->p_offset); + if (first_pt_load) { + first_pt_load =3D 0; if (elf_ex->e_type =3D=3D ET_DYN) { load_bias +=3D error - ELF_PAGESTART(load_bias + vaddr); - load_addr +=3D load_bias; reloc_func_desc =3D load_bias; } } --=20 2.25.1