From nobody Tue May 21 14:36:12 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=reject dis=none) header.from=citrix.com ARC-Seal: i=1; a=rsa-sha256; t=1711638674; cv=none; d=zohomail.com; s=zohoarc; b=H8T5qQsaGrELG9cVIc9BHxLhg9QMHGhpgyjJTd7sHeq8lwnBn1292qctGUlU5QDOgHqTOftrAFEezmcysfToxdJH48O0U9LAJ5v1+QBChIGySgeZWYJsSuSOy79fkfS4aTjY/jjGCrH2A6DfNY0MYcsSABwnrEXWTaePJNZuw/E= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1711638674; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=eq3AT7pXj0vQG5qtRB/nBOWtX8ZshbTnUcp8uTcSupQ=; b=mMqEfbiROycrcfBhDd9oV2cBkOcEJFMiSC3SUbPKZwVMvrrVyNI06smObPE2x8pDxlqjj+g0qXCYHOYsrcYIc6AX7hd2QjxFlWwvMzutMQDfmTs7GSRiytX+PH7pgvGqXRjiBizCuUVRPE1kZZCnbBK+p6Hatg24qtev8eGfDD8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1711638674481637.6697539031155; Thu, 28 Mar 2024 08:11:14 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.698955.1091256 (Exim 4.92) (envelope-from ) id 1rprP8-0001nW-MV; Thu, 28 Mar 2024 15:10:58 +0000 Received: by outflank-mailman (output) from mailman id 698955.1091256; Thu, 28 Mar 2024 15:10:58 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1rprP8-0001nP-JV; Thu, 28 Mar 2024 15:10:58 +0000 Received: by outflank-mailman (input) for mailman id 698955; Thu, 28 Mar 2024 15:10:56 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1rprP6-0001mV-Tm for xen-devel@lists.xenproject.org; Thu, 28 Mar 2024 15:10:56 +0000 Received: from mail-qt1-x82a.google.com (mail-qt1-x82a.google.com [2607:f8b0:4864:20::82a]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id 5fbebd18-ed15-11ee-afe3-a90da7624cb6; Thu, 28 Mar 2024 16:10:55 +0100 (CET) Received: by mail-qt1-x82a.google.com with SMTP id d75a77b69052e-43182c2457bso5988011cf.1 for ; Thu, 28 Mar 2024 08:10:55 -0700 (PDT) Received: from rossla-lxenia.eng.citrite.net ([185.25.67.249]) by smtp.gmail.com with ESMTPSA id cr7-20020a05622a428700b004313f54aaa9sm696300qtb.5.2024.03.28.08.10.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 Mar 2024 08:10:54 -0700 (PDT) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 5fbebd18-ed15-11ee-afe3-a90da7624cb6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=citrix.com; s=google; t=1711638654; x=1712243454; darn=lists.xenproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=eq3AT7pXj0vQG5qtRB/nBOWtX8ZshbTnUcp8uTcSupQ=; b=hwGu4NMop3eNMtbtnLK9ILrbEElqX41Jnx2wkFsiWenb3v09KJEDiqbC6qpBXbPy+G GuMFTyrsIoXDoOmh2uGz1rbtW+gnvH3lXsuc3uTrXXxVi5VWm5W97VssreunDlY/Cw+4 AKyWbheTlj7I5ZCKxdixf8bzobiMg3BP/PSy4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1711638654; x=1712243454; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=eq3AT7pXj0vQG5qtRB/nBOWtX8ZshbTnUcp8uTcSupQ=; b=OhLs+FEGLHMRSP/0IwROqe6bmVhjFbCgvdM2NJD2Aken7/ky8IQbqyYiwWuC5EnLnn xnf83oFec+ZWPeK6M7Prfh+q8sdNbOnlYOltfjdHhOqPtxht3b/ud2xrWHTyv5rC3cs0 mil15YW7ypmP5CmpHQ2udQogwIU5v/8ZYgmg91UVT5KSuc1wzx0fAwzEbd6a6WFyqyUX 9BJ1YbOJe+mqJ6hQwuaPs+MzvGkCbDOkS8AnsZ/RHXuR0yUbZ0kRBfKbyoZHrnu0irBI 5GYcZDsU6bygG+NJKJ9axvWLrCrv73A1rGtM0mP/KWE+d1Wu0zYSRFh7N2Y2aVe2yTcT jgQQ== X-Gm-Message-State: AOJu0Yxzyb7+wEpwzuT4EfnZRmIeqia8R5ihNycDXaQodZx54NuJhdcf n+y/jdGDlENYS5oSfDOlGunIIOFzTMnkBhAKR/HWwOD96scAeLWgAvl/yhgB6w== X-Google-Smtp-Source: AGHT+IFRiKrVvRemL8kfvC3qN4N8Lcc7JSK3BFibtolaMcbVYPlf+yQnlL6cYNo2NBNzseeKPq4+1w== X-Received: by 2002:a05:622a:194:b0:432:b960:b10 with SMTP id s20-20020a05622a019400b00432b9600b10mr1205534qtw.60.1711638654610; Thu, 28 Mar 2024 08:10:54 -0700 (PDT) From: Ross Lagerwall To: grub-devel@gnu.org Cc: xen-devel@lists.xenproject.org, Ross Lagerwall , Daniel Kiper , Daniel Kiper , Andrew Cooper , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= , Jan Beulich Subject: [PATCH v2 1/3] multiboot2: Add support for the PE binary type Date: Thu, 28 Mar 2024 15:13:00 +0000 Message-ID: <20240328151302.1451158-2-ross.lagerwall@citrix.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240328151302.1451158-1-ross.lagerwall@citrix.com> References: <20240328151302.1451158-1-ross.lagerwall@citrix.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @citrix.com) X-ZM-MESSAGEID: 1711638675072100001 Content-Type: text/plain; charset="utf-8" Currently, multiboot2-compatible bootloaders can load ELF binaries and a.out binaries. The presence of the address header tag determines how the bootloader tries to interpret the binary (a.out if the address tag is present else ELF). In addition to the existing address and ELF load types, specify that boot loaders may optionally support PE binaries as well. This new type is a useful addition since PE binaries can be signed and verified (i.e. used with Secure Boot). Boot loaders can distinguish between ELF and PE binaries using magic numbers since it is not possible for a binary to be both an ELF and PE binary at the same time. Signed-off-by: Ross Lagerwall --- doc/multiboot.texi | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/doc/multiboot.texi b/doc/multiboot.texi index df8a0d056e76..d26c35b54cd4 100644 --- a/doc/multiboot.texi +++ b/doc/multiboot.texi @@ -510,12 +510,15 @@ assumes that no bss segment is present. @end table =20 Note: This information does not need to be provided if the kernel image -is in @sc{elf} format, but it must be provided if the image is in a.out -format or in some other format. When the address tag is present it must -be used in order to load the image, regardless of whether an @sc{elf} -header is also present. Compliant boot loaders must be able to load -images that are either in @sc{elf} format or contain the address tag -embedded in the Multiboot2 header. +is in @sc{elf} or @sc{PE} format, but it must be provided if the image +is in a.out format or in some other format. When the address tag is +present it must be used in order to load the image, regardless of +whether an @sc{elf} or @sc{PE} header is also present. Compliant boot +loaders must be able to load images that are either in @sc{elf} format +or contain the address tag embedded in the Multiboot2 header. Compliant +boot loaders may optionally support loading images in @sc{PE} format. +When the address tag is not present, the boot loader should use magic +numbers to identify the type of the image to determine how to load it. =20 @subsection The entry address tag of Multiboot2 header =20 @@ -565,7 +568,7 @@ start running EFI i386 compatible operating system code. =20 This tag is taken into account only on EFI i386 platforms when Multiboot2 image header contains EFI boot services tag. -Then entry point specified in ELF header and the entry address +Then entry point specified in ELF or PE header and the entry address tag of Multiboot2 header are ignored. =20 @subsection EFI amd64 entry address tag of Multiboot2 header @@ -597,7 +600,7 @@ start running EFI amd64 compatible operating system cod= e. =20 This tag is taken into account only on EFI amd64 platforms when Multiboot2 image header contains EFI boot services tag. -Then entry point specified in ELF header and the entry address +Then entry point specified in ELF or PE header and the entry address tag of Multiboot2 header are ignored. =20 @node Console header tags --=20 2.43.0 From nobody Tue May 21 14:36:12 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=reject dis=none) header.from=citrix.com ARC-Seal: i=1; a=rsa-sha256; t=1711638678; cv=none; d=zohomail.com; s=zohoarc; b=XXwOmvONJRjOcP6TMxOLoEpxBtbUCnPqhPkIqE35VOJ/STlX1IttIslXICLfpUjmfpSucdB7ynASry3rypeA2gKSABmg6wY5oFREae2ctRfJu7SDvGmMY8f4Siid3ffXZQbqg+36X+44Q+jMRy7JlgtllnixKqRBakVGUfwwXAw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1711638678; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=G9324KJmT9LrWuNsOI70J8iDdayMGHOlIuajPPrTHQg=; b=eYmPKm2cSk8uYNheBM2Q+tG2lDdxq79znfG/DNcZM/u3O5nQ3yjnDr6msqRbD5SmIdQdNKKxJWo2Pz0EO73VLtpOVkc9Gzqn1A56Wksy9sugFmTSB6dMI1OtiByChvjnpjyR1SB7zcNTR50Q0YTQjPb1bFa+JLrgRf30om/BiKU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1711638678830539.4346956368249; Thu, 28 Mar 2024 08:11:18 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.698956.1091267 (Exim 4.92) (envelope-from ) id 1rprPD-000263-Te; Thu, 28 Mar 2024 15:11:03 +0000 Received: by outflank-mailman (output) from mailman id 698956.1091267; Thu, 28 Mar 2024 15:11:03 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1rprPD-00025u-Qh; Thu, 28 Mar 2024 15:11:03 +0000 Received: by outflank-mailman (input) for mailman id 698956; Thu, 28 Mar 2024 15:11:01 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1rprPB-0001mV-OV for xen-devel@lists.xenproject.org; Thu, 28 Mar 2024 15:11:01 +0000 Received: from mail-oi1-x22c.google.com (mail-oi1-x22c.google.com [2607:f8b0:4864:20::22c]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id 62123545-ed15-11ee-afe3-a90da7624cb6; Thu, 28 Mar 2024 16:10:59 +0100 (CET) Received: by mail-oi1-x22c.google.com with SMTP id 5614622812f47-3c3daebabe4so691997b6e.2 for ; Thu, 28 Mar 2024 08:10:59 -0700 (PDT) Received: from rossla-lxenia.eng.citrite.net ([185.25.67.249]) by smtp.gmail.com with ESMTPSA id cr7-20020a05622a428700b004313f54aaa9sm696300qtb.5.2024.03.28.08.10.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 Mar 2024 08:10:57 -0700 (PDT) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 62123545-ed15-11ee-afe3-a90da7624cb6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=citrix.com; s=google; t=1711638658; x=1712243458; darn=lists.xenproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=G9324KJmT9LrWuNsOI70J8iDdayMGHOlIuajPPrTHQg=; b=QhTnawdBpwos6nJaeDRhoX3I0xR7YMKNoc7zAxtzOtOdLTu5j1LPm7NPUddxCtZOl8 1jTYdYFw5WTJzvcLVqo8sQm1tRJFDzudK5MKE1RIzl1NaKiNxDR+gEHPxmkUsy2LXpdM wEUrymLrW46vcfwCNc8AMwOrAGxSdxm33+iMY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1711638658; x=1712243458; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=G9324KJmT9LrWuNsOI70J8iDdayMGHOlIuajPPrTHQg=; b=t9xKdvbRXnpmN6oAd882vzrtJkqGTV7ZpmKeX3X40c++E2EPRnDthRPSgThubRQxB7 Ip3XktrMUEBU6BGs0Gmj1JR0FxQDHdjyOpiCEiGDYS+xmOIGbveJ1qFmQJn6jDHEiKgz Qdu87uvT0EjVdodY0rYvqrhiOyasRSVE8o0Kk6UxDFxJAYGiGNO/oNPfAa39ilNcZahO NFlUzVCPPvk2hUfnezJkP0wFw0xcKvz0+XB0ReKnMogSHhF+vG2WsqLJE8LjszDCG3hR upDCKDakAtXpdu22zQE7unDe6JEogQMY+hSoBiTiOhgdGEZv+p00GWe6mn88bc0w0AQz oYhg== X-Gm-Message-State: AOJu0YyL0Vf37gxjMOC9gUb09a1jxwLQI9bUz8NiZ0AWQ76T4vzSnpgT CnXPNYSO1uRQ+S//9stuO+1w+u8p+TyO1QwghUdzJxpbndTZD9GQriOgQt/8EA== X-Google-Smtp-Source: AGHT+IH83M+cutSzSOy7EFKpOqpOFWmoSh7nMpOmiqpACnDM3dbkrJh6cxtOxpbi9ljRH2TasfwM6w== X-Received: by 2002:a05:6808:291:b0:3c3:d497:b750 with SMTP id z17-20020a056808029100b003c3d497b750mr3064373oic.55.1711638658256; Thu, 28 Mar 2024 08:10:58 -0700 (PDT) From: Ross Lagerwall To: grub-devel@gnu.org Cc: xen-devel@lists.xenproject.org, Ross Lagerwall , Daniel Kiper , Daniel Kiper , Andrew Cooper , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= Subject: [PATCH v2 2/3] multiboot2: Add PE load support Date: Thu, 28 Mar 2024 15:13:01 +0000 Message-ID: <20240328151302.1451158-3-ross.lagerwall@citrix.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240328151302.1451158-1-ross.lagerwall@citrix.com> References: <20240328151302.1451158-1-ross.lagerwall@citrix.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @citrix.com) X-ZM-MESSAGEID: 1711638679109100001 Content-Type: text/plain; charset="utf-8" Add the ability to load multiboot binaries in PE format. This allows the binaries to be signed and verified. Signed-off-by: Ross Lagerwall --- grub-core/Makefile.core.def | 1 + grub-core/loader/multiboot.c | 7 + grub-core/loader/multiboot_mbi2.c | 11 +- grub-core/loader/multiboot_pe.c | 702 ++++++++++++++++++++++++++++++ include/grub/efi/pe32.h | 64 +++ include/grub/multiboot.h | 3 + include/grub/multiboot2.h | 9 + 7 files changed, 796 insertions(+), 1 deletion(-) create mode 100644 grub-core/loader/multiboot_pe.c diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 1571421d7e84..34697ba58171 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -1815,6 +1815,7 @@ module =3D { =20 common =3D loader/multiboot.c; common =3D loader/multiboot_mbi2.c; + common =3D loader/multiboot_pe.c; enable =3D x86; enable =3D i386_xen_pvh; enable =3D mips; diff --git a/grub-core/loader/multiboot.c b/grub-core/loader/multiboot.c index 94be512c4d0c..8220a74e6f19 100644 --- a/grub-core/loader/multiboot.c +++ b/grub-core/loader/multiboot.c @@ -220,6 +220,13 @@ static grub_uint64_t highest_load; #include "multiboot_elfxx.c" #undef MULTIBOOT_LOAD_ELF32 =20 +bool +GRUB_MULTIBOOT (is_elf) (mbi_load_data_t *mld) +{ + return grub_multiboot_is_elf32 (mld->buffer) || + grub_multiboot_is_elf64 (mld->buffer); +} + /* Load ELF32 or ELF64. */ grub_err_t GRUB_MULTIBOOT (load_elf) (mbi_load_data_t *mld) diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot= _mbi2.c index 00a48413c013..601f38161e11 100644 --- a/grub-core/loader/multiboot_mbi2.c +++ b/grub-core/loader/multiboot_mbi2.c @@ -349,7 +349,16 @@ grub_multiboot2_load (grub_file_t file, const char *fi= lename) mld.file =3D file; mld.filename =3D filename; mld.avoid_efi_boot_services =3D keep_bs; - err =3D grub_multiboot2_load_elf (&mld); + if (grub_multiboot2_is_pe (&mld)) + err =3D grub_multiboot2_load_pe (&mld); + else if (grub_multiboot2_is_elf (&mld)) + err =3D grub_multiboot2_load_elf (&mld); + else + { + grub_free (mld.buffer); + return grub_error (GRUB_ERR_UNKNOWN_OS, + "Unknown image type and address tag not speci= fied"); + } if (err) { grub_free (mld.buffer); diff --git a/grub-core/loader/multiboot_pe.c b/grub-core/loader/multiboot_p= e.c new file mode 100644 index 000000000000..1c194f89b79c --- /dev/null +++ b/grub-core/loader/multiboot_pe.c @@ -0,0 +1,702 @@ +/* + * Significant portions of this code are derived from the Fedora GRUB patch + * "0007-Add-secureboot-support-on-efi-chainloader.patch" which is in turn + * derived from the PE loading code in Shim. The license is reproduced bel= ow: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Copyright Peter Jones + * + * Modifications: + * + * Copyright (c) 2024. Cloud Software Group, Inc. + */ + +#include +#include +#include + +static int +image_is_64_bit (grub_pe_header_t *pe_hdr) +{ + /* .Magic is the same offset in all cases */ + return pe_hdr->pe32plus.optional_header.magic =3D=3D GRUB_PE32_PE64_MAGI= C; +} + +static const grub_uint16_t machine_type __attribute__((__unused__)) =3D +#if defined(__x86_64__) + GRUB_PE32_MACHINE_X86_64; +#elif defined(__aarch64__) + GRUB_PE32_MACHINE_ARM64; +#elif defined(__arm__) + GRUB_PE32_MACHINE_ARMTHUMB_MIXED; +#elif defined(__i386__) || defined(__i486__) || defined(__i686__) + GRUB_PE32_MACHINE_I386; +#elif defined(__ia64__) + GRUB_PE32_MACHINE_IA64; +#elif defined(__riscv) && (__riscv_xlen =3D=3D 32) + GRUB_PE32_MACHINE_RISCV32; +#elif defined(__riscv) && (__riscv_xlen =3D=3D 64) + GRUB_PE32_MACHINE_RISCV64; +#else +#error this architecture is not supported by grub2 +#endif + +static int +image_is_loadable(grub_pe_header_t *pe_hdr) +{ + /* + * Check the machine type matches the binary and that we recognize + * the magic number. + */ + return (pe_hdr->pe32.coff_header.machine =3D=3D machine_type || + (pe_hdr->pe32.coff_header.machine =3D=3D GRUB_PE32_MACHINE_X86= _64 && + machine_type =3D=3D GRUB_PE32_MACHINE_I386)) && + (pe_hdr->pe32plus.optional_header.magic =3D=3D GRUB_PE32_PE32_M= AGIC || + pe_hdr->pe32plus.optional_header.magic =3D=3D GRUB_PE32_PE64_M= AGIC); +} + +/* + * Read the binary header and grab appropriate information from it + */ +static grub_err_t +read_header(void *data, unsigned int datasize, + pe_coff_loader_image_context_t *context) +{ + grub_pe32_msdos_header_t *dos_hdr =3D data; + grub_pe_header_t *pe_hdr =3D data; + unsigned long header_without_data_dir, section_header_offset, opt_header= _size; + unsigned long file_alignment =3D 0; + + if (datasize < sizeof (pe_hdr->pe32)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid image"); + return GRUB_ERR_OUT_OF_RANGE; + } + + if (dos_hdr->e_magic =3D=3D GRUB_PE32_MAGIC) + pe_hdr =3D (grub_pe_header_t *)((char *)data + dos_hdr->e_lfanew); + + if (!image_is_loadable(pe_hdr)) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Platform does not support= this image"); + return GRUB_ERR_NOT_IMPLEMENTED_YET; + } + + if (image_is_64_bit(pe_hdr)) + { + context->number_of_rva_and_sizes =3D pe_hdr->pe32plus.optional_heade= r.num_data_directories; + context->size_of_headers =3D pe_hdr->pe32plus.optional_header.header= _size; + context->image_size =3D pe_hdr->pe32plus.optional_header.image_size; + context->section_alignment =3D pe_hdr->pe32plus.optional_header.sect= ion_alignment; + file_alignment =3D pe_hdr->pe32plus.optional_header.file_alignment; + opt_header_size =3D sizeof(struct grub_pe64_optional_header); + } + else + { + context->number_of_rva_and_sizes =3D pe_hdr->pe32.optional_header.nu= m_data_directories; + context->size_of_headers =3D pe_hdr->pe32.optional_header.header_siz= e; + context->image_size =3D (grub_uint64_t)pe_hdr->pe32.optional_header.= image_size; + context->section_alignment =3D pe_hdr->pe32.optional_header.section_= alignment; + file_alignment =3D pe_hdr->pe32.optional_header.file_alignment; + opt_header_size =3D sizeof(struct grub_pe32_optional_header); + } + + if (file_alignment % 2 !=3D 0) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "File Alignment is invalid (%ld)"= , file_alignment); + return GRUB_ERR_OUT_OF_RANGE; + } + if (file_alignment =3D=3D 0) + file_alignment =3D 0x200; + if (context->section_alignment =3D=3D 0) + context->section_alignment =3D GRUB_EFI_PAGE_SIZE; + if (context->section_alignment < file_alignment) + context->section_alignment =3D file_alignment; + + context->number_of_sections =3D pe_hdr->pe32.coff_header.num_sections; + + if (EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES < context->number_of_rva_and_s= izes) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "Image header too small"); + return GRUB_ERR_OUT_OF_RANGE; + } + + header_without_data_dir =3D opt_header_size + - sizeof (struct grub_pe32_data_directory) * EFI_IMAGE_N= UMBER_OF_DIRECTORY_ENTRIES; + if (((grub_uint32_t)pe_hdr->pe32.coff_header.optional_header_size - head= er_without_data_dir) !=3D + context->number_of_rva_and_sizes * sizeof (struct grub_p= e32_data_directory)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "Image header overflows data dire= ctory"); + return GRUB_ERR_OUT_OF_RANGE; + } + + section_header_offset =3D dos_hdr->e_lfanew + + sizeof (grub_uint32_t) + + sizeof (struct grub_pe32_coff_header) + + pe_hdr->pe32.coff_header.optional_header_size; + if (((grub_uint32_t)context->image_size - section_header_offset) / sizeo= f(struct grub_pe32_section_table) + <=3D context->number_of_sections) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "Image sections overflow image si= ze"); + return GRUB_ERR_OUT_OF_RANGE; + } + + if ((context->size_of_headers - section_header_offset) / sizeof(struct g= rub_pe32_section_table) + < (grub_uint32_t)context->number_of_sections) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "Image sections overflow section = headers"); + return GRUB_ERR_OUT_OF_RANGE; + } + + if ((((grub_uint8_t *)pe_hdr - (grub_uint8_t *)data) + sizeof(grub_pe_he= ader_t)) > datasize) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid image"); + return GRUB_ERR_OUT_OF_RANGE; + } + + if (pe_hdr->pe32.signature[0] !=3D 'P' || + pe_hdr->pe32.signature[1] !=3D 'E' || + pe_hdr->pe32.signature[2] !=3D 0x00 || + pe_hdr->pe32.signature[3] !=3D 0x00) + { + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "Unsupported image type"); + return GRUB_ERR_NOT_IMPLEMENTED_YET; + } + + context->pe_hdr =3D pe_hdr; + + if (image_is_64_bit(pe_hdr)) + { + context->image_address =3D pe_hdr->pe32plus.optional_header.image_ba= se; + context->entry_point =3D pe_hdr->pe32plus.optional_header.entry_addr; + context->reloc_dir =3D &pe_hdr->pe32plus.optional_header.base_reloca= tion_table; + context->sec_dir =3D &pe_hdr->pe32plus.optional_header.certificate_t= able; + } + else + { + context->image_address =3D pe_hdr->pe32.optional_header.image_base; + context->entry_point =3D pe_hdr->pe32.optional_header.entry_addr; + context->reloc_dir =3D &pe_hdr->pe32.optional_header.base_relocation= _table; + context->sec_dir =3D &pe_hdr->pe32.optional_header.certificate_table; + } + + context->first_section =3D (struct grub_pe32_section_table *)((char *)pe= _hdr + + pe_hdr->pe32.coff_header.optional_header_size + + sizeof(grub_uint32_t) + sizeof(struct grub_pe32_coff_header)); + + if (context->image_size < context->size_of_headers) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid image"); + return GRUB_ERR_OUT_OF_RANGE; + } + + if ((unsigned long)((grub_uint8_t *)context->sec_dir - (grub_uint8_t *)d= ata) > + (datasize - sizeof(struct grub_pe32_data_directory))) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "Invalid image"); + return GRUB_ERR_OUT_OF_RANGE; + } + return GRUB_ERR_NONE; +} + +static grub_phys_addr_t +image_address (grub_phys_addr_t image, grub_uint64_t sz, grub_uint64_t add= r) +{ + if (addr > sz) + return 0; + + return image + addr; +} + +static grub_err_t +relocate_coff (pe_coff_loader_image_context_t *context, + struct grub_pe32_section_table *section, + grub_phys_addr_t phys_addr, grub_uint8_t *virt_addr, + mbi_load_data_t *mld) +{ + struct grub_pe32_data_directory *reloc_base, *reloc_base_end; + grub_uint8_t *reloc_buffer; + grub_uint64_t adjust; + struct grub_pe32_fixup_block *reloc, *reloc_end; + grub_uint8_t *fixup, *fixup_base; + grub_uint16_t *fixup_16; + grub_uint32_t *fixup_32; + grub_uint64_t *fixup_64; + int n =3D 0; + grub_err_t ret =3D GRUB_ERR_NONE; + + if (image_is_64_bit (context->pe_hdr)) + context->pe_hdr->pe32plus.optional_header.image_base =3D + (grub_uint64_t)(unsigned long)phys_addr; + else + context->pe_hdr->pe32.optional_header.image_base =3D + (grub_uint32_t)(unsigned long)phys_addr; + + /* Alright, so here's how this works: + * + * context->reloc_dir gives us two things: + * - the VA the table of base relocation blocks are (maybe) to be + * mapped at (reloc_dir->rva) + * - the virtual size (reloc_dir->size) + * + * The .reloc section (section here) gives us some other things: + * - the name! kind of. (section->name) + * - the virtual size (section->virtual_size), which should be the same + * as RelocDir->Size + * - the virtual address (section->virtual_address) + * - the file section size (section->raw_data_size), which is + * a multiple of optional_header->file_alignment. Only useful for ima= ge + * validation, not really useful for iteration bounds. + * - the file address (section->raw_data_offset) + * - a bunch of stuff we don't use that's 0 in our binaries usually + * - Flags (section->characteristics) + * + * and then the thing that's actually at the file address is an array + * of struct grub_pe32_fixup_block structs with some values packed behind + * them. The block_size field of this structure includes the + * structure itself, and adding it to that structure's address will + * yield the next entry in the array. + */ + + reloc_buffer =3D grub_malloc (section->virtual_size); + if (!reloc_buffer) + return grub_errno; + + if (grub_file_seek (mld->file, section->raw_data_offset) =3D=3D (grub_of= f_t) -1) + { + ret =3D grub_errno; + goto out; + } + + if (grub_file_read (mld->file, reloc_buffer, section->virtual_size) + !=3D (grub_ssize_t) section->virtual_size) + { + if (!grub_errno) + { + grub_error (GRUB_ERR_FILE_READ_ERROR, "premature end of file %s", + mld->filename); + ret =3D GRUB_ERR_FILE_READ_ERROR; + } + else + ret =3D grub_errno; + goto out; + } + + reloc_base =3D (struct grub_pe32_data_directory *)reloc_buffer; + reloc_base_end =3D (struct grub_pe32_data_directory *)(reloc_buffer + se= ction->virtual_size); + + grub_dprintf ("multiboot_loader", "relocate_coff(): reloc_base %p reloc_= base_end %p\n", + reloc_base, reloc_base_end); + + if (!reloc_base && !reloc_base_end) + return GRUB_ERR_NONE; + + if (!reloc_base || !reloc_base_end) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc table overflows binary"); + return GRUB_ERR_BAD_ARGUMENT; + } + + adjust =3D (grub_uint64_t)(grub_efi_uintn_t)phys_addr - context->image_a= ddress; + if (adjust =3D=3D 0) + return GRUB_ERR_NONE; + + while (reloc_base < reloc_base_end) + { + grub_uint16_t *entry; + reloc =3D (struct grub_pe32_fixup_block *)((char*)reloc_base); + + if ((reloc_base->size =3D=3D 0) || + (reloc_base->size > context->reloc_dir->size)) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, + "Reloc %d block size %d is invalid\n", n, + reloc_base->size); + ret =3D GRUB_ERR_BAD_ARGUMENT; + goto out; + } + + entry =3D &reloc->entries[0]; + reloc_end =3D (struct grub_pe32_fixup_block *) + ((char *)reloc_base + reloc_base->size); + + if ((grub_uint8_t *)reloc_end < reloc_buffer || + (grub_uint8_t *)reloc_end > (reloc_buffer + section->virtual_siz= e)) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc entry %d overflows bin= ary", + n); + return GRUB_ERR_BAD_ARGUMENT; + } + + fixup_base =3D virt_addr + reloc_base->rva; + if (!fixup_base) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "Reloc %d Invalid fixupbase",= n); + ret =3D GRUB_ERR_BAD_ARGUMENT; + goto out; + } + + while ((void *)entry < (void *)reloc_end) + { + fixup =3D fixup_base + (*entry & 0xFFF); + switch ((*entry) >> 12) + { + case GRUB_PE32_REL_BASED_ABSOLUTE: + break; + case GRUB_PE32_REL_BASED_HIGH: + fixup_16 =3D (grub_uint16_t *)fixup; + *fixup_16 =3D (grub_uint16_t) + (*fixup_16 + ((grub_uint16_t)((grub_uint32_t)adjust >> 1= 6))); + break; + case GRUB_PE32_REL_BASED_LOW: + fixup_16 =3D (grub_uint16_t *)fixup; + *fixup_16 =3D (grub_uint16_t) (*fixup_16 + (grub_uint16_t)= adjust); + break; + case GRUB_PE32_REL_BASED_HIGHLOW: + fixup_32 =3D (grub_uint32_t *)fixup; + *fixup_32 =3D *fixup_32 + (grub_uint32_t)adjust; + break; + case GRUB_PE32_REL_BASED_DIR64: + fixup_64 =3D (grub_uint64_t *)fixup; + *fixup_64 =3D *fixup_64 + (grub_uint64_t)adjust; + break; + default: + grub_error (GRUB_ERR_BAD_ARGUMENT, + "Reloc %d unknown relocation type %d", + n, (*entry) >> 12); + ret =3D GRUB_ERR_BAD_ARGUMENT; + goto out; + } + entry +=3D 1; + } + reloc_base =3D (struct grub_pe32_data_directory *)reloc_end; + n++; + } + +out: + grub_free(reloc_buffer); + + return ret; +} + +grub_err_t +grub_multiboot2_load_pe (mbi_load_data_t *mld) +{ + int i; + grub_uint8_t *virt_addr; + grub_phys_addr_t phys_addr, reloc_base, reloc_base_end, base, end; + struct grub_pe32_section_table *reloc_section =3D NULL, fake_reloc_secti= on; + struct grub_pe32_section_table *section; + grub_relocator_chunk_t ch; + pe_coff_loader_image_context_t context; + grub_err_t ret =3D GRUB_ERR_NONE; + grub_uint32_t section_alignment; + int found_entry_point =3D 0; + + ret =3D read_header(mld->buffer, MULTIBOOT_SEARCH, &context); + if (ret) + return ret; + + /* + * The spec says, uselessly, of SectionAlignment: + * =3D=3D=3D=3D=3D + * The alignment (in bytes) of sections when they are loaded into + * memory. It must be greater than or equal to FileAlignment. The + * default is the page size for the architecture. + * =3D=3D=3D=3D=3D + * Which doesn't tell you whose responsibility it is to enforce the + * "default", or when. It implies that the value in the field must + * be > FileAlignment (also poorly defined), but it appears visual + * studio will happily write 512 for FileAlignment (its default) and + * 0 for SectionAlignment, intending to imply PAGE_SIZE. + * + * We only support one page size, so if it's zero, nerf it to 4096. + */ + section_alignment =3D context.section_alignment; + if (section_alignment =3D=3D 0) + section_alignment =3D 4096; + + section_alignment =3D grub_max(section_alignment, mld->align); + + ret =3D grub_relocator_alloc_chunk_align_safe (grub_multiboot2_relocator= , &ch, + mld->min_addr, mld->max_add= r, + context.image_size, section= _alignment, + mld->preference, mld->avoid= _efi_boot_services); + + if (ret) + { + grub_dprintf ("multiboot_loader", "Cannot allocate memory for OS ima= ge\n"); + return ret; + } + + virt_addr =3D get_virtual_current_address (ch); + phys_addr =3D get_physical_target_address (ch); + + if (grub_file_seek (mld->file, 0) =3D=3D (grub_off_t) -1) { + ret =3D grub_errno; + goto out; + } + + if (grub_file_read (mld->file, virt_addr, context.size_of_headers) + !=3D (grub_ssize_t) context.size_of_headers) + { + if (!grub_errno) + { + grub_error (GRUB_ERR_FILE_READ_ERROR, "premature end of file %s", + mld->filename); + ret =3D GRUB_ERR_FILE_READ_ERROR; + } + else + ret =3D grub_errno; + goto out; + } + + mld->load_base_addr =3D phys_addr; + mld->link_base_addr =3D context.image_address; + + grub_dprintf ("multiboot_loader", "load_base_addr: 0x%08x link_base_addr= 0x%08x\n", + mld->load_base_addr, mld->link_base_addr); + + grub_multiboot2_payload_eip =3D context.entry_point; + grub_dprintf ("multiboot_loader", "entry_point: 0x%08x\n", grub_multiboo= t2_payload_eip); + if (!grub_multiboot2_payload_eip) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid entry point"); + ret =3D GRUB_ERR_BAD_ARGUMENT; + goto out; + } + + grub_dprintf ("multiboot_loader", "reloc_dir: %p reloc_size: 0x%08x\n", + (void *)(unsigned long)context.reloc_dir->rva, + context.reloc_dir->size); + reloc_base =3D image_address (phys_addr, context.image_size, + context.reloc_dir->rva); + /* RelocBaseEnd here is the address of the last byte of the table */ + reloc_base_end =3D image_address (phys_addr, context.image_size, + context.reloc_dir->rva + + context.reloc_dir->size - 1); + grub_dprintf ("multiboot_loader", "reloc_base: 0x%016lx reloc_base_end: = 0x%016lx\n", + reloc_base, reloc_base_end); + + section =3D context.first_section; + for (i =3D 0; i < context.number_of_sections; i++, section++) + { + char name[9]; + + base =3D image_address (phys_addr, context.image_size, + section->virtual_address); + end =3D image_address (phys_addr, context.image_size, + section->virtual_address + section->virtual_siz= e -1); + + grub_strncpy(name, section->name, 9); + name[8] =3D '\0'; + grub_dprintf ("multiboot_loader", "Section %d \"%s\" at 0x%016lx..0x= %016lx\n", i, + name, base, end); + + if (end < base) + { + grub_dprintf ("multiboot_loader", " base is 0x%016lx but end is = 0x%016lx... bad.\n", + base, end); + grub_error (GRUB_ERR_BAD_ARGUMENT, + "Image has invalid negative size"); + ret =3D GRUB_ERR_BAD_ARGUMENT; + goto out; + } + + if (section->virtual_address <=3D context.entry_point && + (section->virtual_address + section->raw_data_size - 1) + > context.entry_point) + { + found_entry_point++; + grub_dprintf ("multiboot_loader", " section contains entry point= \n"); + } + + /* We do want to process .reloc, but it's often marked + * discardable, so we don't want to memcpy it. */ + if (grub_memcmp (section->name, ".reloc\0\0", 8) =3D=3D 0) + { + if (reloc_section) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, + "Image has multiple relocation sections"); + ret =3D GRUB_ERR_BAD_ARGUMENT; + goto out; + } + + /* If it has nonzero sizes, and our bounds check + * made sense, and the VA and size match RelocDir's + * versions, then we believe in this section table. */ + if (section->raw_data_size && section->virtual_size && + base && end && reloc_base =3D=3D base) + { + if (reloc_base_end =3D=3D end) + { + grub_dprintf ("multiboot_loader", " section is relocatio= n section\n"); + reloc_section =3D section; + } + else if (reloc_base_end && reloc_base_end < end) + { + /* Bogus virtual size in the reloc section -- RelocDir + * reported a smaller Base Relocation Directory. Decrease + * the section's virtual size so that it equal RelocDir's + * idea, but only for the purposes of relocate_coff(). */ + grub_dprintf ("multiboot_loader", + " section is (overlong) relocation section= \n"); + grub_memcpy (&fake_reloc_section, section, sizeof *secti= on); + fake_reloc_section.virtual_size -=3D (end - reloc_base_e= nd); + reloc_section =3D &fake_reloc_section; + } + } + + if (!reloc_section) + { + grub_dprintf ("multiboot_loader", " section is not reloc sec= tion?\n"); + grub_dprintf ("multiboot_loader", " rds: 0x%08x, vs: %08x\n", + section->raw_data_size, section->virtual_size); + grub_dprintf ("multiboot_loader", " base: 0x%016lx end: 0x%0= 16lx\n", base, end); + grub_dprintf ("multiboot_loader", " reloc_base: 0x%016lx rel= oc_base_end: 0x%016lx\n", + reloc_base, reloc_base_end); + } + } + + grub_dprintf ("multiboot_loader", " Section characteristics are %08x= \n", + section->characteristics); + grub_dprintf ("multiboot_loader", " Section virtual size: %08x\n", + section->virtual_size); + grub_dprintf ("multiboot_loader", " Section raw_data size: %08x\n", + section->raw_data_size); + if (section->characteristics & GRUB_PE32_SCN_MEM_DISCARDABLE) + { + grub_dprintf ("multiboot_loader", " Discarding section\n"); + continue; + } + + if (!base || !end) + { + grub_dprintf ("multiboot_loader", " section is invalid\n"); + grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid section size"); + ret =3D GRUB_ERR_BAD_ARGUMENT; + goto out; + } + + if (section->characteristics & GRUB_PE32_SCN_CNT_UNINITIALIZED_DATA) + { + if (section->raw_data_size !=3D 0) + grub_dprintf ("multiboot_loader", " UNINITIALIZED_DATA section= has data?\n"); + } + else if (section->virtual_address < context.size_of_headers || + section->raw_data_offset < context.size_of_headers) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, + "Section %d is inside image headers", i); + ret =3D GRUB_ERR_BAD_ARGUMENT; + goto out; + } + + if (section->raw_data_size > 0) + { + grub_dprintf ("multiboot_loader", " copying 0x%08x bytes to 0x%0= 16lx\n", + section->raw_data_size, base); + + if (grub_file_seek (mld->file, section->raw_data_offset) =3D=3D = (grub_off_t) -1) + { + ret =3D grub_errno; + goto out; + } + + if (grub_file_read (mld->file, virt_addr + (base - phys_addr), s= ection->raw_data_size) + !=3D (grub_ssize_t) section->raw_data_size) + { + if (!grub_errno) + { + grub_error (GRUB_ERR_FILE_READ_ERROR, "premature end of = file %s", + mld->filename); + ret =3D GRUB_ERR_FILE_READ_ERROR; + } + else + ret =3D grub_errno; + goto out; + } + } + + if (section->raw_data_size < section->virtual_size) + { + grub_dprintf ("multiboot_loader", " padding with 0x%08x bytes at= 0x%016lx\n", + section->virtual_size - section->raw_data_size, + base + section->raw_data_size); + grub_memset (virt_addr + (base - phys_addr) + section->raw_data_= size, 0, + section->virtual_size - section->raw_data_size); + } + + grub_dprintf ("multiboot_loader", " finished section %s\n", name); + } + + /* 5 =3D=3D EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC */ + if (context.number_of_rva_and_sizes <=3D 5) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "image has no relocation entry\n"= ); + ret =3D GRUB_ERR_BAD_ARGUMENT; + goto out; + } + + if (context.reloc_dir->size && reloc_section) + { + /* run the relocation fixups */ + ret =3D relocate_coff (&context, reloc_section, phys_addr, virt_addr= , mld); + + if (ret) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "relocation failed"); + goto out; + } + } + + if (!found_entry_point) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "entry point is not within sectio= ns"); + ret =3D GRUB_ERR_BAD_ARGUMENT; + goto out; + } + if (found_entry_point > 1) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, "%d sections contain entry point", + found_entry_point); + ret =3D GRUB_ERR_BAD_ARGUMENT; + goto out; + } + +out: + return ret; +} + +bool +grub_multiboot2_is_pe (mbi_load_data_t *mld) +{ + grub_pe32_msdos_header_t *dos_hdr =3D mld->buffer; + + return dos_hdr->e_magic =3D=3D GRUB_PE32_MAGIC; +} diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h index 4e6e9d254bd3..2c8f7c3b85a5 100644 --- a/include/grub/efi/pe32.h +++ b/include/grub/efi/pe32.h @@ -20,6 +20,7 @@ #define GRUB_EFI_PE32_HEADER 1 =20 #include +#include #include =20 /* The MSDOS compatibility stub. This was copied from the output of @@ -46,6 +47,28 @@ =20 #define GRUB_PE32_MSDOS_STUB_SIZE 0x80 =20 +typedef struct { + grub_uint16_t e_magic; ///< Magic number. + grub_uint16_t e_cblp; ///< Bytes on last page of file. + grub_uint16_t e_cp; ///< Pages in file. + grub_uint16_t e_crlc; ///< Relocations. + grub_uint16_t e_cparhdr; ///< Size of header in paragraphs. + grub_uint16_t e_minalloc; ///< Minimum extra paragraphs needed. + grub_uint16_t e_maxalloc; ///< Maximum extra paragraphs needed. + grub_uint16_t e_ss; ///< Initial (relative) SS value. + grub_uint16_t e_sp; ///< Initial SP value. + grub_uint16_t e_csum; ///< Checksum. + grub_uint16_t e_ip; ///< Initial IP value. + grub_uint16_t e_cs; ///< Initial (relative) CS value. + grub_uint16_t e_lfarlc; ///< File address of relocation table. + grub_uint16_t e_ovno; ///< Overlay number. + grub_uint16_t e_res[4]; ///< Reserved words. + grub_uint16_t e_oemid; ///< OEM identifier (for e_oeminfo). + grub_uint16_t e_oeminfo; ///< OEM information; e_oemid specific. + grub_uint16_t e_res2[10]; ///< Reserved words. + grub_uint32_t e_lfanew; ///< File address of new exe header. +} grub_pe32_msdos_header_t; + #define GRUB_PE32_MAGIC 0x5a4d =20 struct grub_msdos_image_header @@ -249,6 +272,7 @@ struct grub_pe32_section_table =20 #define GRUB_PE32_SCN_CNT_CODE 0x00000020 #define GRUB_PE32_SCN_CNT_INITIALIZED_DATA 0x00000040 +#define GRUB_PE32_SCN_CNT_UNINITIALIZED_DATA 0x00000080 #define GRUB_PE32_SCN_MEM_DISCARDABLE 0x02000000 #define GRUB_PE32_SCN_MEM_EXECUTE 0x20000000 #define GRUB_PE32_SCN_MEM_READ 0x40000000 @@ -349,4 +373,44 @@ struct grub_pe32_reloc #define GRUB_PE32_REL_I386_DIR32 0x6 #define GRUB_PE32_REL_I386_REL32 0x14 =20 +struct grub_pe32_header_32 +{ + char signature[GRUB_PE32_SIGNATURE_SIZE]; + struct grub_pe32_coff_header coff_header; + struct grub_pe32_optional_header optional_header; +}; + +struct grub_pe32_header_64 +{ + char signature[GRUB_PE32_SIGNATURE_SIZE]; + struct grub_pe32_coff_header coff_header; + struct grub_pe64_optional_header optional_header; +}; + +typedef union +{ + struct grub_pe32_header_32 pe32; + struct grub_pe32_header_64 pe32plus; +} grub_pe_header_t; + +struct pe_coff_loader_image_context +{ + grub_efi_uint64_t image_address; + grub_efi_uint64_t image_size; + grub_efi_uint64_t entry_point; + grub_efi_uintn_t size_of_headers; + grub_efi_uint16_t image_type; + grub_efi_uint16_t number_of_sections; + grub_efi_uint32_t section_alignment; + struct grub_pe32_section_table *first_section; + struct grub_pe32_data_directory *reloc_dir; + struct grub_pe32_data_directory *sec_dir; + grub_efi_uint64_t number_of_rva_and_sizes; + grub_pe_header_t *pe_hdr; +}; + +typedef struct pe_coff_loader_image_context pe_coff_loader_image_context_t; + +#define EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES 16 + #endif /* ! GRUB_EFI_PE32_HEADER */ diff --git a/include/grub/multiboot.h b/include/grub/multiboot.h index d8847f7531d3..c6af5c71b4e8 100644 --- a/include/grub/multiboot.h +++ b/include/grub/multiboot.h @@ -100,6 +100,9 @@ struct mbi_load_data }; typedef struct mbi_load_data mbi_load_data_t; =20 +bool +grub_multiboot_is_elf (mbi_load_data_t *mld); + /* Load ELF32 or ELF64. */ grub_err_t grub_multiboot_load_elf (mbi_load_data_t *mld); diff --git a/include/grub/multiboot2.h b/include/grub/multiboot2.h index b90aa6989674..6169cb4472a7 100644 --- a/include/grub/multiboot2.h +++ b/include/grub/multiboot2.h @@ -92,10 +92,19 @@ struct mbi_load_data }; typedef struct mbi_load_data mbi_load_data_t; =20 +bool +grub_multiboot2_is_elf (mbi_load_data_t *mld); + /* Load ELF32 or ELF64. */ grub_err_t grub_multiboot2_load_elf (mbi_load_data_t *mld); =20 +grub_err_t +grub_multiboot2_load_pe (mbi_load_data_t *mld); + +bool +grub_multiboot2_is_pe (mbi_load_data_t *mld); + extern grub_size_t grub_multiboot2_pure_size; extern grub_size_t grub_multiboot2_alloc_mbi; extern grub_uint32_t grub_multiboot2_payload_eip; --=20 2.43.0 From nobody Tue May 21 14:36:12 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=reject dis=none) header.from=citrix.com ARC-Seal: i=1; a=rsa-sha256; t=1711638681; cv=none; d=zohomail.com; s=zohoarc; b=CY7Sf3PVriXRPU4cu1E7TZwwjkkpY3QZJRyJwMtMuuYt9qdh3VB0LPAqe+fWEMu1cWRWIIHj/kErtupi6lszix/GVextVU7UR/VP5OULkjLHEGu7wjUtBRiO8po9SCpEJ3IOune7arwbvNJ8QM9jZykVToI8F8Y7UvuAe6tSGq4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1711638681; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=U2qmXAF7kH+Xo7dcYPNWV07zKXcD5akVAYdTNUPm5Ak=; b=G3//QCXBQJ9ao1GaAiLnSVGWRl3Gn/QgdEiB/gQ20GZDlgK6cnwDa7axMtg2NwNWzDLCwzAMCzuHmMMlGVTfDUyLXd6HKpNFYOzOQwY8JFhDTOxudb+o7eDbWEiQnavieglmUSudGg4hz8jNXJ3k2Sh5S3FAVUE71TKQzsji5YQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1711638681427705.986772798097; Thu, 28 Mar 2024 08:11:21 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.698957.1091277 (Exim 4.92) (envelope-from ) id 1rprPF-0002MB-Al; Thu, 28 Mar 2024 15:11:05 +0000 Received: by outflank-mailman (output) from mailman id 698957.1091277; Thu, 28 Mar 2024 15:11:05 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1rprPF-0002M0-7V; Thu, 28 Mar 2024 15:11:05 +0000 Received: by outflank-mailman (input) for mailman id 698957; Thu, 28 Mar 2024 15:11:03 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1rprPD-0001mV-3O for xen-devel@lists.xenproject.org; Thu, 28 Mar 2024 15:11:03 +0000 Received: from mail-qt1-x82f.google.com (mail-qt1-x82f.google.com [2607:f8b0:4864:20::82f]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id 63cdc1a3-ed15-11ee-afe3-a90da7624cb6; Thu, 28 Mar 2024 16:11:02 +0100 (CET) Received: by mail-qt1-x82f.google.com with SMTP id d75a77b69052e-43107ccd7b9so5577561cf.3 for ; Thu, 28 Mar 2024 08:11:02 -0700 (PDT) Received: from rossla-lxenia.eng.citrite.net ([185.25.67.249]) by smtp.gmail.com with ESMTPSA id cr7-20020a05622a428700b004313f54aaa9sm696300qtb.5.2024.03.28.08.11.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 Mar 2024 08:11:00 -0700 (PDT) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 63cdc1a3-ed15-11ee-afe3-a90da7624cb6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=citrix.com; s=google; t=1711638661; x=1712243461; darn=lists.xenproject.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=U2qmXAF7kH+Xo7dcYPNWV07zKXcD5akVAYdTNUPm5Ak=; b=bNoRIdajri1wVAtu80pzggb6o6axyqxWdnp5Bsa62pAuNgE8SvMNaWbtgjX00lXnI5 JcXm3jwPTPuJOdlxjmvFNw3H6JYkg9B1rAgNPISh5hKvZHUMa+0bO4x5GP+Us0RVmfXb a3tDWxrWiG55E38ofCUADCL9vBvt++XjBZBOY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1711638661; x=1712243461; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=U2qmXAF7kH+Xo7dcYPNWV07zKXcD5akVAYdTNUPm5Ak=; b=WLq9Shx+wr41UPL8YlP+FSeMYrpbIu1ozKHIp1KSBpAyAFpyceuwLySs6SghtaXYua J3JC7CFne5wHVA6oNl4hTwowF3SvfEllllwpHSWbrXiu99gK67JXJbXlDb9Z7vafBaiE Lp04YlAyPnXk3AeAJVYudDMGYeKy/sUeqNlmcicIifWFnGqMqdGJeWWnuQnSB5nX2J+8 sGhu1bSd5yIcGd1Cy31EpSmNRDKk9LrylF/YgIgzET5XZVMdvHWpo0tsE9GGBYQEd5N3 aebN0+V/bMTE5stGVhPXJmboj7pHgRjR5+mFICtTkV0spwb622kz/2iftm8SG9KxJjMf bltQ== X-Gm-Message-State: AOJu0YyepdaONKwYikXJMHD1REyWMuKQUmMi37BoVvCOU0J7Qh6I2boQ jxy1LP0otEu3WLki2zJ94JHlQW2aTYo2+d+mYvZbvrTReazfbJW4d21Qzu4IkQ== X-Google-Smtp-Source: AGHT+IHRgh7LeGuGdwNldABcb1tIrGf4GrwtRM68IhGmhRZqpwgzTkw0Gpe38tSy6CDtLxe8+DQwvA== X-Received: by 2002:ac8:5c8c:0:b0:430:e2cb:9a54 with SMTP id r12-20020ac85c8c000000b00430e2cb9a54mr3266954qta.12.1711638661506; Thu, 28 Mar 2024 08:11:01 -0700 (PDT) From: Ross Lagerwall To: grub-devel@gnu.org Cc: xen-devel@lists.xenproject.org, Ross Lagerwall , Daniel Kiper , Daniel Kiper , Andrew Cooper , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= Subject: [PATCH v2 3/3] efi: Allow loading multiboot modules without verification Date: Thu, 28 Mar 2024 15:13:02 +0000 Message-ID: <20240328151302.1451158-4-ross.lagerwall@citrix.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240328151302.1451158-1-ross.lagerwall@citrix.com> References: <20240328151302.1451158-1-ross.lagerwall@citrix.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @citrix.com) X-ZM-MESSAGEID: 1711638683051100001 Content-Type: text/plain; charset="utf-8" GRUB doesn't do anything with multiboot modules except loading them and passing a pointer to the multiboot kernel. Therefore GRUB itself doesn't need to verify the module. Multiboot modules may contain code that needs to be verified. If this is the case, the expectation is that the multiboot kernel verifies the modules. For example, with Xen, the first multiboot module contains the dom0 kernel binary and Xen verifies it before starting it. Signed-off-by: Ross Lagerwall --- grub-core/kern/efi/sb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c index 8d3e413608bb..f76290d65e9f 100644 --- a/grub-core/kern/efi/sb.c +++ b/grub-core/kern/efi/sb.c @@ -171,6 +171,7 @@ shim_lock_verifier_init (grub_file_t io __attribute__ (= (unused)), case GRUB_FILE_TYPE_LOADENV: case GRUB_FILE_TYPE_SAVEENV: case GRUB_FILE_TYPE_VERIFY_SIGNATURE: + case GRUB_FILE_TYPE_MULTIBOOT_MODULE: *flags =3D GRUB_VERIFY_FLAGS_SKIP_VERIFICATION; return GRUB_ERR_NONE; =20 --=20 2.43.0