From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by mx.groups.io with SMTP id smtpd.web12.15989.1659893660444908800 for ; Sun, 07 Aug 2022 10:34:21 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="unable to parse pub key" header.i=@intel.com header.s=intel header.b=n2/LxqzD; spf=pass (domain: intel.com, ip: 192.55.52.88, mailfrom: jian.j.wang@intel.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1659893660; x=1691429660; h=from:to:cc:subject:date:message-id:references: in-reply-to:content-transfer-encoding:mime-version; bh=8co2NexMmX4gs0ov70WGl92vlU4JD95Z0ohcalsSWtA=; b=n2/LxqzDzbu3/OOFfNY64thQargER1SA1Zwz82fiVxTaqpYN1ntKg2OH gPZAI2xWFeEukiawPyE+swpZ/+pmD3IqPoOgtrV0scR5NGMSgu7Y5I1Zt DPsXue5dUikedY7b5tat0iCLqhAdEDSr2+sh+ax/OWTS2rdW7Pr8EWDNf 44MImf1U5uMg7m1ir6cvJRlt2fkcX4EayACMevL6QfqN94B7YkQJ26YKF QuAP3S+qBXcSRkg6TXmUTEmuN5t6D3RYRACM4Pc/xJCFL9+KRwZ7kFXBP +TQu4aIwnVmhh43It1d6eylwXQMk5hlqN2ERNgEQmyiLTkxk7828xR1Xc w==; X-IronPort-AV: E=McAfee;i="6400,9594,10432"; a="316357047" X-IronPort-AV: E=Sophos;i="5.93,220,1654585200"; d="scan'208";a="316357047" Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Aug 2022 10:34:19 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.93,220,1654585200"; d="scan'208";a="707173356" Received: from fmsmsx605.amr.corp.intel.com ([10.18.126.85]) by fmsmga002.fm.intel.com with ESMTP; 07 Aug 2022 10:34:19 -0700 Received: from fmsmsx609.amr.corp.intel.com (10.18.126.89) by fmsmsx605.amr.corp.intel.com (10.18.126.85) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.28; Sun, 7 Aug 2022 10:34:19 -0700 Received: from fmsmsx604.amr.corp.intel.com (10.18.126.84) by fmsmsx609.amr.corp.intel.com (10.18.126.89) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.28; Sun, 7 Aug 2022 10:34:18 -0700 Received: from fmsedg602.ED.cps.intel.com (10.1.192.136) by fmsmsx604.amr.corp.intel.com (10.18.126.84) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2375.28 via Frontend Transport; Sun, 7 Aug 2022 10:34:18 -0700 Received: from NAM11-BN8-obe.outbound.protection.outlook.com (104.47.58.169) by edgegateway.intel.com (192.55.55.71) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2375.28; Sun, 7 Aug 2022 10:34:17 -0700 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=BV/9xgekrcsBMfIwHauZAXwg5U2muu6nObN7RAJ2JtO390GSzREET8KCHnfGc/a+dk4xdxCrI4hylf3pokgZYrd/otNYcFoqkhbPpHHr+rMNf04+Dnpg+aws1FUYojhMjjdMxHkXacnrg7t4wrD3BcfeiEnU8j5avJasNU5WaqFFMU+FEXGbjThJdjkHE8FVffUHXsVXy4TRrjyw73iIi6MyorUfCLYMpaIEGXU3ExnSxB3wKdRVM1vOEgJGis5MPfdOmxcCZ6fVMyZRfMGkeDM82BXQ1jyDWFmarYBHHYubyKyEMdPoIXbccFwPi2cgsXBFl+DbRxrM2tnNJOITBA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=v1spizPN9CYwXsLBMeZkJpsYPlfjYCiCFkB8IKUBJCs=; b=jEpU243gX1RC1eQ5djHE064ylWfI2UyWr4vBLkEY9hJPKLUvpi3bJEgF2Quizx9vtURRWzlXqRMrjAwpZ/2gZaSmcZOUtT87ArYfp3nx7Tgae/3uJaaRgb4j+v2dIGHh8L1PHPteorPU4HILrwqBiraNh1aOa6i/pw2PsZHS/znjiQOAfLwXcYrtNlF79tULz1whohl7jewQnFTRkzOgEfiSDedxizxo1X28Hyv+Iqw8yr5J+rJLJUsoj+HzNtl7WFjSXeSEPPprrzDD/8yEoGHxdCW4lr99/h/HGQLh+m8gYjZohdAIiaJsQ71X2X9XFBClEKqrgMPpN7W0wS5ofA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=intel.com; dmarc=pass action=none header.from=intel.com; dkim=pass header.d=intel.com; arc=none Received: from CO1PR11MB4945.namprd11.prod.outlook.com (2603:10b6:303:9c::8) by DM6PR11MB4204.namprd11.prod.outlook.com (2603:10b6:5:206::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.5504.16; Sun, 7 Aug 2022 17:34:11 +0000 Received: from CO1PR11MB4945.namprd11.prod.outlook.com ([fe80::60a4:f0f8:c310:9daf]) by CO1PR11MB4945.namprd11.prod.outlook.com ([fe80::60a4:f0f8:c310:9daf%9]) with mapi id 15.20.5504.019; Sun, 7 Aug 2022 17:34:10 +0000 From: "Wang, Jian J" To: "Vang, Judah" , "devel@edk2.groups.io" CC: "Yao, Jiewen" , "Xu, Min M" , "Mistry, Nishant C" Subject: Re: [PATCH v3 17/28] SecurityPkg: Add Protected Variable Services Thread-Topic: [PATCH v3 17/28] SecurityPkg: Add Protected Variable Services Thread-Index: AQHYe8ayZOFV6MMOckGX2mtuY60fwa2gzdkg Date: Sun, 7 Aug 2022 17:34:10 +0000 Message-ID: References: <20220609060322.3491-1-judah.vang@intel.com> <20220609060322.3491-18-judah.vang@intel.com> In-Reply-To: <20220609060322.3491-18-judah.vang@intel.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: dlp-reaction: no-action dlp-version: 11.6.500.17 dlp-product: dlpe-windows authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=intel.com; x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: cf6b4a1d-e583-4a8d-2a15-08da789b09ce x-ms-traffictypediagnostic: DM6PR11MB4204:EE_ x-ms-exchange-senderadcheck: 1 x-ms-exchange-antispam-relay: 0 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: 5abVr+GUicsagygRaasrxkEQLEe6uOTCsC3oor6Nop5CqucJ+vivpCfurZngjxsDl9esM/YaokI4uk80tKWA3BqP9N/3mNSzUczv4RznvL+dM5o5Of8clt4ugI2LJ90Xi01UnoCpurvW0JJCL3osco+3gWdcpAqiiAjjYD/dCKNoN07h/5LG7aMXMvm902YamC0ALinI5HU3IseaBXXXPupPDGDjw0bGt7qDzmtBCasb4+bywIupUbCXQYnMdUWx35mrl+Iqn0C7puALFRMAjZiuYrRUijBZ8myMyfkWoxBx0rLdT5dGUMS0aKBu1lqrOfZjHqesVaeW3QIlkWktfYAIWSi8lct98398LDd70ILzleDl5PEGEnn5tpSc9JIg8wdmE/lO8aIO04JxFQuPiI7/YMkFYy50PNwwO4EYrflSgLdh1bOKnA+W7eSqfwdeDzIdGs9unnRrlNQnd4YhIlrWkC9ihhaEmZT21caWMmwKXXyM1h48iA+NyD3pBTiZjRH8nKD7IbCR/BIEmXxkPyLBgH/N0k9Ufio9faSppKN6fvxJG1+7SjgEDiztk7dU6dYJzB4vehDNI+xt8Bb2wBjbVyf//741AMXo0YPhK5fHQQ9+fcuQLhisHfsPTaBuzK0yV4aYO8BXetec3OTkWRShQv8Hc2OajFfxQ2qrWq8NnQZUrMXqXHoRsDYExQIhWekH/dH22mgXMZdPKO1RngaHDCWQ0buGADKII17Ho0o9LgR9aXJnxn73txvLReZ6zeI8fL75w+VA5xEpfOsbodxU3ijdqYEL2zjVPm5Z0Usmbbog4pl8jMz5dxeY244Qi8AjzQZnIECHJtYbQSs6ZQ== x-forefront-antispam-report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:CO1PR11MB4945.namprd11.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230016)(376002)(346002)(136003)(366004)(396003)(39860400002)(478600001)(38100700002)(8676002)(30864003)(966005)(52536014)(76116006)(8936002)(66946007)(33656002)(4326008)(2906002)(15650500001)(66556008)(38070700005)(5660300002)(82960400001)(66476007)(9686003)(41300700001)(122000001)(55016003)(53546011)(110136005)(107886003)(186003)(71200400001)(7696005)(26005)(86362001)(6506007)(19627235002)(64756008)(316002)(54906003)(83380400001)(66446008)(559001)(579004);DIR:OUT;SFP:1102; x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?us-ascii?Q?lj9OJJ8AuWG80sItuWBKPrYIYqFGSpEmflIWtIho30zIaFc49LiBFPcvrOK1?= =?us-ascii?Q?NucPAHaOPtXhcD5g3KuNrUSq4NjZK0JjQrOsqZPZBE7OybHyYY41iD8h0SM1?= =?us-ascii?Q?MjbUHSSzVvWBH1RUtJaNzNtZ3k/QALX+IfbR8VM4o4EPSQIiEBL2hUALqx63?= =?us-ascii?Q?cQ3B4B7wR7mRg9SXRXr6OQBRe1/1f0iz3INYn1tDnbGy+qwrNVLbz9Pgt5/V?= =?us-ascii?Q?VRbOsnVUIu+ZCQY81hos/7lDinzn8Gt3Zfm95Dkbjm5vwf643P3aEfaauWda?= =?us-ascii?Q?sDxoueM+yRxHBfX5T7FNRTIS2blSUWb07REYeFr+JC2P6xkLhHTVg+SBpE3X?= =?us-ascii?Q?82DOmS7/IL34SrcNz965eslaE7odzjIdQNW79qAZeCLuIEy3QyBpS6O0zVKg?= =?us-ascii?Q?eW1rglGnaR02ax0boTnblL55GO0xlv6TFE8jIX8pGpYlj5tTotA04rpYN7i9?= =?us-ascii?Q?xZKURVTUlMPhj1Hw474vonVUKEH+3bD4KVszs1mnD8RPHVMaoGePVQkQD61S?= =?us-ascii?Q?/BHA9hLirRlbkSIuwZCVrV/wbc/lL/Prbk7O1Uftm8gQWBaASC8cdmWoh2pU?= =?us-ascii?Q?fMAlLBMrasVbgJC6Ev5yDtbSkoWlxSU9529dnBb/BEtZhI8ILP/esi9TchpN?= =?us-ascii?Q?MEavSrbt+no4FGLB147kbJ9WBwjoq2eHFoWwtNPfY1wEMOUzTMJEF41VndM9?= =?us-ascii?Q?g8zhcVmUOahazLkvmxclucDXiR+WW4wwideaw48jPP0txjsJBzazm91INBH2?= =?us-ascii?Q?8ekqA0+Rkwd3lvr/u9YvCtHPcLxbZXdPDO/+762rMV+LxBCpgrjjmWPb/DYh?= =?us-ascii?Q?6Vw0zYtFQ6zss8d43XG5dmFNJZtHzsXtxhB1hZeHDTQN4RXuV1MFvm6arSal?= =?us-ascii?Q?IlzQaaAbyhsgXNedjT5qh76jEngcPdHMi+Z42s1PKlvqMIx4vhJV1qPKzaLi?= =?us-ascii?Q?bXEcHq/OgBrX4eZNVBSF/Vel523LBsy6U/dJz134Qd3ZjPKqPeMFEFdd0+1+?= =?us-ascii?Q?oLOnfBnCxtEFGSZ1e9haozzRZeqYupr/31ABA/RYALIbjlSojua5qyRJ7Pes?= =?us-ascii?Q?0jzc+IeYpp2LQQwmkorGyT26VRqHZuuAQMlGVA0C31VL6vJwzSTJCDI7ZXbX?= =?us-ascii?Q?/1wqJJV/PF63SrvM6DSI5Z/qAiCMT7XGCDKzwsm6I/CQqUAiz6/5y57G6Y7o?= =?us-ascii?Q?N5kdlEWpXMLU71fGsz75MONL1wdIDvZoffMGSr427kwUQMtm2urgVj76P03G?= =?us-ascii?Q?4Eer0Q4VxvCXJalxuBidyMHnfxXBuWFxPBFWvEniFrseVIq+GoTGlTFzo3h4?= =?us-ascii?Q?qXKDKe2hzFJKNCAp8lf0gIJHDYcEfm0ox2hRUGV2stjKwLOuz+riQgXKBBoN?= =?us-ascii?Q?489OJ+yg6Kio8fvnh6ncaSoh2OoQqbmeqnjEi3Cka6dYdSgWznePRBIkbjQW?= =?us-ascii?Q?+/E0HyTDkpO9bAs3apRb/XNu3+SDgA7j5utB8Dgv1hPdD/yXjcC3s478pJsT?= =?us-ascii?Q?t6tuimZO9R80u4z2MobMPVnsil+IiLO8WCkgIlrUEV2kucMQ7uUKVnF099g6?= =?us-ascii?Q?NBWqy5169hQCSWd7snCSdBNalU+M7eHC5kre00fo?= MIME-Version: 1.0 X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: CO1PR11MB4945.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: cf6b4a1d-e583-4a8d-2a15-08da789b09ce X-MS-Exchange-CrossTenant-originalarrivaltime: 07 Aug 2022 17:34:10.5491 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 46c98d88-e344-4ed4-8496-4ed7712e255d X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: 6x2CsF/m05fPiFb7NmqnkLgxADVkQRTrUBQAukOF0jCcBnDP9nOyJjqNf5ay7TM/aDFfqDcW2EpheSGIzJotyA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM6PR11MB4204 Return-Path: jian.j.wang@intel.com X-OriginatorOrg: intel.com Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Hi Judah, Just one minor issue. In ProtectedVariableInternal.h, following prototype i= s never implemented. ProtectedVariableLibGetNextInternal The logic in this patch is very complicated. It's hard to find out any logi= c issue by reading code. Please make sure that code has been passed enough tests. I can only give ac= k for it. Acked-by: Jian J Wang > -----Original Message----- > From: Vang, Judah > Sent: Thursday, June 09, 2022 2:03 PM > To: devel@edk2.groups.io > Cc: Wang, Jian J ; Yao, Jiewen ; > Xu, Min M ; Mistry, Nishant C > > Subject: [PATCH v3 17/28] SecurityPkg: Add Protected Variable Services >=20 > REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D2594 >=20 > V3: Change placement of buffer used for confidentiality crypto > operation to fix an issue when enabling confidentiality. Remove > un-needed increment of monotonic counter. >=20 > V1: Add Protected Variable Services across the different UEFI phases. > Functions includes creating variable digest, performing integrity > check, initializing protected variables, updating protected > variables, and verifying the MetaDataHmacVar variable. > This module prevents UEFI variable tampering. It provides > variable integrity and confidentiality. >=20 > Cc: Jian J Wang > Cc: Jiewen Yao > Cc: Min Xu > Cc: Nishant C Mistry > Signed-off-by: Jian J Wang > Signed-off-by: Nishant C Mistry > Signed-off-by: Judah Vang > --- > SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf = | 64 > + > SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf = | 68 > + > SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf = | > 67 + > SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib.= inf > | 62 + > SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h = | > 611 ++++++ > SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c = | > 2103 ++++++++++++++++++++ > SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c = | 163 > ++ > SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c = | 1327 > ++++++++++++ > SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c = | 209 > ++ > SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon.c > | 967 +++++++++ > SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c = | > 233 +++ > 11 files changed, 5874 insertions(+) >=20 > diff --git > a/SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf > b/SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.inf > new file mode 100644 > index 000000000000..74a0285af7ef > --- /dev/null > +++ b/SecurityPkg/Library/ProtectedVariableLib/DxeProtectedVariableLib.in= f > @@ -0,0 +1,64 @@ > +## @file > +# Provides protected variable services for EmulatorPkg. > +# > +# Copyright (c) 2022, Intel Corporation. All rights reserved.
> +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x00010029 > + BASE_NAME =3D DxeProtectedVariableLib > + MODULE_UNI_FILE =3D ProtectedVariableLib.uni > + FILE_GUID =3D 6F424E10-0F75-4716-9F97-58C2E1C643A= D > + MODULE_TYPE =3D DXE_RUNTIME_DRIVER > + VERSION_STRING =3D 0.1 > + LIBRARY_CLASS =3D ProtectedVariableLib|DXE_RUNTIME_DR= IVER > + > +# > +# The following information is for reference only and not required by th= e build > tools. > +# > +# VALID_ARCHITECTURES =3D IA32 X64 > +# > + > +[Sources] > + ProtectedVariableDxe.c > + ProtectedVariableCommon.c > + ProtectedVariableSmmDxeCommon.c > + ProtectedVariableInternal.h > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + SecurityPkg/SecurityPkg.dec > + CryptoPkg/CryptoPkg.dec > + > +[LibraryClasses] > + BaseLib > + BaseMemoryLib > + DebugLib > + MemoryAllocationLib > + HobLib > + BaseCryptLib > + EncryptionVariableLib > + RpmcLib > + HashApiLib > + SortLib > + > +[Protocols] > + gEfiVariableWriteArchProtocolGuid > + > +[Guids] > + gEdkiiMetaDataHmacVariableGuid > + gEdkiiProtectedVariableGlobalGuid > + gEdkiiVarErrorFlagGuid > + gEdkiiProtectedVariableContextGuid > + > +[Pcd] > + gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName > + gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid > + gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity > + gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize > diff --git a/SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariabl= eLib.inf > b/SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.inf > new file mode 100644 > index 000000000000..44c959a94ca3 > --- /dev/null > +++ b/SecurityPkg/Library/ProtectedVariableLib/PeiProtectedVariableLib.in= f > @@ -0,0 +1,68 @@ > +## @file > +# Provides protected variable services. > +# > +# Copyright (c) 2022, Intel Corporation. All rights reserved.
> +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x00010029 > + BASE_NAME =3D PeiProtectedVariableLib > + MODULE_UNI_FILE =3D ProtectedVariableLib.uni > + FILE_GUID =3D 76FBFBCE-ACBB-4084-A348-8FCC97AAEB9= D > + MODULE_TYPE =3D PEIM > + VERSION_STRING =3D 0.1 > + LIBRARY_CLASS =3D ProtectedVariableLib|PEIM > + > +# > +# The following information is for reference only and not required by th= e build > tools. > +# > +# VALID_ARCHITECTURES =3D IA32 X64 AARCH64 > +# > + > +[Sources] > + ProtectedVariablePei.c > + ProtectedVariableCommon.c > + ProtectedVariableInternal.h > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + SecurityPkg/SecurityPkg.dec > + CryptoPkg/CryptoPkg.dec > + > +[LibraryClasses] > + BaseLib > + BaseMemoryLib > + DebugLib > + MemoryAllocationLib > + HobLib > + BaseCryptLib > + RpmcLib > + VariableKeyLib > + EncryptionVariableLib > + ReportStatusCodeLib > + PeiServicesLib > + HashApiLib > + SortLib > + > +[Guids] > + gEdkiiMetaDataHmacVariableGuid > + gEdkiiProtectedVariableGlobalGuid > + gEdkiiVarErrorFlagGuid > + gEdkiiProtectedVariableContextGuid > + > +[Ppis] > + gEfiPeiMemoryDiscoveredPpiGuid > + gEfiPeiVariableStoreDiscoveredPpiGuid > + > +[Pcd] > + gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeVariableIntegrity > + gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName > + gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid > + gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity > + gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize > diff --git > a/SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf > b/SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.inf > new file mode 100644 > index 000000000000..ecf0b1a43d30 > --- /dev/null > +++ b/SecurityPkg/Library/ProtectedVariableLib/SmmProtectedVariableLib.in= f > @@ -0,0 +1,67 @@ > +## @file > +# Provides protected variable services. > +# > +# Copyright (c) 2022, Intel Corporation. All rights reserved.
> +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x00010029 > + BASE_NAME =3D SmmProtectedVariableLib > + MODULE_UNI_FILE =3D ProtectedVariableLib.uni > + FILE_GUID =3D 2BEE71E5-259B-4057-A2C1-2115DF43C76= A > + MODULE_TYPE =3D DXE_SMM_DRIVER > + VERSION_STRING =3D 0.1 > + LIBRARY_CLASS =3D ProtectedVariableLib|DXE_SMM_DRIVER > MM_STANDALONE > + > +# > +# The following information is for reference only and not required by th= e build > tools. > +# > +# VALID_ARCHITECTURES =3D IA32 X64 > +# > + > +[Sources] > + ProtectedVariableSmm.c > + ProtectedVariableCommon.c > + ProtectedVariableSmmDxeCommon.c > + ProtectedVariableInternal.h > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + SecurityPkg/SecurityPkg.dec > + CryptoPkg/CryptoPkg.dec > + > +[LibraryClasses] > + BaseLib > + BaseMemoryLib > + DebugLib > + MemoryAllocationLib > + HobLib > + BaseCryptLib > + EncryptionVariableLib > + RpmcLib > + VariableKeyLib > + HashApiLib > + SortLib > + > +[Protocols] > + gEfiMmEndOfDxeProtocolGuid > + > +[Guids] > + gSmmVariableWriteGuid > + gEdkiiMetaDataHmacVariableGuid > + gEdkiiProtectedVariableGlobalGuid > + gEdkiiVarErrorFlagGuid > + gEdkiiProtectedVariableContextGuid > + > +[Pcd] > + gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName > + gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid > + gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity > + gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize > + > diff --git > a/SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib= .i > nf > b/SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib= .i > nf > new file mode 100644 > index 000000000000..011ccdce2db8 > --- /dev/null > +++ > b/SecurityPkg/Library/ProtectedVariableLib/SmmRuntimeProtectedVariableLib= .i > nf > @@ -0,0 +1,62 @@ > +## @file > +# Provides protected variable services. > +# > +# Copyright (c) 2022, Intel Corporation. All rights reserved.
> +# SPDX-License-Identifier: BSD-2-Clause-Patent > +# > +## > + > +[Defines] > + INF_VERSION =3D 0x00010029 > + BASE_NAME =3D SmmRuntimeProtectedVariableLib > + MODULE_UNI_FILE =3D ProtectedVariableLib.uni > + FILE_GUID =3D 99A623DE-1AD3-4AB3-909D-E3AADD7845E= F > + MODULE_TYPE =3D DXE_RUNTIME_DRIVER > + VERSION_STRING =3D 0.1 > + LIBRARY_CLASS =3D ProtectedVariableLib|DXE_DRIVER > DXE_RUNTIME_DRIVER > + > +# > +# The following information is for reference only and not required by th= e build > tools. > +# > +# VALID_ARCHITECTURES =3D IA32 X64 > +# > + > +[Sources] > + ProtectedVariableSmmRuntime.c > + ProtectedVariableCommon.c > + ProtectedVariableInternal.h > + > +[Packages] > + MdePkg/MdePkg.dec > + MdeModulePkg/MdeModulePkg.dec > + SecurityPkg/SecurityPkg.dec > + CryptoPkg/CryptoPkg.dec > + > +[LibraryClasses] > + BaseLib > + BaseMemoryLib > + DebugLib > + MemoryAllocationLib > + HobLib > + BaseCryptLib > + EncryptionVariableLib > + RpmcLib > + HashApiLib > + SortLib > + > +[Guids] > + gEfiEventVirtualAddressChangeGuid > + gEdkiiMetaDataHmacVariableGuid > + gEdkiiProtectedVariableGlobalGuid > + gEdkiiVarErrorFlagGuid > + gEdkiiProtectedVariableContextGuid > + > +[Pcd] > + gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableName > + gEfiSecurityPkgTokenSpaceGuid.PcdPlatformVariableGuid > + gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableIntegrity > + gEfiSecurityPkgTokenSpaceGuid.PcdProtectedVariableConfidentiality > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxAuthVariableSize > + gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize > + > diff --git > a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h > b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.h > new file mode 100644 > index 000000000000..fd38b5bd2019 > --- /dev/null > +++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableInternal.= h > @@ -0,0 +1,611 @@ > +/** @file > + Definitions shared among different implementation of ProtectedVariable= Lib. > + > +Copyright (c) 2022, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#ifndef PROTECTED_VARIABLE_INTERNAL_H_ > +#define PROTECTED_VARIABLE_INTERNAL_H_ > + > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define VARIABLE_KEY_SIZE (256/8) > + > +#define METADATA_HMAC_SIZE (256/8) > +#define METADATA_HMAC_KEY_NAME L"HMAC_KEY" > +#define METADATA_HMAC_KEY_NAME_SIZE 0x10 > + > +#define METADATA_HMAC_SEP L":" > +#define METADATA_HMAC_SEP_SIZE 2 > + > +#define METADATA_HMAC_VARIABLE_NAME L"MetaDataHmacVar" > +#define METADATA_HMAC_VARIABLE_NAME_SIZE sizeof > (METADATA_HMAC_VARIABLE_NAME) > +#define METADATA_HMAC_VARIABLE_GUID > gEdkiiMetaDataHmacVariableGuid > +#define METADATA_HMAC_VARIABLE_ATTR > VARIABLE_ATTRIBUTE_NV_BS_RT > + > +#define DIGEST_CONTEXT_SIZE (HashApiGetContextSize()) > + > +#define MAX_VARIABLE_SIZE = \ > + MAX (MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 > (PcdMaxAuthVariableSize)), \ > + PcdGet32 (PcdMaxHardwareErrorVariableSize)) > + > +#define IS_VARIABLE(Var, Name, Guid) \ > + (StrCmp ((Var)->VariableName, (Name)) =3D=3D 0 \ > + && CompareGuid ((CONST EFI_GUID *)(Var)->VendorGuid, (CONST EFI_GUID > *)(Guid))) > + > +#define VARIABLE_SIZE(VarInfo) \ > + (((UINTN)(VarInfo)->Header.Data - (UINTN)(VarInfo)->Buffer) \ > + + (VarInfo)->Header.DataSize \ > + + GET_PAD_SIZE ((VarInfo)->Header.DataSize)) > + > +#define VARIABLE_HEADER_SIZE(AuthFlag) \ > + ((AuthFlag) ? sizeof (AUTHENTICATED_VARIABLE_HEADER) \ > + : sizeof (VARIABLE_HEADER)) > + > +#define VARIABLE_NAME(Var, AuthFlag) \ > + ((CHAR16 *)((UINTN)(Var) + VARIABLE_HEADER_SIZE(AuthFlag))) > + > +#define VARIABLE_START(VarStore) \ > + ((VARIABLE_HEADER *)HEADER_ALIGN ((VARIABLE_STORE_HEADER > *)(VarStore) + 1)) > + > +#define VARIABLE_END(VarStore) \ > + ((VARIABLE_HEADER *)HEADER_ALIGN ((UINTN)(VarStore) \ > + + ((VARIABLE_STORE_HEADER *)(VarStore))->Size)) > + > +#define SET_VARIABLE_DATA_SIZE(VarInfo, Size) = \ > + if ((VarInfo)->Flags.Auth) { = \ > + ((AUTHENTICATED_VARIABLE_HEADER *)((VarInfo)->Buffer))->DataSize =3D > Size; \ > + (VarInfo)->Header.DataSize =3D Size; = \ > + } else { = \ > + ((VARIABLE_HEADER *)((VarInfo)->Buffer))->DataSize =3D Size; = \ > + (VarInfo)->Header.DataSize =3D Size; = \ > + } > + > +#define IS_KNOWN_UNPROTECTED_VARIABLE(Global, VarInfo) \ > + (CheckKnownUnprotectedVariable ((Global), (VarInfo)) < > UnprotectedVarIndexMax) > + > +#define GET_CNTX(Global) ((PROTECTED_VARIABLE_CONTEXT_IN > *)(UINTN)((Global)->ContextIn)) > +#define GET_BUFR(Address) ((VOID *)(UINTN)(Address)) > +#define GET_ADRS(Buffer) ((EFI_PHYSICAL_ADDRESS)(UINTN)(Buffer)) > + > +typedef struct _VARIABLE_IDENTIFIER { > + CHAR16 *VariableName; > + EFI_GUID *VendorGuid; > + UINT8 State; > +} VARIABLE_IDENTIFIER; > + > +typedef enum { > + IndexHmacInDel =3D 0, /// MetaDataHmacVar with state > VAR_IN_DELETED_TRANSITION > + IndexHmacAdded, /// MetaDataHmacVar with state VAR_ADDED > + IndexErrorFlag, /// VarErrorFlag > + IndexPlatformVar, /// Platform Variable > + UnprotectedVarIndexMax > +} UNPROTECTED_VARIABLE_INDEX; > + > +#pragma pack(1) > + > +#define PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION 0x02 > + > +typedef struct _PROTECTED_VARIABLE_FLAG { > + BOOLEAN Auth; // Authenticated variable format > + BOOLEAN WriteInit; // Write-init-done > + BOOLEAN WriteReady; // Ready-to-write > + BOOLEAN RecoveryMode; // Variable storage recovery or provisioning > + BOOLEAN CacheReady; // Indicates Cache is available > + BOOLEAN Reserved; // reserved > +} PROTECTED_VARIABLE_FLAG; > + > +typedef struct _PROTECTED_VARIABLE_GLOBAL { > + UINT32 StructVersion; > + UINT32 StructSize; > + > + /// > + /// Variable root key used to derive Encryption key and HMAC key. > + /// > + UINT8 RootKey[VARIABLE_KEY_SIZE]; > + /// > + /// HMAC key derived from RootKey. > + /// > + UINT8 MetaDataHmacKey[VARIABLE_KEY_SIZE]; > + /// > + /// Number of variables in linked list pointed by VariableDigests. > + /// > + UINT32 VariableNumber; > + /// > + /// Size of memory reserved by VariableCache. > + /// > + UINT32 VariableCacheSize; > + /// > + /// Memory reserved to temporarily hold data of one variable, for inte= grity > + /// validation purpose. > + /// > + EFI_PHYSICAL_ADDRESS VariableCache; > + /// > + /// Pointer to linked list, in which each node holds the digest value = of each > + /// variable. > + /// > + EFI_PHYSICAL_ADDRESS VariableDigests; > + /// > + /// Memory reserved for Context used in hash API to avoid repeat alloc= /free. > + /// > + EFI_PHYSICAL_ADDRESS DigestContext; > + /// > + /// Pointer to one of node in linked list pointed by VariableDigests, = which > + /// has been just accessed. This is mainly used to facilitate the two = calls > + /// use case of GetVariable(). > + /// > + EFI_PHYSICAL_ADDRESS LastAccessedVariable; > + /// > + /// Cached copy of pointers to nodes of unprotected variables in the l= inked > + /// list pointed by VariableDigests. > + /// > + EFI_PHYSICAL_ADDRESS Unprotected[UnprotectedVarIndexMax]; > + /// > + /// Pointer to data structure holding helper functions passed by user = of > + /// ProtectedVariableLib, most of which are used to complete operation= s on > + /// variable storage. > + /// > + EFI_PHYSICAL_ADDRESS ContextIn; > + > + /// > + /// Pointer to Global data structure. This is to hold pre-mem address = value. > + /// Later to be used to identify pre-mem to post-mem transition. > + /// > + EFI_PHYSICAL_ADDRESS GlobalSelf; > + > + PROTECTED_VARIABLE_FLAG Flags; > +} PROTECTED_VARIABLE_GLOBAL; > + > +#pragma pack() > + > +/* Sort method function pointer taking two parameters */ > +typedef > +INTN > +(*SORT_METHOD) ( > + IN VARIABLE_DIGEST *Variable1, > + IN VARIABLE_DIGEST *Variable2 > + ); > + > +/* Update variable digest data function pointer */ > +typedef > +BOOLEAN > +(*DIGEST_UPDATE) ( > + IN OUT VOID *Context, > + IN VOID *Data, > + IN UINTN DataSize > + ); > + > +/** > + > + Print variable information > + > + @param[in] Data8 Pointer to data > + @param[out] DataSize Size of data > + > +**/ > +VOID > +PrintVariableData ( > + IN UINT8 *Data8, > + IN UINTN DataSize > + ); > + > +/** > + > + Derive HMAC key from given variable root key. > + > + @param[in] RootKey Pointer to root key to derive from. > + @param[in] RootKeySize Size of root key. > + @param[out] HmacKey Pointer to generated HMAC key. > + @param[in] HmacKeySize Size of HMAC key. > + > + @retval TRUE The HMAC key is derived successfully. > + @retval FALSE Failed to generate HMAC key from given root key. > + > +**/ > +BOOLEAN > +EFIAPI > +GenerateMetaDataHmacKey ( > + IN CONST UINT8 *RootKey, > + IN UINTN RootKeySize, > + OUT UINT8 *HmacKey, > + IN UINTN HmacKeySize > + ); > + > +/** > + > + Digests the given variable data and updates HMAC context. > + > + @param[in,out] Context Pointer to initialized HMAC context. > + @param[in] VarInfo Pointer to variable data. > + > + @retval TRUE HMAC context was updated successfully. > + @retval FALSE Failed to update HMAC context. > + > +**/ > +BOOLEAN > +UpdateVariableMetadataHmac ( > + IN VOID *Context, > + IN PROTECTED_VARIABLE_INFO *VarInfo > + ); > + > +/** > + > + Re-calculate HMAC based on new variable data and re-generate > MetaDataHmacVar. > + > + @param[in] Global Pointer to global configuration data. > + @param[in] NewVarInfo Pointer to buffer of new variable data= . > + @param[in,out] NewHmacVarInfo Pointer to buffer of new > MetaDataHmacVar. > + > + @return EFI_SUCCESS The HMAC value was updated successfully. > + @return EFI_ABORTED Failed to calculate the HMAC value. > + @return EFI_OUT_OF_RESOURCES Not enough resource to calculate HMC > value. > + @return EFI_NOT_FOUND The MetaDataHmacVar was not found in > storage. > + > +**/ > +EFI_STATUS > +RefreshVariableMetadataHmac ( > + IN PROTECTED_VARIABLE_GLOBAL *Global, > + IN PROTECTED_VARIABLE_INFO *NewVarInfo, > + IN OUT PROTECTED_VARIABLE_INFO *NewHmacVarInfo > + ); > + > +/** > + > + Retrieve the context and global configuration data structure from HOB. > + > + Once protected NV variable storage is cached and verified in PEI phase= , > + all related information are stored in a HOB which can be used by PEI v= ariable > + service itself and passed to SMM along with the boot flow, which can a= void > + many duplicate works, like generating HMAC key, verifying NV variable > storage, > + etc. > + > + The HOB can be identified by gEdkiiProtectedVariableGlobalGuid. > + > + @param[out] Global Pointer to global configuration data from PE= I phase. > + > + @retval EFI_SUCCESS The HOB was found, and Context and Global are > retrieved. > + @retval EFI_NOT_FOUND The HOB was not found. > + > +**/ > +EFI_STATUS > +EFIAPI > +GetProtectedVariableGlobalFromHob ( > + OUT PROTECTED_VARIABLE_GLOBAL **Global OPTIONAL > + ); > + > +/** > + > + Get context and/or global data structure used to process protected var= iable. > + > + @param[out] Global Pointer to global configuration data. > + > + @retval EFI_SUCCESS Get requested structure successfully. > + > +**/ > +EFI_STATUS > +EFIAPI > +GetProtectedVariableGlobal ( > + OUT PROTECTED_VARIABLE_GLOBAL **Global OPTIONAL > + ); > + > +/** > + > + Get context data structure used to process protected variable. > + > + @param[out] ContextIn Pointer to context provided by variable runt= ime > services. > + > + @retval EFI_SUCCESS Get requested structure successfully. > + > +**/ > +EFI_STATUS > +EFIAPI > +GetProtectedVariableContext ( > + PROTECTED_VARIABLE_CONTEXT_IN **ContextIn OPTIONAL > + ); > + > +/** > + > + Check if a given variable is unprotected variable specified in advance > + and return its index ID. > + > + @param[in] Global Pointer to global configuration data. > + @param[in] VarInfo Pointer to variable information data. > + > + @retval IndexHmacInDel Variable is MetaDataHmacVar in delete-transi= tion > state. > + @retval IndexHmacAdded Variable is MetaDataHmacVar in valid state. > + @retval IndexErrorFlag Variable is VarErrorLog. > + @retval Others Variable is not any known unprotected variab= les. > + > +**/ > +UNPROTECTED_VARIABLE_INDEX > +CheckKnownUnprotectedVariable ( > + IN PROTECTED_VARIABLE_GLOBAL *Global, > + IN PROTECTED_VARIABLE_INFO *VarInfo > + ); > + > +/** > + > + Return the size of variable MetaDataHmacVar. > + > + @param[in] AuthFlag Auth-variable indicator. > + > + @retval size of variable MetaDataHmacVar. > + > +**/ > +UINTN > +GetMetaDataHmacVarSize ( > + IN BOOLEAN AuthFlag > + ); > + > +/** > + > + Fix state of MetaDataHmacVar on NV variable storage, if there's failur= e at > + last boot during updating variable. > + > + This must be done before the first writing of variable in current boot= , > + including storage reclaim. > + > + @retval EFI_UNSUPPORTED Updating NV variable storage is not > supported. > + @retval EFI_OUT_OF_RESOURCES Not enough resource to complete the > operation. > + @retval EFI_SUCCESS Variable store was successfully updated= . > + > +**/ > +EFI_STATUS > +FixupHmacVariable ( > + VOID > + ); > + > +/** > + > + Verify the variable digest. > + > + @param[in] Global Pointer to global configuration data. > + @param[in] VarInfo Pointer to verified copy of protected variable= s. > + @param[in] VarDig Pointer to variable digest data. > + > + @retval EFI_INVALID_PARAMETER Invalid parameter was passed in. > + @retval EFI_OUT_OF_RESOURCES Not enough resource to calculate hash. > + @retval EFI_ABORTED An error was encountered. > + @retval EFI_COMPROMISED_DATA The data was compromised. > + @retval EFI_SUCCESS Variable digest was successfully verifi= ed. > + > +**/ > +EFI_STATUS > +VerifyVariableDigest ( > + IN PROTECTED_VARIABLE_GLOBAL *Global, > + IN PROTECTED_VARIABLE_INFO *VarInfo, > + IN VARIABLE_DIGEST *VarDig > + ); > + > +/** > + > + Get the variable digest. > + > + @param[in] Global Pointer to global configuration data. > + @param[in] VarInfo Pointer to verified copy of protected va= riables. > + @param[in,out] DigestValue Pointer to variable digest value. > + > + @retval EFI_INVALID_PARAMETER Invalid parameter was passed in. > + @retval EFI_OUT_OF_RESOURCES Not enough resource to calculate hash. > + @retval EFI_ABORTED An error was encountered. > + @retval EFI_COMPROMISED_DATA The data was compromised. > + @retval EFI_SUCCESS Variable digest was successfully verifi= ed. > + > +**/ > +EFI_STATUS > +GetVariableDigest ( > + IN PROTECTED_VARIABLE_GLOBAL *Global, > + IN PROTECTED_VARIABLE_INFO *VarInfo, > + IN OUT UINT8 *DigestValue > + ); > + > +/** > + > + Compare variable name and Guid > + > + @param[in] Name1 Name of first variable. > + @param[in] Name1Size Size of first variable. > + @param[in] Name2 Name of second variable. > + @param[in] Name2Size Size of second variable. > + @param[in] Guid1 Guid for first variable. > + @param[in] Guid2 Guid for second variable. > + > + @retval 0 First name is identical to Second name. > + @return others First name is not identical to Second name. > + > +**/ > +INTN > +CompareVariableNameAndGuid ( > + IN CONST CHAR16 *Name1, > + IN UINTN Name1Size, > + IN CONST CHAR16 *Name2, > + IN UINTN Name2Size, > + IN EFI_GUID *Guid1, > + IN EFI_GUID *Guid2 > + ); > + > +/** > + > + Compare variable digest. > + > + @param[in] Variable1 Pointer to first variable digest. > + @param[in] Variable2 Pointer to second variable digest. > + > + @retval 0 Variables are identical. > + @return others Variables are not identical. > + > +**/ > +INTN > +CompareVariableDigestInfo ( > + IN VARIABLE_DIGEST *Variable1, > + IN VARIABLE_DIGEST *Variable2 > + ); > + > +/** > + > + Move a node backward in the order controlled by SortMethod. > + > + @param[in] Node Pointer to node to be moved. > + @param[in] SortMethod Method used to compare node in list. > + > +**/ > +VOID > +MoveNodeBackward ( > + IN OUT VARIABLE_DIGEST *Node, > + IN SORT_METHOD SortMethod > + ); > + > +/** > + > + Remove variable digest node. > + > + @param[in,out] Global Pointer to global configuration data. > + @param[in,out] VarDig Pointer to variable digest value. > + @param[in] FreeResource Flag to indicate whether to free resourc= e. > + > +**/ > +VOID > +RemoveVariableDigestNode ( > + IN OUT PROTECTED_VARIABLE_GLOBAL *Global, > + IN OUT VARIABLE_DIGEST *VarDig, > + IN BOOLEAN FreeResource > + ); > + > +/** > + > + Insert variable digest node. > + > + @param[in,out] Global Pointer to global configuration data. > + @param[in] VarDig Pointer to variable digest value. > + @param[in] SortMethod Method for sorting. > + > +**/ > +VOID > +InsertVariableDigestNode ( > + IN OUT PROTECTED_VARIABLE_GLOBAL *Global, > + IN VARIABLE_DIGEST *VarDig, > + IN SORT_METHOD SortMethod > + ); > + > +/** > + > + Create variable digest node. > + > + @param[in] VariableName Name of variable. > + @param[in] VendorGuid Guid of variable. > + @param[in] NameSize Size of variable name. > + @param[in] DataSize Size of variable data. > + @param[in] AuthVar Authenticated variable flag. > + @param[in] Global Pointer to global configuration data. > + > + @retval Ptr Pointer to variable digest > + > +**/ > +VARIABLE_DIGEST * > +CreateVariableDigestNode ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN UINT16 NameSize, > + IN UINT32 DataSize, > + IN BOOLEAN AuthVar, > + IN PROTECTED_VARIABLE_GLOBAL *Global > + ); > + > +/** > + > + This function is used to enumerate the variables managed by current > + ProtectedVariableLib. > + > + If the VarInfo->StoreIndex is invalid (VAR_INDEX_INVALID), the first v= ariable > + with the smallest StoreIndex will be returned. Otherwise, the variable= with > + StoreIndex just after than the VarInfo->StoreIndex will be returned. > + > + @param[in,out] VarInfo Pointer to structure containing variab= le > information. > + > + @retval EFI_SUCCESS Found the specified variable. > + @retval EFI_INVALID_PARAMETER VarInfo is NULL. > + @retval EFI_NOT_FOUND The specified variable could not be = found. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibGetNextInternal ( > + IN OUT PROTECTED_VARIABLE_INFO *VarInfo > + ); > + > +/** > + > + Find the specified variable digest > + > + @param[in] Global Pointer to global configuration data. > + @param[in] VarInfo Pointer to variable data. > + @param[in] FindNext Flag to continue looking for variable. > + > +**/ > +VARIABLE_DIGEST * > +FindVariableInternal ( > + IN PROTECTED_VARIABLE_GLOBAL *Global, > + IN PROTECTED_VARIABLE_INFO *VarInfo, > + IN BOOLEAN FindNext > + ); > + > +/** > + > + Synchronize the RPMC counters > + > + @param[in] Global Pointer to global configuration data. > + @param[in] VarInfo Pointer to variable data. > + @param[in] FindNext Flag to continue looking for variable. > + > + @retval EFI_SUCCESS Successfully sync RPMC counters. > + @return others Failed to sync RPMC counters. > + > +**/ > +EFI_STATUS > +SyncRpmcCounter ( > + VOID > + ); > + > +/** > + > + Perform for protected variable integrity check. > + > + If this initialization failed upon any error, the whole variable servi= ces > + should not be used. A system reset might be needed to re-construct NV > + variable storage to be the default state. > + > + @param[in] ContextIn Pointer to variable service context needed by > + protected variable. > + > + @retval EFI_SUCCESS Protected variable services are read= y. > + @retval EFI_INVALID_PARAMETER If ContextIn =3D=3D NULL or somethin= g > missing or > + mismatching in the content in Contex= tIn. > + @retval EFI_COMPROMISED_DATA If failed to check integrity of prot= ected > variables. > + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource. > + @retval EFI_UNSUPPORTED Unsupported to process protected var= iable. > + > +**/ > +EFI_STATUS > +EFIAPI > +PerformVariableIntegrityCheck ( > + IN PROTECTED_VARIABLE_CONTEXT_IN *ContextIn > + ); > + > +extern EFI_TIME mDefaultTimeStamp; > +extern VARIABLE_IDENTIFIER > mUnprotectedVariables[UnprotectedVarIndexMax]; > +extern PROTECTED_VARIABLE_CONTEXT_IN mVariableContextIn; > +extern PROTECTED_VARIABLE_GLOBAL mProtectedVariableGlobal; > + > +#endif > diff --git > a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c > b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c > new file mode 100644 > index 000000000000..456c871a4561 > --- /dev/null > +++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableCommon.c > @@ -0,0 +1,2103 @@ > +/** @file > + The common protected variable operation routines. > + > +Copyright (c) 2022, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > + > +#include > +#include > + > +#include > +#include > +#include > +#include > + > +#include "ProtectedVariableInternal.h" > + > +EFI_TIME mDefaultTimeStamp =3D { 0, 0, 0, 0, 0, 0, 0, = 0, 0, 0, 0 }; > +VARIABLE_IDENTIFIER mUnprotectedVariables[] =3D { > + { > + METADATA_HMAC_VARIABLE_NAME, > + &METADATA_HMAC_VARIABLE_GUID, > + VAR_ADDED & VAR_IN_DELETED_TRANSITION > + }, > + { > + METADATA_HMAC_VARIABLE_NAME, > + &METADATA_HMAC_VARIABLE_GUID, > + VAR_ADDED > + }, > + { > + VAR_ERROR_FLAG_NAME, > + &gEdkiiVarErrorFlagGuid, > + VAR_ADDED > + }, > + { > + (CHAR16 *)PcdGetPtr (PcdPlatformVariableName), > + (EFI_GUID *)PcdGetPtr (PcdPlatformVariableGuid), > + VAR_ADDED > + } > +}; > + > +/** > + Print variable information. > + > + @param[in] Data8 Pointer to data. > + @param[in] DataSize Size of data. > + > +**/ > +VOID > +PrintVariableData ( > + IN UINT8 *Data8, > + IN UINTN DataSize > + ) > +{ > + UINTN Index; > + > + for (Index =3D 0; Index < DataSize; Index++) { > + if (Index % 0x10 =3D=3D 0) { > + DEBUG ((DEBUG_INFO, "\n%08X:", Index)); > + } > + > + DEBUG ((DEBUG_INFO, " %02X", *Data8++)); > + } > + > + DEBUG ((DEBUG_INFO, "\n")); > +} > + > +/** > + > + Retrieve the context and global configuration data structure from HOB. > + > + Once protected NV variable storage is cached and verified in PEI phase= , > + all related information are stored in a HOB which can be used by PEI v= ariable > + service itself and passed to SMM along with the boot flow, which can a= void > + many duplicate works, like generating HMAC key, verifying NV variable > storage, > + etc. > + > + The HOB can be identified by gEdkiiProtectedVariableGlobalGuid. > + > + @param[out] Global Pointer to global configuration data from PE= I phase. > + > + @retval EFI_SUCCESS The HOB was found, and Context and Global are > retrieved. > + @retval EFI_NOT_FOUND The HOB was not found. > + > +**/ > +EFI_STATUS > +EFIAPI > +GetProtectedVariableGlobalFromHob ( > + OUT PROTECTED_VARIABLE_GLOBAL **Global > + ) > +{ > + VOID *Data; > + EFI_PEI_HOB_POINTERS Hob; > + EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob; > + PROTECTED_VARIABLE_CONTEXT_IN *ContextIn; > + EFI_PHYSICAL_ADDRESS OldStart; > + VARIABLE_DIGEST *VarDig; > + EFI_HOB_GUID_TYPE *GuidHob; > + UINTN Index; > + > + Hob.Raw =3D GetFirstGuidHob (&gEdkiiProtectedVariableGlobalGuid); > + if (Hob.Raw !=3D NULL) { > + Data =3D GET_GUID_HOB_DATA (Hob); > + } else { > + // > + // Search the global from allocated memory blob. > + // > + Data =3D NULL; > + MemoryAllocationHob =3D NULL; > + > + Hob.Raw =3D GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION); > + while (Hob.Raw !=3D NULL) { > + MemoryAllocationHob =3D (EFI_HOB_MEMORY_ALLOCATION *)Hob.Raw; > + if (CompareGuid ( > + &MemoryAllocationHob->AllocDescriptor.Name, > + &gEdkiiProtectedVariableGlobalGuid > + )) > + { > + Data =3D (VOID *)(UINTN) > + MemoryAllocationHob->AllocDescriptor.MemoryBaseAddress; > + break; > + } > + > + Hob.Raw =3D GET_NEXT_HOB (Hob); > + Hob.Raw =3D GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, > Hob.Raw); > + } > + } > + > + if (Data =3D=3D NULL) { > + return EFI_NOT_FOUND; > + } > + > + if (Global !=3D NULL) { > + GuidHob =3D GetFirstGuidHob (&gEdkiiProtectedVariableContextGuid); > + if (GuidHob !=3D NULL) { > + ContextIn =3D (PROTECTED_VARIABLE_CONTEXT_IN *)GET_GUID_HOB_DATA > (GuidHob); > + } else { > + ASSERT (GuidHob =3D=3D NULL); > + } > + > + *Global =3D (PROTECTED_VARIABLE_GLOBAL *)((UINT8 *)Data); > + // > + // Fix pointers in the HOB (due to physical memory readiness) > + // > + if ((*Global)->GlobalSelf !=3D (EFI_PHYSICAL_ADDRESS)(UINTN)(*Global= )) { > + OldStart =3D (*Global)->GlobalSelf; > + (*Global)->ContextIn =3D GET_ADRS (ContextIn); > + > + // > + // Mark Memory caching is available > + // > + (*Global)->Flags.CacheReady =3D TRUE; > + > + // > + // Re-allocate new minimum cache > + // > + (*Global)->VariableCache =3D GET_ADRS (Data) > + + ((*Global)->VariableCache - OldStart)= ; > + > + (*Global)->DigestContext =3D GET_ADRS (((*Global) + 1)); > + for (Index =3D 0; Index < UnprotectedVarIndexMax; Index++) { > + if ((*Global)->Unprotected[Index] !=3D VAR_INDEX_INVALID) { > + (*Global)->Unprotected[Index] =3D GET_ADRS (Data) > + + ((*Global)->Unprotected[Inde= x] - OldStart); > + } > + } > + > + (*Global)->LastAccessedVariable =3D GET_ADRS (Data) > + + ((*Global)->LastAccessedVariab= le - OldStart); > + > + // > + // Fix all linked-list pointers inside VARIABLE_SIGNATURE. > + // > + (*Global)->VariableDigests =3D GET_ADRS (Data) > + + ((*Global)->VariableDigests - OldSt= art); > + VarDig =3D VAR_DIG_PTR ((*Global)->VariableDigests); > + while (VarDig !=3D NULL) { > + if (VarDig->Prev !=3D 0) { > + VarDig->Prev =3D GET_ADRS (Data) + (VarDig->Prev - OldStart); > + } > + > + if (VarDig->Next !=3D 0) { > + VarDig->Next =3D GET_ADRS (Data) + (VarDig->Next - OldStart); > + } > + > + VarDig =3D VAR_DIG_NEXT (VarDig); > + } > + > + (*Global)->GlobalSelf =3D (EFI_PHYSICAL_ADDRESS)(UINTN)(*Global); > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + > + Derive HMAC key from given variable root key. > + > + @param[in] RootKey Pointer to root key to derive from. > + @param[in] RootKeySize Size of root key. > + @param[out] HmacKey Pointer to generated HMAC key. > + @param[in] HmacKeySize Size of HMAC key. > + > + @retval TRUE The HMAC key is derived successfully. > + @retval FALSE Failed to generate HMAC key from given root key. > + > +**/ > +BOOLEAN > +EFIAPI > +GenerateMetaDataHmacKey ( > + IN CONST UINT8 *RootKey, > + IN UINTN RootKeySize, > + OUT UINT8 *HmacKey, > + IN UINTN HmacKeySize > + ) > +{ > + UINT8 Salt[AES_BLOCK_SIZE]; > + > + return HkdfSha256ExtractAndExpand ( > + RootKey, > + RootKeySize, > + Salt, > + 0, > + (UINT8 *)METADATA_HMAC_KEY_NAME, > + METADATA_HMAC_KEY_NAME_SIZE, > + HmacKey, > + HmacKeySize > + ); > +} > + > +/** > + > + Return the size of variable MetaDataHmacVar. > + > + @param[in] AuthFlag Auth-variable indicator. > + > + @retval size of variable MetaDataHmacVar. > + > +**/ > +UINTN > +GetMetaDataHmacVarSize ( > + IN BOOLEAN AuthFlag > + ) > +{ > + UINTN Size; > + > + if (AuthFlag) { > + Size =3D sizeof (AUTHENTICATED_VARIABLE_HEADER); > + } else { > + Size =3D sizeof (VARIABLE_HEADER); > + } > + > + Size +=3D METADATA_HMAC_VARIABLE_NAME_SIZE; > + Size +=3D GET_PAD_SIZE (Size); > + Size +=3D METADATA_HMAC_SIZE; > + Size +=3D GET_PAD_SIZE (Size); > + > + return Size; > +} > + > +/** > + > + Digests the given variable data and updates HMAC context. > + > + @param[in] Context Pointer to initialized HMAC context. > + @param[in] VarInfo Pointer to variable data. > + @param[in] UpdateMethod Function to run when updating variable = digest. > + > + @retval TRUE HMAC context was updated successfully. > + @retval FALSE Failed to update HMAC context. > + > +**/ > +STATIC > +BOOLEAN > +UpdateVariableDigestData ( > + IN VOID *Context, > + IN PROTECTED_VARIABLE_INFO *VarInfo, > + IN DIGEST_UPDATE UpdateMethod > + ) > +{ > + VOID *Buffer[12]; > + UINT32 BufferSize[12]; > + UINTN Index; > + BOOLEAN Status; > + > + // > + // Empty variable is legal here (e.g. variable deletion case or write-= init case). > + // > + if ((VarInfo =3D=3D NULL) || > + (VarInfo->CipherData =3D=3D NULL) || > + (VarInfo->CipherDataSize =3D=3D 0)) > + { > + return TRUE; > + } > + > + // > + // HMAC (":" || VariableName) > + // > + Buffer[0] =3D METADATA_HMAC_SEP; > + BufferSize[0] =3D METADATA_HMAC_SEP_SIZE; > + > + Buffer[1] =3D VarInfo->Header.VariableName; > + BufferSize[1] =3D (UINT32)VarInfo->Header.NameSize; > + > + // > + // HMAC (":" || VendorGuid || Attributes || DataSize) > + // > + Buffer[2] =3D METADATA_HMAC_SEP; > + BufferSize[2] =3D METADATA_HMAC_SEP_SIZE; > + > + Buffer[3] =3D VarInfo->Header.VendorGuid; > + BufferSize[3] =3D sizeof (EFI_GUID); > + > + Buffer[4] =3D &VarInfo->Header.Attributes; > + BufferSize[4] =3D sizeof (VarInfo->Header.Attributes); > + > + Buffer[5] =3D &VarInfo->CipherDataSize; > + BufferSize[5] =3D sizeof (VarInfo->CipherDataSize); > + > + // > + // HMAC (":" || CipherData) > + // > + Buffer[6] =3D METADATA_HMAC_SEP; > + BufferSize[6] =3D METADATA_HMAC_SEP_SIZE; > + > + Buffer[7] =3D VarInfo->CipherData; > + BufferSize[7] =3D VarInfo->CipherDataSize; > + > + // > + // HMAC (":" || PubKeyIndex || AuthMonotonicCount || TimeStamp) > + // > + Buffer[8] =3D METADATA_HMAC_SEP; > + BufferSize[8] =3D METADATA_HMAC_SEP_SIZE; > + > + Buffer[9] =3D &VarInfo->Header.PubKeyIndex; > + BufferSize[9] =3D sizeof (VarInfo->Header.PubKeyIndex); > + > + Buffer[10] =3D &VarInfo->Header.MonotonicCount; > + BufferSize[10] =3D sizeof (VarInfo->Header.MonotonicCount); > + > + Buffer[11] =3D (VarInfo->Header.TimeStamp !=3D NULL) ? > + VarInfo->Header.TimeStamp : &mDefaultTimeStamp; > + BufferSize[11] =3D sizeof (EFI_TIME); > + > + for (Index =3D 0; Index < ARRAY_SIZE (Buffer); ++Index) { > + Status =3D UpdateMethod (Context, Buffer[Index], BufferSize[Index]); > + if (!Status) { > + ASSERT (FALSE); > + return FALSE; > + } > + } > + > + return TRUE; > +} > + > +/** > + > + Digests the given variable data and updates HMAC context. > + > + @param[in] Context Pointer to initialized HMAC context. > + @param[in] VarInfo Pointer to variable data. > + > + @retval TRUE HMAC context was updated successfully. > + @retval FALSE Failed to update HMAC context. > + > +**/ > +BOOLEAN > +UpdateVariableMetadataHmac ( > + IN VOID *Context, > + IN PROTECTED_VARIABLE_INFO *VarInfo > + ) > +{ > + return UpdateVariableDigestData (Context, VarInfo, > (DIGEST_UPDATE)HmacSha256Update); > +} > + > +/** > + > + Get the variable digest. > + > + @param[in] Global Pointer to global configuration data. > + @param[in] VarInfo Pointer to verified copy of protected va= riables. > + @param[in,out] DigestValue Pointer to variable digest value. > + > + @retval EFI_INVALID_PARAMETER Invalid parameter was passed in. > + @retval EFI_OUT_OF_RESOURCES Not enough resource to calculate hash. > + @retval EFI_ABORTED An error was encountered. > + @retval EFI_COMPROMISED_DATA The data was compromised. > + @retval EFI_SUCCESS Variable digest was successfully verifi= ed. > + > +**/ > +EFI_STATUS > +GetVariableDigest ( > + IN PROTECTED_VARIABLE_GLOBAL *Global, > + IN PROTECTED_VARIABLE_INFO *VarInfo, > + IN OUT UINT8 *DigestValue > + ) > +{ > + EFI_STATUS Status; > + VOID *Context; > + > + if ((Global =3D=3D NULL) || (VarInfo =3D=3D NULL) || (DigestValue =3D= =3D NULL)) { > + ASSERT (Global !=3D NULL); > + ASSERT (VarInfo !=3D NULL); > + ASSERT (DigestValue !=3D NULL); > + return EFI_INVALID_PARAMETER; > + } > + > + Context =3D GET_BUFR (Global->DigestContext); > + if (!HashApiInit (Context)) { > + ASSERT (Context !=3D NULL); > + return EFI_OUT_OF_RESOURCES; > + } > + > + if (VarInfo->CipherData =3D=3D NULL) { > + VarInfo->CipherData =3D VarInfo->Header.Data; > + VarInfo->CipherDataSize =3D (UINT32)VarInfo->Header.DataSize; > + } > + > + if ( !UpdateVariableDigestData (Context, VarInfo, > (DIGEST_UPDATE)HashApiUpdate) > + || !HashApiFinal (Context, DigestValue)) > + { > + ASSERT (FALSE); > + Status =3D EFI_ABORTED; > + } else { > + Status =3D EFI_SUCCESS; > + } > + > + return Status; > +} > + > +/** > + > + Verify the variable digest. > + > + @param[in] Global Pointer to global configuration data. > + @param[in] VarInfo Pointer to verified copy of protected variable= s. > + @param[in] VarDig Pointer to variable digest data. > + > + @retval EFI_INVALID_PARAMETER Invalid parameter was passed in. > + @retval EFI_OUT_OF_RESOURCES Not enough resource to calculate hash. > + @retval EFI_ABORTED An error was encountered. > + @retval EFI_COMPROMISED_DATA The data was compromised. > + @retval EFI_SUCCESS Variable digest was successfully verifi= ed. > + > +**/ > +EFI_STATUS > +VerifyVariableDigest ( > + IN PROTECTED_VARIABLE_GLOBAL *Global, > + IN PROTECTED_VARIABLE_INFO *VarInfo, > + IN VARIABLE_DIGEST *VarDig > + ) > +{ > + EFI_STATUS Status; > + UINT8 NewDigest[METADATA_HMAC_SIZE]; > + > + if (Global->Flags.RecoveryMode || !VarDig->Flags.Protected) { > + return EFI_SUCCESS; > + } > + > + ASSERT (VarDig->DigestSize =3D=3D sizeof (NewDigest)); > + > + Status =3D GetVariableDigest (Global, VarInfo, NewDigest); > + if (!EFI_ERROR (Status)) { > + if (CompareMem (VAR_DIG_VALUE (VarDig), NewDigest, VarDig- > >DigestSize) !=3D 0) { > + Status =3D EFI_COMPROMISED_DATA; > + } > + } > + > + return Status; > +} > + > +/** > + Initialize variable MetaDataHmacVar. > + > + @param[in,out] Variable Pointer to buffer of MetaDataHmacVar. > + @param[in] AuthFlag Variable format flag. > + > +**/ > +VOID > +InitMetadataHmacVariable ( > + IN OUT VARIABLE_HEADER *Variable, > + IN BOOLEAN AuthFlag > + ) > +{ > + UINT8 *NamePtr; > + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; > + > + Variable->StartId =3D VARIABLE_DATA; > + Variable->State =3D VAR_ADDED; > + Variable->Reserved =3D 0; > + Variable->Attributes =3D VARIABLE_ATTRIBUTE_NV_BS_RT; > + > + if (AuthFlag) { > + AuthVariable =3D (AUTHENTICATED_VARIABLE_HEADER *)Variable; > + > + AuthVariable->NameSize =3D METADATA_HMAC_VARIABLE_NAME_SIZE; > + AuthVariable->DataSize =3D METADATA_HMAC_SIZE; > + AuthVariable->PubKeyIndex =3D 0; > + AuthVariable->MonotonicCount =3D 0; > + > + ZeroMem (&AuthVariable->TimeStamp, sizeof (EFI_TIME)); > + CopyMem (&AuthVariable->VendorGuid, > &METADATA_HMAC_VARIABLE_GUID, sizeof (EFI_GUID)); > + > + NamePtr =3D (UINT8 *)AuthVariable + sizeof > (AUTHENTICATED_VARIABLE_HEADER); > + } else { > + Variable->NameSize =3D METADATA_HMAC_VARIABLE_NAME_SIZE; > + Variable->DataSize =3D METADATA_HMAC_SIZE; > + > + CopyMem (&Variable->VendorGuid, &METADATA_HMAC_VARIABLE_GUID, > sizeof (EFI_GUID)); > + > + NamePtr =3D (UINT8 *)Variable + sizeof (VARIABLE_HEADER); > + } > + > + CopyMem (NamePtr, METADATA_HMAC_VARIABLE_NAME, > METADATA_HMAC_VARIABLE_NAME_SIZE); > +} > + > +/** > + Re-calculate HMAC based on new variable data and re-generate > MetaDataHmacVar. > + > + @param[in] Global Pointer to global configuration data. > + @param[in] NewVarInfo Pointer to buffer of new variable data= . > + @param[in,out] NewHmacVarInfo Pointer to buffer of new > MetaDataHmacVar. > + > + @return EFI_SUCCESS The HMAC value was updated successfully. > + @return EFI_ABORTED Failed to calculate the HMAC value. > + @return EFI_OUT_OF_RESOURCES Not enough resource to calculate HMC > value. > + @return EFI_NOT_FOUND The MetaDataHmacVar was not found in > storage. > + > +**/ > +EFI_STATUS > +RefreshVariableMetadataHmac ( > + IN PROTECTED_VARIABLE_GLOBAL *Global, > + IN PROTECTED_VARIABLE_INFO *NewVarInfo, > + IN OUT PROTECTED_VARIABLE_INFO *NewHmacVarInfo > + ) > +{ > + EFI_STATUS Status; > + VOID *Context; > + UINT32 Counter; > + PROTECTED_VARIABLE_INFO VarInfo; > + PROTECTED_VARIABLE_INFO CurrHmacVarInfo; > + UINT8 *HmacValue; > + PROTECTED_VARIABLE_CONTEXT_IN *ContextIn; > + VARIABLE_DIGEST *VarDig; > + VARIABLE_DIGEST *HmacVarDig; > + > + ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo)); > + ZeroMem ((VOID *)&CurrHmacVarInfo, sizeof (CurrHmacVarInfo)); > + > + Status =3D RequestMonotonicCounter (RPMC_COUNTER_2, &Counter); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + Counter +=3D 1; > + ContextIn =3D GET_CNTX (Global); > + > + // > + // Delete current MetaDataHmacVariable first, if any. > + // > + if (Global->Unprotected[IndexHmacAdded] !=3D VAR_INDEX_INVALID) { > + HmacVarDig =3D VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded]); > + > + CurrHmacVarInfo.Header.NameSize =3D HmacVarDig->NameSize; > + CurrHmacVarInfo.Header.VariableName =3D VAR_DIG_NAME (HmacVarDig); > + CurrHmacVarInfo.Header.VendorGuid =3D VAR_DIG_GUID (HmacVarDig); > + > + CurrHmacVarInfo.Buffer =3D VAR_HDR_PTR (HmacVarDig->CacheIndex); > + CurrHmacVarInfo.StoreIndex =3D HmacVarDig->StoreIndex; > + CurrHmacVarInfo.Flags.Auth =3D HmacVarDig->Flags.Auth; > + // > + // Force marking current MetaDataHmacVariable as > VAR_IN_DELETED_TRANSITION. > + // > + CurrHmacVarInfo.Buffer->State &=3D VAR_IN_DELETED_TRANSITION; > + HmacVarDig->State &=3D VAR_IN_DELETED_TRANSITION; > + Status =3D ContextIn->UpdateVariableStore ( > + &CurrHmacVarInfo, > + OFFSET_OF (VARIABLE_HE= ADER, State), > + sizeof (CurrHmacVarInf= o.Buffer->State), > + &CurrHmacVarInfo.Buffe= r->State > + ); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + } else if (Global->Unprotected[IndexHmacInDel] !=3D VAR_INDEX_INVALID)= { > + HmacVarDig =3D VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel]); > + } else { > + // > + // No MetaDataHmacVar. Allocate space to cache its value. > + // > + HmacVarDig =3D CreateVariableDigestNode ( > + METADATA_HMAC_VARIABLE_NAME, > + &METADATA_HMAC_VARIABLE_GUID, > + METADATA_HMAC_VARIABLE_NAME_SIZE, > + METADATA_HMAC_SIZE, > + Global->Flags.Auth, > + Global > + ); > + if (HmacVarDig =3D=3D NULL) { > + ASSERT (HmacVarDig !=3D NULL); > + return EFI_OUT_OF_RESOURCES; > + } > + > + HmacVarDig->Flags.Protected =3D FALSE; > + } > + > + if (HmacVarDig->CacheIndex =3D=3D VAR_INDEX_INVALID) { > + HmacVarDig->CacheIndex =3D (GET_ADRS (Global)) + (Global->StructSize= - > GetMetaDataHmacVarSize (Global->Flags.Auth)); > + } > + > + // > + // Construct new MetaDataHmacVar. > + // > + if (NewHmacVarInfo =3D=3D NULL) { > + NewHmacVarInfo =3D &VarInfo; > + NewHmacVarInfo->Buffer =3D GET_BUFR (HmacVarDig->CacheIndex); > + } > + > + InitMetadataHmacVariable (NewHmacVarInfo->Buffer, Global->Flags.Auth); > + > + NewHmacVarInfo->StoreIndex =3D VAR_INDEX_INVALID; // Skip calculat= ing > offset > + NewHmacVarInfo->Flags.Auth =3D Global->Flags.Auth; > + Status =3D ContextIn->GetVariableInfo (NewHmacVarI= nfo); > + ASSERT_EFI_ERROR (Status); > + HmacValue =3D NewHmacVarInfo->Header.Data; > + > + // > + // Re-calculate HMAC for all valid variables > + // > + Context =3D HmacSha256New (); > + if (Context =3D=3D NULL) { > + ASSERT (Context !=3D NULL); > + return EFI_OUT_OF_RESOURCES; > + } > + > + Status =3D EFI_ABORTED; > + if (!HmacSha256SetKey ( > + Context, > + Global->MetaDataHmacKey, > + sizeof (Global->MetaDataHmacKey) > + )) > + { > + ASSERT (FALSE); > + goto Done; > + } > + > + // > + // HMAC (|| hash(Var1) || hash(Var2) || ... || hash(VarN)) > + // > + VarDig =3D VAR_DIG_PTR (Global->VariableDigests); > + while (VarDig !=3D NULL) { > + if (VarDig->Flags.Valid && VarDig->Flags.Protected) { > + HmacSha256Update (Context, VAR_DIG_VALUE (VarDig), VarDig- > >DigestSize); > + } > + > + VarDig =3D VAR_DIG_NEXT (VarDig); > + } > + > + // > + // HMAC (RpmcMonotonicCounter) > + // > + if (!HmacSha256Update (Context, &Counter, sizeof (Counter))) { > + ASSERT (FALSE); > + goto Done; > + } > + > + if (!HmacSha256Final (Context, HmacValue)) { > + ASSERT (FALSE); > + goto Done; > + } > + > + // > + // Update HMAC value in cache. > + // > + CopyMem (VAR_DIG_VALUE (HmacVarDig), HmacValue, HmacVarDig- > >DataSize); > + if ((HmacVarDig->Prev =3D=3D 0) && (HmacVarDig->Next =3D=3D 0)) { > + InsertVariableDigestNode (Global, HmacVarDig, NULL); > + } > + > + // > + // Just one MetaDataHmacVar is needed for normal operation. > + // > + Global->Unprotected[IndexHmacAdded] =3D VAR_DIG_ADR (HmacVarDig); > + Global->Unprotected[IndexHmacInDel] =3D VAR_INDEX_INVALID; > + > + Status =3D EFI_SUCCESS; > + > +Done: > + if (Context !=3D NULL) { > + HmacSha256Free (Context); > + } > + > + return Status; > +} > + > +/** > + > + Check if a given variable is unprotected variable specified in advance > + and return its index ID. > + > + @param[in] Global Pointer to global configuration data. > + @param[in] VarInfo Pointer to variable information data. > + > + @retval IndexHmacInDel Variable is MetaDataHmacVar in delete-transi= tion > state. > + @retval IndexHmacAdded Variable is MetaDataHmacVar in valid state. > + @retval IndexErrorFlag Variable is VarErrorLog. > + @retval Others Variable is not any known unprotected variab= les. > + > +**/ > +UNPROTECTED_VARIABLE_INDEX > +CheckKnownUnprotectedVariable ( > + IN PROTECTED_VARIABLE_GLOBAL *Global, > + IN PROTECTED_VARIABLE_INFO *VarInfo > + ) > +{ > + UNPROTECTED_VARIABLE_INDEX Index; > + > + if ((VarInfo =3D=3D NULL) || ( (VarInfo->StoreIndex =3D=3D VAR_INDEX_= INVALID) > + && ( (VarInfo->Header.VariableName =3D=3D NU= LL) > + || (VarInfo->Header.VendorGuid =3D=3D NULL= )))) > + { > + ASSERT (VarInfo !=3D NULL); > + ASSERT (VarInfo->StoreIndex !=3D VAR_INDEX_INVALID); > + ASSERT (VarInfo->Header.VariableName !=3D NULL); > + ASSERT (VarInfo->Header.VendorGuid !=3D NULL); > + return UnprotectedVarIndexMax; > + } > + > + for (Index =3D 0; Index < UnprotectedVarIndexMax; ++Index) { > + if ( (Global->Unprotected[Index] !=3D VAR_INDEX_INVALID) > + && (VarInfo->StoreIndex !=3D VAR_INDEX_INVALID)) > + { > + if (VarInfo->StoreIndex =3D=3D VAR_DIG_PTR (Global->Unprotected[In= dex])- > >StoreIndex) { > + break; > + } > + } else if (IS_VARIABLE ( > + &VarInfo->Header, > + mUnprotectedVariables[Index].VariableName, > + mUnprotectedVariables[Index].VendorGuid > + ) && (VarInfo->Header.State =3D=3D mUnprotectedVariable= s[Index].State)) > + { > + break; > + } > + } > + > + return Index; > +} > + > +/** > + > + Compare variable name and Guid > + > + @param[in] Name1 Name of first variable. > + @param[in] Name1Size Size of first variable. > + @param[in] Name2 Name of second variable. > + @param[in] Name2Size Size of second variable. > + @param[in] Guid1 Guid for first variable. > + @param[in] Guid2 Guid for second variable. > + > + @retval 0 First name is identical to Second name. > + @return others First name is not identical to Second name. > + > +**/ > +INTN > +CompareVariableNameAndGuid ( > + IN CONST CHAR16 *Name1, > + IN UINTN Name1Size, > + IN CONST CHAR16 *Name2, > + IN UINTN Name2Size, > + IN EFI_GUID *Guid1, > + IN EFI_GUID *Guid2 > + ) > +{ > + INTN Result; > + > + Result =3D StrnCmp ( > + Name1, > + Name2, > + MIN (Name1Size, Name2Size) / sizeof (CHAR16) > + ); > + if (Result =3D=3D 0) { > + if (Name1Size !=3D Name2Size) { > + // > + // Longer name is 'bigger' than shorter one. > + // > + Result =3D (INTN)Name1Size - (INTN)Name2Size; > + } else { > + // > + // The variable name is the same. Compare the GUID. > + // > + Result =3D CompareMem ((VOID *)Guid1, (VOID *)Guid2, sizeof (EFI_G= UID)); > + } > + } > + > + return Result; > +} > + > +/** > + > + Compare variable digest. > + > + @param[in] Variable1 Pointer to first variable digest. > + @param[in] Variable2 Pointer to second variable digest. > + > + @retval 0 Variables are identical. > + @return others Variables are not identical. > + > +**/ > +INTN > +CompareVariableDigestInfo ( > + IN VARIABLE_DIGEST *Variable1, > + IN VARIABLE_DIGEST *Variable2 > + ) > +{ > + return CompareVariableNameAndGuid ( > + VAR_DIG_NAME (Variable1), > + Variable1->NameSize, > + VAR_DIG_NAME (Variable2), > + Variable2->NameSize, > + &Variable1->VendorGuid, > + &Variable2->VendorGuid > + ); > +} > + > +/** > + > + Move a node backward in the order controlled by SortMethod. > + > + @param[in,out] Node Pointer to node to be moved. > + @param[in] SortMethod Method used to compare node in list. > + > +**/ > +VOID > +MoveNodeBackward ( > + IN OUT VARIABLE_DIGEST *Node, > + IN SORT_METHOD SortMethod > + ) > +{ > + VARIABLE_DIGEST *Curr; > + VARIABLE_DIGEST *Prev; > + INTN Result; > + > + Curr =3D Node; > + while (Curr !=3D NULL) { > + Prev =3D VAR_DIG_PREV (Curr); > + if (Prev =3D=3D NULL) { > + Result =3D -1; > + } else { > + Result =3D SortMethod (Prev, Node); > + } > + > + // > + // 'Result > 0' means the 'Prev' is 'bigger' than 'Node'. Continue t= o check > + // previous node til a node 'smaller' than 'Node' found. > + // > + if (Result > 0) { > + Curr =3D Prev; > + continue; > + } > + > + if (Curr !=3D Node) { > + // > + // Remove Node first > + // > + if (VAR_DIG_PREV (Node) !=3D NULL) { > + VAR_DIG_PREV (Node)->Next =3D Node->Next; > + } > + > + if (VAR_DIG_NEXT (Node) !=3D NULL) { > + VAR_DIG_NEXT (Node)->Prev =3D Node->Prev; > + } > + > + // > + // Insert Node before Curr. > + // > + Node->Prev =3D Curr->Prev; > + Node->Next =3D VAR_DIG_ADR (Curr); > + > + if (Curr->Prev !=3D 0) { > + VAR_DIG_PREV (Curr)->Next =3D VAR_DIG_ADR (Node); > + } > + > + Curr->Prev =3D VAR_DIG_ADR (Node); > + } > + > + // > + // If there're two identical variables in storage, one of them must = be > + // "in-delete-transition" state. Mark it as "deleted" anyway. > + // > + if (Result =3D=3D 0) { > + if (Curr->State =3D=3D (VAR_ADDED & VAR_IN_DELETED_TRANSITION)) { > + Curr->State &=3D VAR_DELETED; > + } > + > + if (Prev->State =3D=3D (VAR_ADDED & VAR_IN_DELETED_TRANSITION)) { > + Prev->State &=3D VAR_DELETED; > + } > + } > + > + break; > + } > +} > + > +/** > + > + Create variable digest node. > + > + @param[in] VariableName Name of variable. > + @param[in] VendorGuid Guid of variable. > + @param[in] NameSize Size of variable name. > + @param[in] DataSize Size of variable data. > + @param[in] AuthVar Authenticated variable flag. > + @param[in] Global Pointer to global configuration data. > + > + @retval Ptr Pointer to variable digest > + > +**/ > +VARIABLE_DIGEST * > +CreateVariableDigestNode ( > + IN CHAR16 *VariableName, > + IN EFI_GUID *VendorGuid, > + IN UINT16 NameSize, > + IN UINT32 DataSize, > + IN BOOLEAN AuthVar, > + IN PROTECTED_VARIABLE_GLOBAL *Global > + ) > +{ > + VARIABLE_DIGEST *VarDig; > + VOID *Buffer; > + UINTN VarSize; > + > + VarDig =3D (VARIABLE_DIGEST *)AllocateZeroPool ( > + sizeof (VARIABLE_DIGEST) + NameSize + > METADATA_HMAC_SIZE > + ); > + if ((VarDig =3D=3D NULL) || (Global =3D=3D NULL)) { > + ASSERT (VarDig !=3D NULL); > + ASSERT (Global !=3D NULL); > + return NULL; > + } > + > + VarDig->DataSize =3D DataSize; > + VarDig->NameSize =3D NameSize; > + VarDig->DigestSize =3D METADATA_HMAC_SIZE; > + VarDig->State =3D VAR_ADDED; > + VarDig->Attributes =3D VARIABLE_ATTRIBUTE_NV_BS_RT; > + VarDig->Flags.Auth =3D AuthVar; > + VarDig->Flags.Valid =3D TRUE; > + VarDig->Flags.Freeable =3D TRUE; > + VarDig->Flags.Protected =3D PcdGetBool (PcdProtectedVariableIntegrity)= ; > + VarDig->Flags.Encrypted =3D PcdGetBool (PcdProtectedVariableConfidenti= ality); > + VarDig->StoreIndex =3D VAR_INDEX_INVALID; > + VarDig->CacheIndex =3D VAR_INDEX_INVALID; > + > + if (Global->Flags.CacheReady =3D=3D TRUE) { > + VarSize =3D VARIABLE_HEADER_SIZE (VarDig->Flags.Auth); > + VarSize +=3D VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize); > + VarSize +=3D VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize); > + VarSize =3D HEADER_ALIGN (VarSize); > + > + Buffer =3D AllocateZeroPool (VarSize); > + if (Buffer !=3D NULL) { > + VarDig->CacheIndex =3D (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer; > + } > + } > + > + CopyMem (VAR_DIG_NAME (VarDig), VariableName, NameSize); > + CopyMem (VAR_DIG_GUID (VarDig), VendorGuid, sizeof (EFI_GUID)); > + > + return VarDig; > +} > + > +/** > + > + Remove variable digest node. > + > + @param[in,out] Global Pointer to global configuration data. > + @param[in,out] VarDig Pointer to variable digest value. > + @param[in] FreeResource Flag to indicate whether to free resourc= e. > + > +**/ > +VOID > +RemoveVariableDigestNode ( > + IN OUT PROTECTED_VARIABLE_GLOBAL *Global, > + IN OUT VARIABLE_DIGEST *VarDig, > + IN BOOLEAN FreeResource > + ) > +{ > + VARIABLE_DIGEST *Prev; > + VARIABLE_DIGEST *Next; > + > + Prev =3D VAR_DIG_PREV (VarDig); > + Next =3D VAR_DIG_NEXT (VarDig); > + > + if (Global->VariableDigests =3D=3D VAR_DIG_ADR (VarDig)) { > + Global->VariableDigests =3D VAR_DIG_ADR (Next); > + } > + > + if (Prev !=3D NULL) { > + Prev->Next =3D VAR_DIG_ADR (Next); > + } > + > + if (Next !=3D NULL) { > + Next->Prev =3D VAR_DIG_ADR (Prev); > + } > + > + VarDig->Prev =3D 0; > + VarDig->Next =3D 0; > + VarDig->Flags.Valid =3D FALSE; > + > + if (FreeResource && VarDig->Flags.Freeable) { > + if ((VarDig->CacheIndex !=3D 0) && (VarDig->CacheIndex !=3D > VAR_INDEX_INVALID)) { > + VarDig->CacheIndex =3D VAR_INDEX_INVALID; > + } > + } > +} > + > +/** > + > + Insert variable digest node. > + > + @param[in,out] Global Pointer to global configuration data. > + @param[in] VarDig Pointer to variable digest value. > + @param[in] SortMethod Method for sorting. > + > +**/ > +VOID > +InsertVariableDigestNode ( > + IN OUT PROTECTED_VARIABLE_GLOBAL *Global, > + IN VARIABLE_DIGEST *VarDig, > + IN SORT_METHOD SortMethod > + ) > +{ > + VARIABLE_DIGEST *Curr; > + VARIABLE_DIGEST *Prev; > + BOOLEAN DoReplace; > + INTN Result; > + > + if (SortMethod =3D=3D NULL) { > + SortMethod =3D CompareVariableDigestInfo; > + } > + > + DoReplace =3D FALSE; > + Curr =3D VAR_DIG_PTR (Global->VariableDigests); > + if (Curr =3D=3D NULL) { > + // > + // First one. > + // > + VarDig->Prev =3D 0; > + VarDig->Next =3D 0; > + Global->VariableDigests =3D VAR_DIG_ADR (VarDig); > + return; > + } > + > + while (Curr !=3D NULL && Curr !=3D VarDig) { > + Result =3D SortMethod (VarDig, Curr); > + > + if (Result <=3D 0) { > + ASSERT (VarDig->StoreIndex !=3D Curr->StoreIndex); > + > + // > + // The same variable already in list? > + // > + if (Result =3D=3D 0) { > + // > + // Keep only the same new one, unless states are different. In s= uch > + // situation, the one with no VAR_ADDED will be deleted. > + // > + if (VarDig->State >=3D Curr->State) { > + DoReplace =3D TRUE; > + Curr->Flags.Valid =3D FALSE; // to-be-deleted > + } else { > + DoReplace =3D FALSE; > + VarDig->Flags.Valid =3D FALSE; // to-be-deleted > + } > + } > + > + // > + // Put VarDig before Curr > + // > + VarDig->Next =3D VAR_DIG_ADR (Curr); > + VarDig->Prev =3D Curr->Prev; > + > + if (VAR_DIG_PREV (Curr) !=3D NULL) { > + VAR_DIG_PREV (Curr)->Next =3D VAR_DIG_ADR (VarDig); > + } > + > + Curr->Prev =3D VAR_DIG_ADR (VarDig); > + > + if (DoReplace) { > + RemoveVariableDigestNode (Global, Curr, TRUE); > + } > + > + break; > + } > + > + Prev =3D Curr; > + Curr =3D VAR_DIG_NEXT (Curr); > + if (Curr =3D=3D NULL) { > + Prev->Next =3D VAR_DIG_ADR (VarDig); > + > + VarDig->Prev =3D VAR_DIG_ADR (Prev); > + VarDig->Next =3D 0; > + } > + } > + > + // > + // Update the head node if necessary. > + // > + if (VAR_DIG_PTR (VarDig->Prev) =3D=3D NULL) { > + Global->VariableDigests =3D VAR_DIG_ADR (VarDig); > + } > +} > + > +/** > + > + Find the specified variable digest > + > + @param[in] Global Pointer to global configuration data. > + @param[in] VarInfo Pointer to variable data. > + @param[in] FindNext Flag to continue looking for variable. > + > +**/ > +VARIABLE_DIGEST * > +FindVariableInternal ( > + IN PROTECTED_VARIABLE_GLOBAL *Global, > + IN PROTECTED_VARIABLE_INFO *VarInfo, > + IN BOOLEAN FindNext > + ) > +{ > + VARIABLE_DIGEST *VarDig; > + VARIABLE_DIGEST *Found; > + VARIABLE_DIGEST *FirstStoreIndexVar; > + BOOLEAN ByIndex; > + INTN FwdOrBwd; > + > + // > + // If VarInfo->StoreIndex is valid, use it to find the variable. Other= wise, > + // use the variable name and guid instead, if given. If no clue at all= , return > + // the variable with lowest StoreIndex. > + // > + if ( (VarInfo->StoreIndex !=3D VAR_INDEX_INVALID) > + || (VarInfo->Header.VariableName =3D=3D NULL) > + || (VarInfo->Header.VendorGuid =3D=3D NULL)) > + { > + ByIndex =3D TRUE; > + } else { > + ByIndex =3D FALSE; > + } > + > + Found =3D NULL; > + VarDig =3D VAR_DIG_PTR (Global->VariableDigests); > + FirstStoreIndexVar =3D VarDig; > + FwdOrBwd =3D 1; > + > + // > + // Discover variable with first/smallest store index > + // > + while (VarDig !=3D NULL) { > + if (VarDig->StoreIndex < FirstStoreIndexVar->StoreIndex) { > + FirstStoreIndexVar =3D VAR_DIG_PTR (VarDig); > + } > + > + VarDig =3D VAR_DIG_NEXT (VarDig); > + } > + > + // > + // Input variable is NULL than return first variable > + // with smallest store index from the variable digest list. > + // > + if (((VarInfo->Header.VariableName =3D=3D NULL) || > + (VarInfo->Header.VendorGuid =3D=3D NULL)) && > + (ByIndex =3D=3D FALSE)) > + { > + return FirstStoreIndexVar; > + } > + > + // > + // Start with first entry > + // > + VarDig =3D VAR_DIG_PTR (Global->VariableDigests); > + while (VarDig !=3D NULL) { > + if (ByIndex) { > + if (FindNext) { > + if (VarDig->StoreIndex =3D=3D VarInfo->StoreIndex) { > + Found =3D VarDig =3D VAR_DIG_NEXT (VarDig); > + break; > + } > + } else if (VarDig->StoreIndex =3D=3D VarInfo->StoreIndex) { > + Found =3D VarDig; > + break; > + } > + } else { > + // > + // Match given variable name and vendor guid. > + // > + if (IS_VARIABLE (&VarInfo->Header, VAR_DIG_NAME (VarDig), > VAR_DIG_GUID (VarDig))) { > + Found =3D (FindNext) ? VAR_DIG_NEXT (VarDig) : VarDig; > + break; > + } > + } > + > + VarDig =3D (FwdOrBwd > 0) ? VAR_DIG_NEXT (VarDig) : VAR_DIG_PREV > (VarDig); > + if (VarDig =3D=3D NULL) { > + } > + } > + > + return Found; > +} > + > +/** > + > + Synchronize the RPMC counters > + > + @param[in] Global Pointer to global configuration data. > + @param[in] VarInfo Pointer to variable data. > + @param[in] FindNext Flag to continue looking for variable. > + > + @retval EFI_SUCCESS Successfully sync RPMC counters. > + @return others Failed to sync RPMC counters. > + > +**/ > +EFI_STATUS > +SyncRpmcCounter ( > + VOID > + ) > +{ > + UINT32 Counter1; > + UINT32 Counter2; > + EFI_STATUS Status; > + > + // > + // Sync RPMC1 & RPMC2. > + // > + Status =3D RequestMonotonicCounter (RPMC_COUNTER_1, &Counter1); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + Status =3D RequestMonotonicCounter (RPMC_COUNTER_2, &Counter2); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + while (Counter1 < Counter2) { > + Status =3D IncrementMonotonicCounter (RPMC_COUNTER_1); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + ++Counter1; > + } > + > + while (Counter2 < Counter1) { > + Status =3D IncrementMonotonicCounter (RPMC_COUNTER_2); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + ++Counter2; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + > + An alternative version of ProtectedVariableLibGetData to get plain dat= a from > + given variable, if encrypted. > + > + @param[in] Global Pointer to global configuration data= . > + @param[in,out] VarInfo Pointer to structure containing vari= able > + information. VarInfo->Header.Data mu= st point > + to the original variable data. > + > + @retval EFI_SUCCESS Found the specified variable. > + @retval EFI_INVALID_PARAMETER VarInfo is NULL or both VarInfo->Buf= fer > and > + VarInfo->Offset are invalid. > + @retval EFI_NOT_FOUND The specified variable could not be = found. > + > +**/ > +STATIC > +EFI_STATUS > +ProtectedVariableLibGetDataInternal ( > + IN PROTECTED_VARIABLE_GLOBAL *Global, > + IN OUT PROTECTED_VARIABLE_INFO *VarInfo > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_CONTEXT_IN *ContextIn; > + VOID *Buffer; > + UINTN BufferSize; > + > + if ((Global =3D=3D NULL) || (VarInfo =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + ContextIn =3D GET_CNTX (Global); > + > + // > + // Check if the data has been decrypted or not. > + // > + BufferSize =3D VarInfo->PlainDataSize; > + VarInfo->CipherData =3D NULL; > + VarInfo->CipherDataSize =3D 0; > + VarInfo->PlainData =3D NULL; > + VarInfo->PlainDataSize =3D 0; > + Status =3D GetCipherDataInfo (VarInfo); > + > + if ((Status =3D=3D EFI_UNSUPPORTED) || (Status =3D=3D EFI_NOT_FOUND)) = { > + VarInfo->Flags.DecryptInPlace =3D TRUE; > + VarInfo->PlainDataSize =3D (UINT32)VarInfo->Header.DataSize; > + VarInfo->PlainData =3D VarInfo->Header.Data; > + VarInfo->CipherDataType =3D 0; > + VarInfo->CipherHeaderSize =3D 0; > + Status =3D EFI_SUCCESS; > + } else if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + // > + // Don't do decryption if the caller provided buffer is too small > + // Simply return the real Plain Data Size via VarInfo->PlainDataSize > + // > + if (BufferSize < VarInfo->PlainDataSize) { > + return EFI_BUFFER_TOO_SMALL; > + } > + > + // > + // If the variable data is cipher data, decrypt it inplace if possible= . > + // > + if ((VarInfo->PlainData =3D=3D NULL) && (VarInfo->CipherData !=3D NULL= )) { > + VarInfo->Key =3D Global->RootKey; > + VarInfo->KeySize =3D sizeof (Global->RootKey); > + > + switch (ContextIn->VariableServiceUser) { > + case FromPeiModule: > + VarInfo->Flags.DecryptInPlace =3D FALSE; > + // > + // In PEI VariableCache holds Cipher header + Cipher data > + // Do not override Cipher header data during decrypt operation > + // > + VarInfo->PlainData =3D GET_BUFR (Global->VariableCache + VarInfo= - > >CipherHeaderSize); > + > + Status =3D DecryptVariable (VarInfo); > + if (Status =3D=3D EFI_UNSUPPORTED) { > + VarInfo->PlainData =3D VarInfo->Header.Data; > + VarInfo->PlainDataSize =3D (UINT32)VarInfo->Header.DataSize= ; > + VarInfo->CipherDataType =3D 0; > + VarInfo->CipherHeaderSize =3D 0; > + > + Status =3D EFI_SUCCESS; > + } > + > + break; > + > + case FromSmmModule: > + VarInfo->Flags.DecryptInPlace =3D FALSE; > + VarInfo->PlainData =3D GET_BUFR (Global->VariableCach= e); > + > + Status =3D DecryptVariable (VarInfo); > + if (Status =3D=3D EFI_UNSUPPORTED) { > + VarInfo->PlainData =3D VarInfo->Header.Data; > + VarInfo->PlainDataSize =3D (UINT32)VarInfo->Header.DataSize= ; > + VarInfo->CipherDataType =3D 0; > + VarInfo->CipherHeaderSize =3D 0; > + > + Status =3D EFI_SUCCESS; > + } > + > + break; > + > + case FromBootServiceModule: > + case FromRuntimeModule: > + // > + // The SMM passes back only decrypted data. We re-use the origin= al cipher > + // data buffer to keep the plain data along with the cipher head= er. > + // > + VarInfo->Flags.DecryptInPlace =3D TRUE; > + Buffer =3D (VOID *)((UINTN)VarInfo->Ciphe= rData + VarInfo- > >CipherHeaderSize); > + BufferSize =3D VarInfo->PlainDataSize; > + Status =3D ContextIn->FindVariableSmm ( > + VarInfo->Header.Var= iableName, > + VarInfo->Header.Ven= dorGuid, > + &VarInfo->Header.At= tributes, > + &BufferSize, > + Buffer > + ); > + if (!EFI_ERROR (Status)) { > + // > + // Flag the payload as plain data to avoid re-decrypting. > + // > + VarInfo->CipherDataType =3D ENC_TYPE_NULL; > + VarInfo->PlainDataSize =3D (UINT32)BufferSize; > + VarInfo->PlainData =3D Buffer; > + > + Status =3D SetCipherDataInfo (VarInfo); > + if (Status =3D=3D EFI_UNSUPPORTED) { > + Status =3D EFI_SUCCESS; > + } > + } > + > + break; > + > + default: > + Status =3D EFI_UNSUPPORTED; > + break; > + } > + > + VarInfo->CipherData =3D NULL; > + VarInfo->CipherDataSize =3D 0; > + } > + > + return Status; > +} > + > +/** > + > + An alternative version of ProtectedVariableLibGetData to get plain dat= a, if > + encrypted, from given variable, for different use cases. > + > + @param[in,out] VarInfo Pointer to structure containing variab= le > information. > + > + @retval EFI_SUCCESS Found the specified variable. > + @retval EFI_INVALID_PARAMETER VarInfo is NULL or both VarInfo->Buf= fer > and > + VarInfo->Offset are invalid. > + @retval EFI_NOT_FOUND The specified variable could not be = found. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibGetByInfo ( > + IN OUT PROTECTED_VARIABLE_INFO *VarInfo > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_GLOBAL *Global; > + VOID **Buffer; > + UINT32 BufferSize; > + > + Status =3D GetProtectedVariableGlobal (&Global); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + // > + // Save the output data buffer because below call > + // call will use this struct field internally. > + // > + Buffer =3D VarInfo->PlainData; > + BufferSize =3D VarInfo->PlainDataSize; > + > + Status =3D ProtectedVariableLibGetDataInternal (Global, VarInfo); > + if (EFI_ERROR (Status) || ((BufferSize) < VarInfo->PlainDataSize)) { > + // > + // Return with caller provided buffer with zero DataSize > + // > + VarInfo->PlainData =3D Buffer; > + return Status; > + } > + > + // > + // Copy Plain data to ouput data buffer > + // > + CopyMem (Buffer, VarInfo->PlainData, VarInfo->PlainDataSize); > + VarInfo->PlainData =3D Buffer; > + > + return Status; > +} > + > +/** > + > + Retrieve plain data, if encrypted, of given variable. > + > + If variable encryption is employed, this function will initiate a SMM = request > + to get the plain data. Due to security consideration, the decryption c= an only > + be done in SMM environment. > + > + @param[in] Variable Pointer to header of a Variable. > + @param[in,out] Data Pointer to plain data of the given = variable. > + @param[in,out] DataSize Size of data returned or data buffe= r needed. > + @param[in] AuthFlag Auth-variable indicator. > + > + @retval EFI_SUCCESS Found the specified variable. > + @retval EFI_INVALID_PARAMETER Invalid parameter. > + @retval EFI_NOT_FOUND The specified variable could not be= found. > + @retval EFI_BUFFER_TOO_SMALL If *DataSize is smaller than needed= . > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibGetByBuffer ( > + IN VARIABLE_HEADER *Variable, > + IN OUT VOID *Data, > + IN OUT UINT32 *DataSize, > + IN BOOLEAN AuthFlag > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_INFO VarInfo; > + PROTECTED_VARIABLE_GLOBAL *Global; > + AUTHENTICATED_VARIABLE_HEADER *AuthVariable; > + VOID *Buffer; > + > + if ((Variable =3D=3D NULL) || (DataSize =3D=3D NULL)) { > + ASSERT (Variable !=3D NULL); > + ASSERT (DataSize !=3D NULL); > + return EFI_INVALID_PARAMETER; > + } > + > + Status =3D GetProtectedVariableGlobal (&Global); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + ZeroMem (&VarInfo, sizeof (VarInfo)); > + > + VarInfo.Buffer =3D Variable; > + VarInfo.Flags.Auth =3D AuthFlag; > + VarInfo.PlainDataSize =3D *DataSize; > + > + if (VarInfo.Flags.Auth =3D=3D TRUE) { > + AuthVariable =3D (AUTHENTICATED_VARIABLE_HEADER *)Variable; > + > + VarInfo.Header.VariableName =3D (CHAR16 *)((UINTN)Variable + sizeof > (AUTHENTICATED_VARIABLE_HEADER)); > + VarInfo.Header.NameSize =3D AuthVariable->NameSize; > + VarInfo.Header.VendorGuid =3D &AuthVariable->VendorGuid; > + VarInfo.Header.Attributes =3D AuthVariable->Attributes; > + VarInfo.Header.DataSize =3D AuthVariable->DataSize; > + } else { > + VarInfo.Header.VariableName =3D (CHAR16 *)((UINTN)Variable + sizeof > (VARIABLE_HEADER)); > + VarInfo.Header.NameSize =3D Variable->NameSize; > + VarInfo.Header.VendorGuid =3D &Variable->VendorGuid; > + VarInfo.Header.Attributes =3D Variable->Attributes; > + VarInfo.Header.DataSize =3D Variable->DataSize; > + } > + > + Buffer =3D VARIABLE_NAME (VarInfo.Buffer, VarInfo.Flags.A= uth); > + Buffer =3D GET_BUFR (GET_ADRS (Buffer) + VarInfo.Header.N= ameSize); > + Buffer =3D GET_BUFR (GET_ADRS (Buffer) + GET_PAD_SIZE > (VarInfo.Header.NameSize)); > + VarInfo.Header.Data =3D Buffer; > + > + Status =3D ProtectedVariableLibGetDataInternal (Global, &VarInfo); > + *DataSize =3D VarInfo.PlainDataSize; > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + CopyMem (Data, VarInfo.PlainData, VarInfo.PlainDataSize); > + > + return Status; > +} > + > +/** > + This service retrieves a variable's value using its name and GUID. > + > + Read the specified variable from the UEFI variable store. If the Data > + buffer is too small to hold the contents of the variable, the error > + EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required b= uffer > + size to obtain the data. > + > + @param VariableName A pointer to a null-terminated string th= at is the > variable's name. > + @param VariableGuid A pointer to an EFI_GUID that is the var= iable's > GUID. The combination of > + VariableGuid and VariableName must be un= ique. > + @param Attributes If non-NULL, on return, points to the va= riable's > attributes. > + @param DataSize On entry, points to the size in bytes of= the Data > buffer. > + On return, points to the size of the dat= a returned in Data. > + @param Data Points to the buffer which will hold the= returned > variable value. > + May be NULL with a zero DataSize in orde= r to determine the > size of the buffer needed. > + > + @retval EFI_SUCCESS The variable was read successfully. > + @retval EFI_NOT_FOUND The variable was be found. > + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result= ing > data. > + DataSize is updated with the size requir= ed for > + the specified variable. > + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or > Data is NULL. > + @retval EFI_DEVICE_ERROR The variable could not be retrieved beca= use of > a device error. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibGetByName ( > + IN CONST CHAR16 *VariableName, > + IN CONST EFI_GUID *VariableGuid, > + OUT UINT32 *Attributes, > + IN OUT UINTN *DataSize, > + OUT VOID *Data OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_CONTEXT_IN *ContextIn; > + PROTECTED_VARIABLE_GLOBAL *Global; > + VARIABLE_DIGEST *VarDig; > + PROTECTED_VARIABLE_INFO VarInfo; > + EFI_TIME TimeStamp; > + VOID *DataBuffer; > + > + if ((VariableName =3D=3D NULL) || (VariableGuid =3D=3D NULL) || (DataS= ize =3D=3D NULL)) { > + ASSERT (VariableName !=3D NULL); > + ASSERT (VariableGuid !=3D NULL); > + ASSERT (DataSize !=3D NULL); > + return EFI_INVALID_PARAMETER; > + } > + > + Status =3D GetProtectedVariableGlobal (&Global); > + > + if (EFI_ERROR (Status)) { > + return EFI_UNSUPPORTED; > + } > + > + ContextIn =3D GET_CNTX (Global); > + > + ZeroMem (&VarInfo, sizeof (VarInfo)); > + VarInfo.StoreIndex =3D VAR_INDEX_INVALID; > + VarInfo.Header.VariableName =3D (CHAR16 *)VariableName; > + VarInfo.Header.NameSize =3D StrSize (VariableName); > + VarInfo.Header.VendorGuid =3D (EFI_GUID *)VariableGuid; > + > + VarDig =3D FindVariableInternal (Global, &VarInfo, FALSE); > + if (VarDig =3D=3D NULL) { > + return EFI_NOT_FOUND; > + } > + > + if (Attributes !=3D NULL) { > + *Attributes =3D VarDig->Attributes; > + } > + > + if ((Data =3D=3D NULL) || (*DataSize < VarDig->PlainDataSize)) { > + *DataSize =3D VarDig->PlainDataSize; > + return EFI_BUFFER_TOO_SMALL; > + } > + > + VarInfo.Flags.Auth =3D VarDig->Flags.Auth; > + VarInfo.Flags.Protected =3D VarDig->Flags.Protected; > + > + // > + // Verify digest before copy the data back, if the variable is not in = cache. > + // > + if (VarDig->CacheIndex !=3D VAR_INDEX_INVALID) { > + VarInfo.Header.VariableName =3D NULL; > + VarInfo.Header.VendorGuid =3D NULL; > + VarInfo.Buffer =3D GET_BUFR (VarDig->CacheIndex); > + > + Status =3D ContextIn->GetVariableInfo (&VarInfo); > + ASSERT_EFI_ERROR (Status); > + } else { > + // > + // A buffer for at least one variable data (<=3DPcdMax(Auth)Variable= Size) > + // must be reserved in advance. > + // > + ASSERT ( > + Global->VariableCache !=3D 0 > + && Global->VariableCacheSize >=3D VarDig->DataSize > + ); > + DataBuffer =3D GET_BUFR (Global->VariableCache); > + // > + // Note name and GUID are already there. > + // > + VarInfo.StoreIndex =3D VarDig->StoreIndex; > + > + VarInfo.Header.VariableName =3D NULL; // Prevent name from being ret= rieved > again. > + VarInfo.Header.NameSize =3D 0; > + VarInfo.Header.VendorGuid =3D NULL; // Prevent guid from being ret= rieved > again. > + VarInfo.Header.TimeStamp =3D &TimeStamp; > + VarInfo.Header.Data =3D DataBuffer; > + VarInfo.Header.DataSize =3D VarDig->DataSize; > + > + // > + // Get detailed information about the variable. > + // > + Status =3D ContextIn->GetVariableInfo (&VarInfo); > + ASSERT_EFI_ERROR (Status); > + > + // > + // The variable must be validated its digest value to avoid TOCTOU, = if it's > + // not been cached yet. > + // > + VarInfo.Header.VariableName =3D VAR_DIG_NAME (VarDig); > + VarInfo.Header.NameSize =3D VarDig->NameSize; > + VarInfo.Header.VendorGuid =3D &VarDig->VendorGuid; > + Status =3D VerifyVariableDigest (Global, &VarIn= fo, VarDig); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + } > + > + VarInfo.PlainDataSize =3D (UINT32)*DataSize; > + > + // > + // Decrypt the data, if necessary. > + // > + Status =3D ProtectedVariableLibGetDataInternal (Global, &VarInfo); > + *DataSize =3D VarInfo.PlainDataSize; > + if (EFI_ERROR (Status)) { > + DEBUG (( > + DEBUG_INFO, > + "%a: %d Exit(). VariableName =3D %s, VariableGuid =3D 0x%g, DataSi= ze =3D 0x%X, > Data Buffer =3D 0x%lX, Status =3D %r\n", > + __FUNCTION__, > + __LINE__, > + VariableName, > + VariableGuid, > + *DataSize, > + Data, > + Status > + )); > + return Status; > + } > + > + CopyMem (Data, VarInfo.PlainData, VarInfo.PlainDataSize); > + > + return Status; > +} > + > +/** > + > + This function is used to enumerate the variables managed by current > + ProtectedVariableLib. > + > + If the VarInfo->StoreIndex is invalid (VAR_INDEX_INVALID), the first v= ariable > + with the smallest StoreIndex will be returned. Otherwise, the variable= with > + StoreIndex just after than the VarInfo->StoreIndex will be returned. > + > + @param[in,out] VarInfo Pointer to structure containing variab= le > information. > + > + @retval EFI_SUCCESS Found the specified variable. > + @retval EFI_INVALID_PARAMETER VarInfo is NULL. > + @retval EFI_NOT_FOUND The specified variable could not be = found. > + > +**/ > +STATIC > +EFI_STATUS > +GetNextVariableInternal ( > + IN OUT PROTECTED_VARIABLE_INFO *VarInfo > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_GLOBAL *Global; > + VARIABLE_DIGEST *Found; > + > + if (VarInfo =3D=3D NULL) { > + ASSERT (VarInfo !=3D NULL); > + return EFI_INVALID_PARAMETER; > + } > + > + Status =3D GetProtectedVariableGlobal (&Global); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + Found =3D FindVariableInternal (Global, VarInfo, TRUE); > + if (Found =3D=3D NULL) { > + return EFI_NOT_FOUND; > + } > + > + // > + // Return all cached data. > + // > + VarInfo->Header.VariableName =3D VAR_DIG_NAME (Found); > + VarInfo->Header.VendorGuid =3D VAR_DIG_GUID (Found); > + VarInfo->Header.NameSize =3D Found->NameSize; > + VarInfo->Header.DataSize =3D Found->DataSize; > + VarInfo->Header.Attributes =3D Found->Attributes; > + > + VarInfo->PlainDataSize =3D Found->PlainDataSize; > + VarInfo->StoreIndex =3D Found->StoreIndex; > + if (Found->CacheIndex !=3D VAR_INDEX_INVALID) { > + VarInfo->Buffer =3D GET_BUFR (Found->CacheIndex); > + } > + > + VarInfo->Flags.Auth =3D Found->Flags.Auth; > + > + return EFI_SUCCESS; > +} > + > +/** > + > + Find the request variable. > + > + @param[in, out] VarInfo Pointer to variable data. > + > + @retval EFI_SUCCESS The variable was read successfully. > + @retval EFI_NOT_FOUND The variable could not be found. > + @retval EFI_INVALID_PARAMETER Variable info is NULL. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibFind ( > + IN OUT PROTECTED_VARIABLE_INFO *VarInfo > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_GLOBAL *Global; > + VARIABLE_DIGEST *Found; > + > + if (VarInfo =3D=3D NULL) { > + ASSERT (VarInfo !=3D NULL); > + return EFI_INVALID_PARAMETER; > + } > + > + Status =3D GetProtectedVariableGlobal (&Global); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + Found =3D FindVariableInternal (Global, VarInfo, FALSE); > + if (Found =3D=3D NULL) { > + return EFI_NOT_FOUND; > + } > + > + // > + // Return all cached data. > + // > + VarInfo->Header.VariableName =3D VAR_DIG_NAME (Found); > + VarInfo->Header.VendorGuid =3D VAR_DIG_GUID (Found); > + VarInfo->Header.NameSize =3D Found->NameSize; > + VarInfo->Header.DataSize =3D Found->DataSize; > + VarInfo->Header.Attributes =3D Found->Attributes; > + > + VarInfo->PlainDataSize =3D Found->PlainDataSize; > + VarInfo->StoreIndex =3D Found->StoreIndex; > + if (Found->CacheIndex !=3D VAR_INDEX_INVALID) { > + VarInfo->Buffer =3D GET_BUFR (Found->CacheIndex); > + } > + > + VarInfo->Flags.Auth =3D Found->Flags.Auth; > + > + return EFI_SUCCESS; > +} > + > +/** > + Return the next variable name and GUID. > + > + This function is called multiple times to retrieve the VariableName > + and VariableGuid of all variables currently available in the system. > + On each call, the previous results are passed into the interface, > + and, on return, the interface returns the data for the next > + interface. When the entire variable list has been returned, > + EFI_NOT_FOUND is returned. > + > + @param VariableNameSize On entry, points to the size of the buffer p= ointed > to by VariableName. > + On return, the size of the variable name buf= fer. > + @param VariableName On entry, a pointer to a null-terminated str= ing that > is the variable's name. > + On return, points to the next variable's nul= l-terminated name > string. > + @param VariableGuid On entry, a pointer to an EFI_GUID that is t= he > variable's GUID. > + On return, a pointer to the next variable's = GUID. > + > + @retval EFI_SUCCESS The variable was read successfully. > + @retval EFI_NOT_FOUND The variable could not be found. > + @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for th= e > resulting > + data. VariableNameSize is updated with t= he size > + required for the specified variable. > + @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or > + VariableNameSize is NULL. > + @retval EFI_DEVICE_ERROR The variable could not be retrieved beca= use of > a device error. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibFindNext ( > + IN OUT UINTN *VariableNameSize, > + IN OUT CHAR16 *VariableName, > + IN OUT EFI_GUID *VariableGuid > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_INFO VarInfo; > + PROTECTED_VARIABLE_GLOBAL *Global; > + VARIABLE_DIGEST *VarDig; > + UINTN Size; > + > + if ((VariableNameSize =3D=3D NULL) || (VariableName =3D=3D NULL) || (V= ariableGuid > =3D=3D NULL)) { > + ASSERT (VariableNameSize !=3D NULL); > + ASSERT (VariableName !=3D NULL); > + ASSERT (VariableGuid !=3D NULL); > + return EFI_INVALID_PARAMETER; > + } > + > + Status =3D GetProtectedVariableGlobal (&Global); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + SetMem (&VarInfo, sizeof (VarInfo), 0); > + Size =3D StrSize (VariableName); > + > + if (Size <=3D 2) { > + VarDig =3D VAR_DIG_PTR (Global->VariableDigests); > + } else { > + VarInfo.Header.VariableName =3D VariableName; > + VarInfo.Header.NameSize =3D Size; > + VarInfo.Header.VendorGuid =3D VariableGuid; > + > + VarInfo.StoreIndex =3D VAR_INDEX_INVALID; > + > + VarDig =3D FindVariableInternal (Global, &VarInfo, TRUE); > + } > + > + if (VarDig =3D=3D NULL) { > + return EFI_NOT_FOUND; > + } > + > + if (VarDig->NameSize > *VariableNameSize) { > + return EFI_BUFFER_TOO_SMALL; > + } > + > + CopyMem (VariableName, VAR_DIG_NAME (VarDig), VarDig->NameSize); > + CopyGuid (VariableGuid, &VarDig->VendorGuid); > + *VariableNameSize =3D VarInfo.Header.NameSize; > + > + return EFI_SUCCESS; > +} > + > +/** > + > + Return the next variable name and GUID. > + > + @param[in, out] VarInfo Pointer to variable data. > + > + @retval EFI_SUCCESS The variable was read successfully. > + @retval EFI_INVALID_PARAMETER VarInfo is NULL. > + @retval EFI_NOT_FOUND The specified variable could not be fo= und. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibFindNextEx ( > + IN OUT PROTECTED_VARIABLE_INFO *VarInfo > + ) > +{ > + return GetNextVariableInternal (VarInfo); > +} > + > +/** > + > + Return the max count of a variable. > + > + @return max count of a variable. > + > +**/ > +UINTN > +ProtectedVariableLibGetMaxVariablesCount ( > + VOID > + ) > +{ > + PROTECTED_VARIABLE_GLOBAL *Global; > + PROTECTED_VARIABLE_INFO VarInfo; > + VARIABLE_DIGEST *VarDig; > + EFI_STATUS Status; > + UINTN Count; > + > + Status =3D GetProtectedVariableGlobal (&Global); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return 0; > + } > + > + Count =3D 0; > + ZeroMem (&VarInfo, sizeof (VarInfo)); > + > + // > + // Start with first entry > + // > + VarDig =3D VAR_DIG_PTR (Global->VariableDigests); > + VarInfo.Header.VariableName =3D VAR_DIG_NAME (VarDig); > + VarInfo.Header.VendorGuid =3D VAR_DIG_GUID (VarDig); > + VarInfo.StoreIndex =3D VarDig->StoreIndex; > + > + do { > + VarInfo.Buffer =3D NULL; > + Status =3D ProtectedVariableLibFindNextEx (&VarInfo); > + if (EFI_ERROR (Status)) { > + return Count; > + } > + > + Count++; > + } while (TRUE); > +} > + > +/** > + The function is called by PerformQuickSort to sort. > + > + @param[in] Left The pointer to first buffer. > + @param[in] Right The pointer to second buffer. > + > + @retval 0 Buffer1 equal to Buffer2. > + @return < 0 Buffer1 is less than Buffer2. > + @return > 0 Buffer1 is greater than Buffer2. > + > +**/ > +INTN > +EFIAPI > +CompareStoreIndex ( > + IN CONST VOID *Left, > + IN CONST VOID *Right > + ) > +{ > + EFI_PHYSICAL_ADDRESS StoreIndex1; > + EFI_PHYSICAL_ADDRESS StoreIndex2; > + > + StoreIndex1 =3D (*(EFI_PHYSICAL_ADDRESS *)Left); > + StoreIndex2 =3D (*(EFI_PHYSICAL_ADDRESS *)Right); > + > + if (StoreIndex1 =3D=3D StoreIndex2) { > + return (0); > + } > + > + if (StoreIndex1 < StoreIndex2) { > + return (-1); > + } > + > + return (1); > +} > + > +/** > + Refresh variable information changed by variable service. > + > + @param Buffer Pointer to a pointer of buffer. > + @param NumElements Pointer to number of elements in list. > + > + > + @return EFI_SUCCESS Successfully retrieved sorted list. > + @return others Unsuccessful. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibGetSortedList ( > + IN OUT EFI_PHYSICAL_ADDRESS **Buffer, > + IN OUT UINTN *NumElements > + ) > +{ > + EFI_STATUS Status; > + UINTN Count; > + UINTN StoreIndexTableSize; > + EFI_PHYSICAL_ADDRESS *StoreIndexTable; > + PROTECTED_VARIABLE_INFO VarInfo; > + PROTECTED_VARIABLE_GLOBAL *Global; > + VARIABLE_DIGEST *VarDig; > + > + Status =3D GetProtectedVariableGlobal (&Global); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + Count =3D 0; > + ZeroMem (&VarInfo, sizeof (VarInfo)); > + StoreIndexTableSize =3D ProtectedVariableLibGetMaxVariablesCount (); > + StoreIndexTable =3D AllocateZeroPool (sizeof (EFI_PHYSICAL_ADDRESS= ) * > StoreIndexTableSize); > + > + // > + // Start with first entry > + // > + VarDig =3D VAR_DIG_PTR (Global->VariableDigests); > + VarInfo.Header.VariableName =3D VAR_DIG_NAME (VarDig); > + VarInfo.Header.VendorGuid =3D VAR_DIG_GUID (VarDig); > + VarInfo.StoreIndex =3D VarDig->StoreIndex; > + StoreIndexTable[Count] =3D VarInfo.StoreIndex; > + Count++; > + > + // > + // Populate the un-sorted table > + // > + do { > + VarInfo.Buffer =3D NULL; > + Status =3D ProtectedVariableLibFindNextEx (&VarInfo); > + if (EFI_ERROR (Status)) { > + break; > + } > + > + StoreIndexTable[Count] =3D VarInfo.StoreIndex; > + Count++; > + } while (TRUE); > + > + PerformQuickSort ( > + StoreIndexTable, > + Count, > + sizeof (EFI_PHYSICAL_ADDRESS), > + (SORT_COMPARE)CompareStoreIndex > + ); > + > + *Buffer =3D StoreIndexTable; > + *NumElements =3D Count; > + > + return EFI_SUCCESS; > +} > diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDx= e.c > b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c > new file mode 100644 > index 000000000000..94df21eacf25 > --- /dev/null > +++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableDxe.c > @@ -0,0 +1,163 @@ > +/** @file > + Implemention of ProtectedVariableLib for SMM variable services. > + > +Copyright (c) 2022, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > + > +#include "Library/UefiBootServicesTableLib.h" > +#include "Library/MemoryAllocationLib.h" > + > +#include "ProtectedVariableInternal.h" > + > +PROTECTED_VARIABLE_CONTEXT_IN mVariableContextIn =3D { > + PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION, > + sizeof (PROTECTED_VARIABLE_CONTEXT_IN), > + 0, > + FromSmmModule, > + NULL, > + NULL, > + NULL, > + NULL, > + NULL > +}; > + > +PROTECTED_VARIABLE_GLOBAL mProtectedVariableGlobal =3D { > + PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION, > + sizeof (PROTECTED_VARIABLE_GLOBAL), > + { 0 }, > + { 0 }, > + 0, > + 0, > + 0, > + 0, > + 0, > + 0, > + { 0, 0, 0 }, > + 0, > + 0, > + { 0, 0, 0, 0, 0, 0} > +}; > + > +/** > + Fix incorrect state of MetaDataHmacVariable before any variable update= . > + > + @param[in] Event The event that occurred > + @param[in] Context For EFI compatibility. Not used. > + > +**/ > +VOID > +EFIAPI > +VariableWriteProtocolCallback ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + EFI_STATUS Status; > + > + // > + // Fix incorrect state of MetaDataHmacVariable before any variable upd= ate. > + // This has to be done here due to the fact that this operation needs = to > + // update NV storage but the FVB and FTW protocol might not be ready d= uring > + // ProtectedVariableLibInitialize(). > + // > + Status =3D FixupHmacVariable (); > + ASSERT_EFI_ERROR (Status); > + > + Status =3D ProtectedVariableLibWriteInit (); > + ASSERT_EFI_ERROR (Status); > + > + gBS->CloseEvent (Event); > +} > + > +/** > + > + Initialization for protected variable services. > + > + If this initialization failed upon any error, the whole variable servi= ces > + should not be used. A system reset might be needed to re-construct NV > + variable storage to be the default state. > + > + @param[in] ContextIn Pointer to variable service context needed by > + protected variable. > + > + @retval EFI_SUCCESS Protected variable services are read= y. > + @retval EFI_INVALID_PARAMETER If ContextIn =3D=3D NULL or somethin= g > missing or > + mismatching in the content in Contex= tIn. > + @retval EFI_COMPROMISED_DATA If failed to check integrity of prot= ected > variables. > + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource. > + @retval EFI_UNSUPPORTED Unsupported to process protected var= iable. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibInitialize ( > + IN PROTECTED_VARIABLE_CONTEXT_IN *ContextIn > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_CONTEXT_IN *ProtectedVarContext; > + PROTECTED_VARIABLE_GLOBAL *OldGlobal; > + PROTECTED_VARIABLE_GLOBAL *NewGlobal; > + VOID *VarWriteReg; > + > + if ( (ContextIn =3D=3D NULL) > + || (ContextIn->StructVersion !=3D > PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION) > + || (ContextIn->StructSize !=3D sizeof (PROTECTED_VARIABLE_CONTEXT_I= N)) > + || (ContextIn->GetVariableInfo =3D=3D NULL) > + || (ContextIn->GetNextVariableInfo =3D=3D NULL) > + || (ContextIn->UpdateVariableStore =3D=3D NULL) > + || (ContextIn->UpdateVariable =3D=3D NULL)) > + { > + ASSERT (ContextIn !=3D NULL); > + ASSERT (ContextIn->StructVersion =3D=3D > PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION); > + ASSERT (ContextIn->StructSize =3D=3D sizeof > (PROTECTED_VARIABLE_CONTEXT_IN)); > + ASSERT (ContextIn->GetVariableInfo !=3D NULL); > + ASSERT (ContextIn->GetNextVariableInfo !=3D NULL); > + ASSERT (ContextIn->UpdateVariableStore !=3D NULL); > + return EFI_INVALID_PARAMETER; > + } > + > + GetProtectedVariableGlobal (&NewGlobal); > + ProtectedVarContext =3D GET_CNTX (NewGlobal); > + CopyMem (ProtectedVarContext, ContextIn, sizeof (mVariableContextIn)); > + ProtectedVarContext->VariableServiceUser =3D FromSmmModule; > + > + // > + // Get root key and HMAC key from HOB created by PEI variable driver. > + // > + Status =3D GetProtectedVariableGlobalFromHob (&OldGlobal); > + ASSERT_EFI_ERROR (Status); > + > + CopyMem ((VOID *)NewGlobal, (CONST VOID *)OldGlobal, sizeof > (*OldGlobal)); > + > + // > + // The keys must not be available outside SMM. > + // > + if (ProtectedVarContext->VariableServiceUser =3D=3D FromSmmModule) { > + ZeroMem (OldGlobal->RootKey, sizeof (OldGlobal->RootKey)); > + ZeroMem (OldGlobal->MetaDataHmacKey, sizeof (OldGlobal- > >MetaDataHmacKey)); > + } > + > + // > + // Register variable write protocol notify function used to fix any > + // inconsistency in MetaDataHmacVariable before the first variable wri= te > + // operation. > + // > + NewGlobal->Flags.WriteInit =3D FALSE; > + NewGlobal->Flags.WriteReady =3D FALSE; > + > + EfiCreateProtocolNotifyEvent ( > + &gEfiVariableWriteArchProtocolGuid, > + TPL_CALLBACK, > + VariableWriteProtocolCallback, > + NULL, > + &VarWriteReg > + ); > + > + return EFI_SUCCESS; > +} > diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePe= i.c > b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c > new file mode 100644 > index 000000000000..8b5ccb83e32d > --- /dev/null > +++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariablePei.c > @@ -0,0 +1,1327 @@ > +/** @file > + > +Copyright (c) 2022, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > +#include > + > +#include > +#include > + > +#include > +#include > +#include > +#include > + > +#include "ProtectedVariableInternal.h" > + > +/** > + Function allocates a global buffer. > + > + This function allocates a buffer with the specified size. > + > + @param[in] Size Size of buffer to allocate. > + @param[in] AllocatePage Whether to allocate pages. > + > + @retval Buffer Pointer to the Buffer allocated. > + @retval NULL if no Buffer was found. > + > +**/ > +VOID * > +AllocateGlobalBuffer ( > + IN UINT32 Size, > + IN BOOLEAN AllocatePage > + ) > +{ > + VOID *Buffer; > + EFI_HOB_MEMORY_ALLOCATION *MemoryAllocationHob; > + EFI_PEI_HOB_POINTERS Hob; > + > + Buffer =3D NULL; > + if (!AllocatePage) { > + Buffer =3D BuildGuidHob (&gEdkiiProtectedVariableGlobalGuid, Size); > + } > + > + if (Buffer =3D=3D NULL) { > + // > + // Use the AllocatePages() to get over size limit of general GUID-ed= HOB. > + // > + Buffer =3D AllocatePages (EFI_SIZE_TO_PAGES (Size)); > + if (Buffer =3D=3D NULL) { > + ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES); > + return NULL; > + } > + > + // > + // Mark the HOB holding the pages just allocated so that it can be > + // identified later. > + // > + MemoryAllocationHob =3D NULL; > + Hob.Raw =3D GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION)= ; > + while (Hob.Raw !=3D NULL) { > + MemoryAllocationHob =3D (EFI_HOB_MEMORY_ALLOCATION *)Hob.Raw; > + if ((UINTN)Buffer =3D=3D (UINTN)MemoryAllocationHob- > >AllocDescriptor.MemoryBaseAddress) { > + CopyGuid ( > + &MemoryAllocationHob->AllocDescriptor.Name, > + &gEdkiiProtectedVariableGlobalGuid > + ); > + break; > + } > + > + Hob.Raw =3D GET_NEXT_HOB (Hob); > + Hob.Raw =3D GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, > Hob.Raw); > + } > + } > + > + return Buffer; > +} > + > +/** > + Callback use to re-verify all variables and cache them in memory. > + > + @param[in] PeiServices General purpose services available to = every PEIM. > + @param[in] NotifyDescriptor The notification structure this PEIM r= egistered > on install. > + @param[in] Ppi The memory discovered PPI. Not used. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval others There's error in MP initialization. > +**/ > +EFI_STATUS > +EFIAPI > +MemoryDiscoveredPpiNotifyCallback ( > + IN EFI_PEI_SERVICES **PeiServices, > + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, > + IN VOID *Ppi > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_CONTEXT_IN *ContextIn; > + PROTECTED_VARIABLE_GLOBAL *Global; > + VARIABLE_DIGEST *VarDig; > + PROTECTED_VARIABLE_INFO VarInfo; > + VOID *Buffer; > + UINT32 VarSize; > + INTN Result; > + > + Status =3D GetProtectedVariableGlobal (&Global); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + ContextIn =3D GET_CNTX (Global); > + > + // > + // Allocate last Var buffer for confidentiality crypto operation > + // > + VarSize =3D (Global->VariableNumber + 1) * MAX_VARIABLE_SIZE; > + Buffer =3D AllocateGlobalBuffer (VarSize, TRUE); > + > + // > + // Traverse all valid variables. > + // > + VarDig =3D VAR_DIG_PTR (Global->VariableDigests); > + while (VarDig !=3D NULL) { > + if (VarDig->CacheIndex =3D=3D VAR_INDEX_INVALID) { > + ASSERT (VarDig->StoreIndex !=3D VAR_INDEX_INVALID); > + > + VarSize =3D VARIABLE_HEADER_SIZE (Global->Flags.Auth); > + VarSize +=3D VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize); > + VarSize +=3D VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize); > + VarSize =3D HEADER_ALIGN (VarSize); > + > + // > + // Note the variable might be in unconsecutive space. > + // > + ZeroMem (&VarInfo, sizeof (VarInfo)); > + VarInfo.StoreIndex =3D VarDig->StoreIndex; > + VarInfo.Buffer =3D Buffer; > + VarInfo.Flags.Auth =3D VarDig->Flags.Auth; > + > + Status =3D ContextIn->GetVariableInfo (&VarInfo); > + ASSERT_EFI_ERROR (Status); > + // > + // VerifyVariableDigest() refers to CipherData for raw data. > + // > + VarInfo.CipherData =3D VarInfo.Header.Data; > + VarInfo.CipherDataSize =3D (UINT32)VarInfo.Header.DataSize; > + > + // > + // Make sure that the cached copy is not compromised. > + // > + Status =3D VerifyVariableDigest (Global, &VarInfo, VarDig); > + if (EFI_ERROR (Status)) { > + REPORT_STATUS_CODE ( > + EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED, > + (PcdGet32 (PcdStatusCodeVariableIntegrity) | (Status & 0xFF)) > + ); > + ASSERT_EFI_ERROR (Status); > + CpuDeadLoop (); > + } > + > + // > + // Simply use the cache address as CacheIndex of the variable. > + // > + VarDig->CacheIndex =3D GET_ADRS (Buffer); > + Buffer =3D (UINT8 *)Buffer + MAX_VARIABLE_SIZE; > + } else { > + Result =3D StrnCmp ( > + VAR_DIG_NAME (VarDig), > + METADATA_HMAC_VARIABLE_NAME, > + METADATA_HMAC_VARIABLE_NAME_SIZE > + ); > + if (Result =3D=3D 0) { > + CopyMem ( > + Buffer, > + GET_BUFR (Global->GlobalSelf + (Global->StructSize - > GetMetaDataHmacVarSize (Global->Flags.Auth))), > + GetMetaDataHmacVarSize (Global->Flags.Auth) > + ); > + > + // > + // Simply use the cache address as CacheIndex of the variable. > + // > + VarDig->CacheIndex =3D GET_ADRS (Buffer); > + Buffer =3D (UINT8 *)Buffer + MAX_VARIABLE_SIZE; > + } > + } > + > + VarDig =3D VAR_DIG_NEXT (VarDig); > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Callback use to perform variable integrity check. > + > + @param[in] PeiServices General purpose services available to = every PEIM. > + @param[in] NotifyDescriptor The notification structure this PEIM r= egistered > on install. > + @param[in] Ppi The memory discovered PPI. Not used. > + > + @retval EFI_SUCCESS The function completed successfully. > + @retval others There's error in MP initialization. > +**/ > +EFI_STATUS > +EFIAPI > +VariableStoreDiscoveredPpiNotifyCallback ( > + IN EFI_PEI_SERVICES **PeiServices, > + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, > + IN VOID *Ppi > + ) > +{ > + EFI_STATUS Status; > + EFI_HOB_GUID_TYPE *GuidHob; > + PROTECTED_VARIABLE_CONTEXT_IN *ContextIn; > + > + GuidHob =3D GetFirstGuidHob (&gEdkiiProtectedVariableContextGuid); > + if (GuidHob !=3D NULL) { > + ContextIn =3D (PROTECTED_VARIABLE_CONTEXT_IN *)GET_GUID_HOB_DATA > (GuidHob); > + } else { > + ASSERT (GuidHob =3D=3D NULL); > + } > + > + Status =3D ContextIn->IsHobVariableStoreAvailable (); > + > + if (Status =3D=3D EFI_NOT_READY) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + Status =3D PerformVariableIntegrityCheck (ContextIn); > + > + return Status; > +} > + > +EFI_PEI_NOTIFY_DESCRIPTOR mPostMemNotifyList[] =3D { > + { > + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | > EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), > + &gEfiPeiMemoryDiscoveredPpiGuid, > + MemoryDiscoveredPpiNotifyCallback > + } > +}; > + > +EFI_PEI_NOTIFY_DESCRIPTOR mVariableStoreNotifyList[] =3D { > + { > + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | > EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), > + &gEfiPeiVariableStoreDiscoveredPpiGuid, > + VariableStoreDiscoveredPpiNotifyCallback > + } > +}; > + > +/** > + > + Get global data structure used to process protected variable. > + > + @param[out] Global Pointer to global configuration data. > + > + @retval EFI_SUCCESS Get requested structure successfully. > + > +**/ > +EFI_STATUS > +EFIAPI > +GetProtectedVariableGlobal ( > + OUT PROTECTED_VARIABLE_GLOBAL **Global OPTIONAL > + ) > +{ > + return GetProtectedVariableGlobalFromHob (Global); > +} > + > +/** > + > + Get context data structure used to process protected variable. > + > + @param[out] ContextIn Pointer to context provided by variable runt= ime > services. > + > + @retval EFI_SUCCESS Get requested structure successfully. > + > +**/ > +EFI_STATUS > +EFIAPI > +GetProtectedVariableContext ( > + PROTECTED_VARIABLE_CONTEXT_IN **ContextIn OPTIONAL > + ) > +{ > + EFI_HOB_GUID_TYPE *GuidHob; > + > + GuidHob =3D GetFirstGuidHob (&gEdkiiProtectedVariableContextGuid); > + if (GuidHob !=3D NULL) { > + *ContextIn =3D (PROTECTED_VARIABLE_CONTEXT_IN *)GET_GUID_HOB_DATA > (GuidHob); > + return EFI_SUCCESS; > + } > + > + return EFI_NOT_FOUND; > +} > + > +/** > + Verify the HMAC value stored in MetaDataHmacVar against all valid and > + protected variables in storage. > + > + @param[in,out] Global Pointer to global configuration data. > + > + @retval EFI_SUCCESS The HMAC value matches. > + @retval EFI_ABORTED Error in HMAC value calculation. > + @retval EFI_VOLUME_CORRUPTED Inconsistency found in NV variable > storage. > + @retval EFI_COMPROMISED_DATA The HMAC value doesn't match. > + > +**/ > +EFI_STATUS > +VerifyMetaDataHmac ( > + IN OUT PROTECTED_VARIABLE_GLOBAL *Global > + ) > +{ > + EFI_STATUS Status; > + VARIABLE_DIGEST *VariableDig; > + UINT32 Counter1; > + UINT32 Counter2; > + VOID *Hmac1; > + VOID *Hmac2; > + UINT8 HmacVal1[METADATA_HMAC_SIZE]; > + UINT8 HmacVal2[METADATA_HMAC_SIZE]; > + > + Hmac1 =3D NULL; > + Hmac2 =3D HmacSha256New (); > + if (Hmac2 =3D=3D NULL) { > + ASSERT (Hmac2 !=3D NULL); > + return EFI_OUT_OF_RESOURCES; > + } > + > + if (!HmacSha256SetKey (Hmac2, Global->MetaDataHmacKey, sizeof (Global- > >MetaDataHmacKey))) { > + ASSERT (FALSE); > + Status =3D EFI_ABORTED; > + goto Done; > + } > + > + // > + // Retrieve the RPMC counter value. > + // > + Status =3D RequestMonotonicCounter (RPMC_COUNTER_1, &Counter1); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + goto Done; > + } > + > + Status =3D RequestMonotonicCounter (RPMC_COUNTER_2, &Counter2); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + goto Done; > + } > + > + // > + // Counter1 must be either equal to Counter2 or just one step ahead of > Counter2. > + // > + if ((Counter1 > Counter2) && ((Counter1 - Counter2) > 1)) { > + Status =3D EFI_COMPROMISED_DATA; > + goto Done; > + } > + > + VariableDig =3D VAR_DIG_PTR (Global->VariableDigests); > + while (VariableDig !=3D NULL) { > + // > + // Only take valid protected variables into account. > + // > + if (VariableDig->Flags.Protected && VariableDig->Flags.Valid) { > + if (!HmacSha256Update ( > + Hmac2, > + VAR_DIG_VALUE (VariableDig), > + VariableDig->DigestSize > + )) > + { > + ASSERT (FALSE); > + Status =3D EFI_ABORTED; > + goto Done; > + } > + } > + > + VariableDig =3D VAR_DIG_NEXT (VariableDig); > + } > + > + // > + // If two MetaDataHmacVariable were found, check which one is valid. W= e > might > + // need two HMAC values to check against: one for Counter1, one for > Counter2. > + // > + if ( (Global->Unprotected[IndexHmacAdded] !=3D VAR_INDEX_INVALID) > + && (Global->Unprotected[IndexHmacInDel] !=3D VAR_INDEX_INVALID) > + && (Counter1 !=3D Counter2)) > + { > + // > + // Might need to check Counter1. There must be something wrong in la= st > boot. > + // > + Hmac1 =3D HmacSha256New (); > + if ((Hmac1 =3D=3D NULL) || !HmacSha256Duplicate (Hmac2, Hmac1)) { > + ASSERT (FALSE); > + Status =3D EFI_OUT_OF_RESOURCES; > + goto Done; > + } > + > + if ( !HmacSha256Update (Hmac1, &Counter1, sizeof (Counter1)) > + || !HmacSha256Final (Hmac1, HmacVal1)) > + { > + ASSERT (FALSE); > + Status =3D EFI_ABORTED; > + goto Done; > + } > + } > + > + // > + // Always check Counter2. > + // > + if ( !HmacSha256Update (Hmac2, &Counter2, sizeof (Counter2)) > + || !HmacSha256Final (Hmac2, HmacVal2)) > + { > + ASSERT (FALSE); > + Status =3D EFI_ABORTED; > + goto Done; > + } > + > + // > + // When writing (update or add) a variable, there must be following s= teps > + // performed: > + // > + // A - Increment Counter1 > + // B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION > + // C - Calculate new HMAC value against Counter2+1, > + // and force-add a new MetaDataHmacVar with state of VAR_ADDED > + // D - Write the new protected variable > + // E - Increment Counter2 > + // F - Mark old MetaDataHmacVar as VAR_DELETED > + // > + Status =3D EFI_COMPROMISED_DATA; > + if ( (Global->Unprotected[IndexHmacAdded] !=3D VAR_INDEX_INVALID) > + && (Global->Unprotected[IndexHmacInDel] =3D=3D VAR_INDEX_INVALID)) > + { > + if (CompareMem ( > + VAR_DIG_VALUE (VAR_DIG_PTR (Global- > >Unprotected[IndexHmacAdded])), > + HmacVal2, > + METADATA_HMAC_SIZE > + ) =3D=3D 0) > + { > + // > + // > + // + A - Increment Counter1 > + // B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION > + // C - Calculate new HMAC value against Counter2+1, > + // and force-add a new MetaDataHmacVar with state of VAR_ADD= ED > + // D - Write the new protected variable > + // E - Increment Counter2 > + // F - Mark old MetaDataHmacVar as VAR_DELETED > + // > + // or, > + // > + // + A - Increment Counter1 > + // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION > + // + C - Calculate new HMAC value against Counter2+1, > + // and force-add a new MetaDataHmacVar with state of VAR_ADD= ED > + // + D - Write the new protected variable > + // + E - Increment Counter2 > + // + F - Mark old MetaDataHmacVar as VAR_DELETED > + // > + Status =3D EFI_SUCCESS; > + > + VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])->Flags.Valid =3D > TRUE; > + } > + } else if ( (Global->Unprotected[IndexHmacAdded] =3D=3D VAR_INDEX_INV= ALID) > + && (Global->Unprotected[IndexHmacInDel] !=3D VAR_INDEX_INVAL= ID)) > + { > + if (CompareMem ( > + VAR_DIG_VALUE (VAR_DIG_PTR (Global- > >Unprotected[IndexHmacInDel])), > + HmacVal2, > + METADATA_HMAC_SIZE > + ) =3D=3D 0) > + { > + // > + // + A - Increment Counter1 > + // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION > + // C - Calculate new HMAC value against Counter2+1, > + // and force-add a new MetaDataHmacVar with state of VAR_ADD= ED > + // D - Write the new protected variable > + // E - Increment Counter2 > + // F - Mark old MetaDataHmacVar as VAR_DELETED > + // > + Status =3D EFI_SUCCESS; > + > + VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])->Flags.Valid =3D= TRUE; > + } > + } else if ( (Global->Unprotected[IndexHmacAdded] !=3D VAR_INDEX_INVAL= ID) > + && (Global->Unprotected[IndexHmacInDel] !=3D VAR_INDEX_INVAL= ID)) > + { > + if (Counter1 > Counter2) { > + if (CompareMem ( > + VAR_DIG_VALUE (VAR_DIG_PTR (Global- > >Unprotected[IndexHmacInDel])), > + HmacVal2, > + METADATA_HMAC_SIZE > + ) =3D=3D 0) > + { > + // > + // + A - Increment Counter1 > + // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION > + // + C - Calculate new HMAC value against Counter2+1, > + // and force-add a new MetaDataHmacVar with state VAR_ADDE= D > + // D - Write the new protected variable > + // E - Increment Counter2 > + // F - Mark old MetaDataHmacVar as VAR_DELETED > + // > + Status =3D EFI_SUCCESS; > + > + VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])->Flags.Valid = =3D > FALSE; > + VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])->Flags.Valid = =3D > TRUE; > + } else if (CompareMem ( > + VAR_DIG_VALUE (VAR_DIG_PTR (Global- > >Unprotected[IndexHmacAdded])), > + HmacVal1, > + METADATA_HMAC_SIZE > + ) =3D=3D 0) > + { > + // > + // + A - Increment Counter1 > + // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION > + // + C - Calculate new HMAC value against Counter2+1, > + // and force-add a new MetaDataHmacVar with state of VAR_A= DDED > + // + D - Write the new protected variable > + // E - Increment Counter2 > + // F - Mark old MetaDataHmacVar as VAR_DELETED > + // > + Status =3D EFI_SUCCESS; > + > + VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])->Flags.Valid = =3D > TRUE; > + VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])->Flags.Valid = =3D > FALSE; > + } > + } else { > + if (CompareMem ( > + VAR_DIG_VALUE (VAR_DIG_PTR (Global- > >Unprotected[IndexHmacAdded])), > + HmacVal2, > + METADATA_HMAC_SIZE > + ) =3D=3D 0) > + { > + // > + // + A - Increment Counter1 > + // + B - Mark old MetaDataHmacVar as VAR_IN_DELETED_TRANSITION > + // + C - Calculate new HMAC value against Counter2+1, > + // and force-add a new MetaDataHmacVar with state of VAR_A= DDED > + // + D - Write the new protected variable > + // + E - Increment Counter2 > + // F - Mark old MetaDataHmacVar as VAR_DELETED > + // > + Status =3D EFI_SUCCESS; > + > + VAR_DIG_PTR (Global->Unprotected[IndexHmacAdded])->Flags.Valid = =3D > TRUE; > + VAR_DIG_PTR (Global->Unprotected[IndexHmacInDel])->Flags.Valid = =3D > FALSE; > + } > + } > + } else { > + // > + // There must be logic error or variable written to storage skipped > + // the protected variable service, if code reaches here. > + // > + ASSERT (FALSE); > + } > + > +Done: > + if (Hmac1 !=3D NULL) { > + HmacSha256Free (Hmac1); > + } > + > + if (Hmac2 !=3D NULL) { > + HmacSha256Free (Hmac2); > + } > + > + return Status; > +} > + > +/** > + Collect variable digest information. > + > + This information is collected to be used to for integrity check. > + > + @param[in] Global Pointer to global configuration da= ta. > + @param[in] ContextIn Pointer to variable service contex= t needed by > + protected variable. > + @param[in, out] DigestBuffer Base address of digest of each var= iable. > + @param[out] DigestBufferSize Digest size of one variable if Dig= estBuffer > is NULL. > + Size of DigestBuffer if DigestBuff= er is NOT NULL. > + @param[out] VariableNumber Number of valid variables. > + > + @retval EFI_SUCCESS Successfully retreived variable dige= st. > + @retval EFI_INVALID_PARAMETER One ore more parameters are invalid. > + @retval EFI_OUT_OF_RESOURCES Unable to allocate memory. > + @retval EFI_BUFFER_TOO_SMALL The DigestBufferSize pass in is too = small. > + > +**/ > +EFI_STATUS > +CollectVariableDigestInfo ( > + IN PROTECTED_VARIABLE_GLOBAL *Global, > + IN PROTECTED_VARIABLE_CONTEXT_IN *ContextIn, > + IN OUT VOID *DigestBuffer OPTIONAL, > + OUT UINT32 *DigestBufferSize OPTIONAL, > + OUT UINT32 *VariableNumber OPTIONAL > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_INFO VarInfo; > + UINT32 VarNum; > + UINT32 DigSize; > + VARIABLE_DIGEST *VarDig; > + EFI_TIME TimeStamp; > + UNPROTECTED_VARIABLE_INDEX VarIndex; > + > + // > + // This function might be called before Global is initialized. In that= case, > + // Global must be NULL but not ContextIn. > + // > + if ((Global =3D=3D NULL) && (ContextIn =3D=3D NULL)) { > + ASSERT (Global !=3D NULL || ContextIn !=3D NULL); > + return EFI_INVALID_PARAMETER; > + } > + > + if ((Global =3D=3D NULL) && (DigestBuffer !=3D NULL)) { > + ASSERT (Global !=3D NULL && DigestBuffer !=3D NULL); > + return EFI_INVALID_PARAMETER; > + } > + > + if ( (DigestBuffer !=3D NULL) > + && ((DigestBufferSize =3D=3D NULL) || (*DigestBufferSize =3D=3D 0))= ) > + { > + ASSERT ( > + DigestBuffer !=3D NULL > + && DigestBufferSize !=3D NULL && *DigestBufferSize > 0 > + ); > + return EFI_INVALID_PARAMETER; > + } > + > + if ((Global !=3D NULL) && (ContextIn =3D=3D NULL)) { > + ContextIn =3D GET_CNTX (Global); > + } > + > + DigSize =3D 0; > + VarNum =3D 0; > + VarDig =3D NULL; > + > + ZeroMem (&VarInfo, sizeof (VarInfo)); > + VarInfo.StoreIndex =3D VAR_INDEX_INVALID; // To get the first variable= . > + > + if ((Global !=3D NULL) && > + (Global->VariableCache !=3D 0) && > + (Global->VariableCacheSize > 0)) > + { > + // > + // Use the variable cache to hold a copy of one variable. > + // > + VarInfo.Buffer =3D GET_BUFR (Global->VariableCache); > + } else { > + // > + // Allocate a buffer to hold a copy of one variable > + // > + VarInfo.Buffer =3D AllocatePages (EFI_SIZE_TO_PAGES (MAX_VARIABLE_SI= ZE)); > + if (VarInfo.Buffer =3D=3D NULL) { > + ASSERT (VarInfo.Buffer !=3D NULL); > + return EFI_OUT_OF_RESOURCES; > + } > + } > + > + if ((DigestBuffer !=3D NULL) && (*DigestBufferSize > 0)) { > + VarDig =3D DigestBuffer; > + } > + > + while (TRUE) { > + if (VarDig !=3D NULL) { > + if (DigSize >=3D (*DigestBufferSize)) { > + // > + // Out of buffer. > + // > + break; > + } > + > + VarInfo.Header.VendorGuid =3D &VarDig->VendorGuid; > + VarInfo.Header.VariableName =3D VAR_DIG_NAME (VarDig); > + VarInfo.Header.NameSize =3D (UINTN)DigestBuffer + > (UINTN)*DigestBufferSize > + - (UINTN)VarInfo.Header.VariableName= ; > + VarInfo.Header.TimeStamp =3D &TimeStamp; > + VarInfo.Header.Data =3D NULL; > + } else { > + ZeroMem ((VOID *)&VarInfo.Header, sizeof (VarInfo.Header)); > + } > + > + Status =3D ContextIn->GetNextVariableInfo (&VarInfo); > + if (EFI_ERROR (Status)) { > + break; > + } > + > + // > + // Skip deleted variables. > + // > + if ( (VarInfo.Header.State !=3D VAR_ADDED) > + && (VarInfo.Header.State !=3D (VAR_ADDED & > VAR_IN_DELETED_TRANSITION))) > + { > + continue; > + } > + > + if (Global !=3D NULL) { > + Global->Flags.Auth &=3D VarInfo.Flags.Auth; > + } > + > + VarNum +=3D 1; > + DigSize +=3D (UINT32)(sizeof (VARIABLE_DIGEST) > + + VarInfo.Header.NameSize > + + METADATA_HMAC_SIZE); > + if ((DigestBuffer !=3D NULL) && (DigSize > *DigestBufferSize)) { > + ASSERT (DigSize <=3D *DigestBufferSize); > + return EFI_BUFFER_TOO_SMALL; > + } > + > + if (VarDig !=3D NULL) { > + VarDig->Prev =3D 0; > + VarDig->Next =3D 0; > + VarDig->State =3D VarInfo.Header.State; > + VarDig->Attributes =3D VarInfo.Header.Attributes; > + VarDig->DataSize =3D (UINT32)VarInfo.Header.DataSize; > + VarDig->NameSize =3D (UINT16)VarInfo.Header.NameSize; > + VarDig->DigestSize =3D METADATA_HMAC_SIZE; > + VarDig->StoreIndex =3D VarInfo.StoreIndex; > + > + if ((VarInfo.Buffer !=3D NULL) && ((UINTN)VarInfo.Buffer !=3D Glob= al- > >VariableCache)) { > + VarDig->CacheIndex =3D GET_ADRS (VarInfo.Buffer); > + } else { > + VarDig->CacheIndex =3D VAR_INDEX_INVALID; > + } > + > + VarDig->Flags.Auth =3D VarInfo.Flags.Auth; > + VarDig->Flags.Valid =3D TRUE; > + > + VarIndex =3D CheckKnownUnprotectedVariable (Global, &VarInfo); > + if (VarIndex >=3D UnprotectedVarIndexMax) { > + // > + // Check information relating to encryption, if enabled. > + // > + VarDig->Flags.Encrypted =3D FALSE; > + if ((VarInfo.Header.Data !=3D NULL) && (VarInfo.Header.DataSize = > 0)) { > + VarInfo.CipherData =3D NULL; > + VarInfo.CipherDataSize =3D 0; > + VarInfo.PlainData =3D NULL; > + VarInfo.PlainDataSize =3D 0; > + Status =3D GetCipherDataInfo (&VarInfo); > + if (!EFI_ERROR (Status)) { > + // > + // Discovered encrypted variable mark variable to be > + // encrypted on the next SetVariable() operation > + // > + VarDig->Flags.Encrypted =3D PcdGetBool > (PcdProtectedVariableConfidentiality); > + } else { > + VarInfo.PlainData =3D VarInfo.Header.Data; > + VarInfo.PlainDataSize =3D (UINT32)VarInfo.Header.DataSize= ; > + VarInfo.CipherDataType =3D 0; > + VarInfo.CipherHeaderSize =3D 0; > + if (Status =3D=3D EFI_NOT_FOUND) { > + // > + // Found variable that is not encrypted mark variable to b= e > + // encrypted on the next SetVariable() operation > + // > + VarDig->Flags.Encrypted =3D PcdGetBool > (PcdProtectedVariableConfidentiality); > + } > + } > + } > + > + // > + // Variable is protected > + // > + VarDig->Flags.Protected =3D PcdGetBool (PcdProtectedVariableInte= grity); > + VarDig->PlainDataSize =3D VarInfo.PlainDataSize; > + > + // > + // Calculate digest only for protected variable. > + // > + Status =3D GetVariableDigest (Global, &VarInfo, VAR_DIG_VALUE (V= arDig)); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + // > + // Keep the VarDig in an ordered list. > + // > + InsertVariableDigestNode (Global, VarDig, CompareVariableDigestI= nfo); > + } else { > + VarDig->Flags.Protected =3D FALSE; > + VarDig->Flags.Encrypted =3D FALSE; > + VarDig->PlainDataSize =3D VarDig->DataSize; > + > + // > + // Make use of VARIABLE_DIGEST->DigestValue to cache HMAC value > from > + // MetaDataHmacVar, which doesn't need a digest value (only prot= ected > + // variables need it for integrity check). > + // > + if ((VarIndex =3D=3D IndexHmacInDel) || (VarIndex =3D=3D IndexHm= acAdded)) { > + if (VarDig->State =3D=3D VAR_ADDED) { > + VarIndex =3D IndexHmacAdded; > + } else { > + VarIndex =3D IndexHmacInDel; > + } > + } > + > + Global->Unprotected[VarIndex] =3D VAR_DIG_ADR (VarDig); > + > + if ((VarInfo.Header.Data !=3D NULL) && (VarDig->DataSize <=3D Va= rDig- > >DigestSize)) { > + CopyMem (VAR_DIG_VALUE (VarDig), VarInfo.Header.Data, VarDig- > >DataSize); > + } > + > + // > + // Don't add the VarDig for MetaDataHmacVar into the linked list= now. > + // Do it after the HMAC has been validated. > + // > + if ((VarIndex !=3D IndexHmacInDel) || (VarIndex !=3D IndexHmacAd= ded)) { > + InsertVariableDigestNode (Global, VarDig, CompareVariableDiges= tInfo); > + } > + } > + > + VarDig =3D (VARIABLE_DIGEST *)((UINTN)VarDig + VAR_DIG_END (VarDig= )); > + } > + } > + > + if (EFI_ERROR (Status) && (Status !=3D EFI_NOT_FOUND)) { > + return Status; > + } > + > + if (DigestBufferSize !=3D NULL) { > + *DigestBufferSize =3D DigSize; > + } > + > + if (VariableNumber !=3D NULL) { > + *VariableNumber =3D VarNum; > + } > + > + if ((Global =3D=3D NULL) && (VarInfo.Buffer !=3D NULL)) { > + // > + // Free Buffer > + // > + FreePages (VarInfo.Buffer, EFI_SIZE_TO_PAGES (MAX_VARIABLE_SIZE)); > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + > + Perform for protected variable integrity check. > + > + If this initialization failed upon any error, the whole variable servi= ces > + should not be used. A system reset might be needed to re-construct NV > + variable storage to be the default state. > + > + @param[in] ContextIn Pointer to variable service context needed by > + protected variable. > + > + @retval EFI_SUCCESS Protected variable services are read= y. > + @retval EFI_INVALID_PARAMETER If ContextIn =3D=3D NULL or somethin= g > missing or > + mismatching in the content in Contex= tIn. > + @retval EFI_COMPROMISED_DATA If failed to check integrity of prot= ected > variables. > + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource. > + @retval EFI_UNSUPPORTED Unsupported to process protected var= iable. > + > +**/ > +EFI_STATUS > +EFIAPI > +PerformVariableIntegrityCheck ( > + IN PROTECTED_VARIABLE_CONTEXT_IN *ContextIn > + ) > +{ > + EFI_STATUS Status; > + UINT32 HobDataSize; > + UINT32 VarNumber; > + VOID *Buffer; > + PROTECTED_VARIABLE_GLOBAL *Global; > + VARIABLE_DIGEST *DigBuffer; > + UINT32 DigBufferSize; > + UINT32 HmacMetaDataSize; > + UINTN Index; > + BOOLEAN PreviousKey; > + EFI_HOB_GUID_TYPE *GuidHob; > + > + if ((ContextIn =3D=3D NULL) || (ContextIn->GetNextVariableInfo =3D=3D = NULL)) { > + ASSERT (ContextIn !=3D NULL); > + ASSERT (ContextIn->GetNextVariableInfo !=3D NULL); > + return EFI_INVALID_PARAMETER; > + } > + > + ContextIn->StructSize =3D (ContextIn->StructSize =3D=3D 0) ? sizeof (*= ContextIn) > + : ContextIn->Stru= ctSize; > + > + // > + // Enumerate all variables first to collect info for resource allocati= on. > + // > + DigBufferSize =3D 0; > + Status =3D CollectVariableDigestInfo ( > + NULL, > + ContextIn, > + NULL, > + &DigBufferSize, > + &VarNumber > + ); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return EFI_VOLUME_CORRUPTED; > + } > + > + // > + // Allocate buffer for Global. Memory layout: > + // > + // Global > + // Digest context > + // Variable Digest List > + // HmacMetaData > + // > + // To save precious NEM space of processor, variable cache will not be > + // allocated at this point until physical memory is ready for use. > + // > + HmacMetaDataSize =3D (UINT32)GetMetaDataHmacVarSize (TRUE); > + HobDataSize =3D sizeof (PROTECTED_VARIABLE_GLOBAL) > + + (UINT32)DIGEST_CONTEXT_SIZE > + + DigBufferSize > + + HmacMetaDataSize; > + Buffer =3D AllocateGlobalBuffer (HobDataSize, FALSE); > + if (Buffer =3D=3D NULL) { > + ASSERT (Buffer !=3D NULL); > + return EFI_OUT_OF_RESOURCES; > + } > + > + Global =3D (PROTECTED_VARIABLE_GLOBAL *)((UINTN)Buffer)= ; > + Global->DigestContext =3D GET_ADRS (Global + 1); > + > + if (DigBufferSize > 0) { > + DigBuffer =3D (VARIABLE_DIGEST *)(UINTN)(Global->DigestContext + > DIGEST_CONTEXT_SIZE); > + ZeroMem (DigBuffer, DigBufferSize); > + } else { > + DigBuffer =3D NULL; > + } > + > + // > + // Keep a copy of ContextIn in HOB for later uses. > + // > + Global->GlobalSelf =3D GET_ADRS (Global); > + Global->ContextIn =3D GET_ADRS (ContextIn); > + > + Global->StructVersion =3D > PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION; > + Global->StructSize =3D HobDataSize; > + > + Global->VariableNumber =3D VarNumber; > + Global->VariableDigests =3D 0; > + > + Global->Flags.Auth =3D TRUE; > + Global->Flags.WriteInit =3D FALSE; > + Global->Flags.WriteReady =3D FALSE; > + > + GuidHob =3D GetFirstGuidHob (&gEfiAuthenticatedVariableGuid); > + if (GuidHob =3D=3D NULL) { > + GuidHob =3D GetFirstGuidHob (&gEfiVariableGuid); > + if (GuidHob !=3D NULL) { > + Global->Flags.Auth =3D FALSE; > + } > + } > + > + Global->Flags.RecoveryMode =3D (GuidHob !=3D NULL); > + > + // > + // Before physical memory is ready, we cannot cache all variables in t= he very > + // limited NEM space. But we still need to reserve buffer to hold data= of > + // one variable as well as context for integrity check (HMAC calculati= on). > + // > + Global->VariableCacheSize =3D MAX_VARIABLE_SIZE; > + Buffer =3D AllocatePages (EFI_SIZE_TO_PAGES (Global= - > >VariableCacheSize)); > + if (Buffer =3D=3D NULL) { > + ASSERT (Buffer !=3D NULL); > + return EFI_OUT_OF_RESOURCES; > + } > + > + Global->VariableCache =3D GET_ADRS (Buffer); > + Global->LastAccessedVariable =3D VAR_INDEX_INVALID; > + > + for (Index =3D 0; Index < UnprotectedVarIndexMax; ++Index) { > + Global->Unprotected[Index] =3D VAR_INDEX_INVALID; > + } > + > + // > + // Re-enumerate all NV variables and build digest list. > + // > + Status =3D CollectVariableDigestInfo ( > + Global, > + ContextIn, > + DigBuffer, > + &DigBufferSize, > + &VarNumber > + ); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + ASSERT (Global->VariableNumber =3D=3D VarNumber); > + > + // > + // Fix-up number of valid protected variables (i.e. exclude unprotecte= d ones) > + // > + for (Index =3D 0; VarNumber !=3D 0 && Index < UnprotectedVarIndexMax; = ++Index) > { > + if (Global->Unprotected[Index] !=3D VAR_INDEX_INVALID) { > + --VarNumber; > + } > + } > + > + // > + // Get root key and generate HMAC key. > + // > + PreviousKey =3D FALSE; > + Status =3D GetVariableKey ((VOID *)Global->RootKey, sizeof (Globa= l- > >RootKey)); > + if (EFI_ERROR (Status)) { > + ASSERT (FALSE); > + Status =3D EFI_COMPROMISED_DATA; > + } > + > + // > + // Derive the MetaDataHmacKey from root key > + // > + if (!GenerateMetaDataHmacKey ( > + Global->RootKey, > + sizeof (Global->RootKey), > + Global->MetaDataHmacKey, > + sizeof (Global->MetaDataHmacKey) > + )) > + { > + ASSERT (FALSE); > + Status =3D EFI_COMPROMISED_DATA; > + } > + > + // > + // Check the integrity of all NV variables, if any. > + // > + if (( (Global->Unprotected[IndexHmacAdded] !=3D VAR_INDEX_INVALID) > + || (Global->Unprotected[IndexHmacInDel] !=3D VAR_INDEX_INVALID))) > + { > + // > + // Validate the HMAC stored in variable MetaDataHmacVar. > + // > + Status =3D VerifyMetaDataHmac (Global); > + if (EFI_ERROR (Status)) { > + // > + // Try again with the previous root key if the latest key failed t= he HMAC > validation. > + // > + Status =3D GetVariableKey ((VOID *)Global->RootKey, sizeof (Global= - > >RootKey)); > + if (!EFI_ERROR (Status)) { > + // > + // Derive the MetaDataHmacKey from previous root key > + // > + if (GenerateMetaDataHmacKey ( > + Global->RootKey, > + sizeof (Global->RootKey), > + Global->MetaDataHmacKey, > + sizeof (Global->MetaDataHmacKey) > + ) =3D=3D TRUE) > + { > + // > + // Validate the HMAC stored in variable MetaDataHmacVar. > + // > + Status =3D VerifyMetaDataHmac (Global); > + if (!EFI_ERROR (Status)) { > + Status =3D EFI_COMPROMISED_DATA; > + } > + } else { > + Status =3D EFI_COMPROMISED_DATA; > + } > + } > + } > + } else if (Global->Flags.RecoveryMode) { > + // > + // Generate the first version of MetaDataHmacVar. > + // > + Status =3D SyncRpmcCounter (); > + if (!EFI_ERROR (Status)) { > + Status =3D RefreshVariableMetadataHmac (Global, NULL, NULL); > + if (!EFI_ERROR (Status)) { > + // > + // MetaDataHmacVar is always calculated against Counter2+1. Upda= ting > + // RPMCs to match it. > + // > + (VOID)IncrementMonotonicCounter (RPMC_COUNTER_1); > + (VOID)IncrementMonotonicCounter (RPMC_COUNTER_2); > + } > + } > + } else if ((VarNumber > 0) && !Global->Flags.RecoveryMode) { > + // > + // There's no MetaDataHmacVar found for protected variables. Suppose > + // the variable storage is compromised. > + // > + Status =3D EFI_COMPROMISED_DATA; > + } > + > + if (EFI_ERROR (Status)) { > + // > + // The integrity of variables have been compromised. The platform ha= s to do > + // something to recover the variable store. But the boot should not = go on > + // anyway this time. > + // > + DEBUG ((DEBUG_ERROR, "%a: %d Integrity check Status =3D %r\n", > __FUNCTION__, __LINE__, Status)); > + REPORT_STATUS_CODE ( > + EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED, > + (PcdGet32 (PcdStatusCodeVariableIntegrity) | > EFI_SW_PEI_PC_RECOVERY_BEGIN) > + ); > + #if defined (EDKII_UNIT_TEST_FRAMEWORK_ENABLED) // Avoid test > malfunctioning. > + return Status; > + #else > + ASSERT_EFI_ERROR (Status); > + CpuDeadLoop (); > + #endif > + } > + > + // > + // Everything's OK. > + // > + REPORT_STATUS_CODE ( > + EFI_PROGRESS_CODE, > + PcdGet32 (PcdStatusCodeVariableIntegrity) > + ); > + > + if (GET_BUFR (Global->VariableCacheSize) !=3D NULL) { > + // > + // Free Buffer > + // > + FreePages (Buffer, EFI_SIZE_TO_PAGES (Global->VariableCacheSize)); > + } > + > + // > + // Keep the valid MetaDataHmacVar in the list. > + // > + for (Index =3D 0; Index < IndexPlatformVar; ++Index) { > + if ( (Global->Unprotected[Index] !=3D VAR_INDEX_INVALID) > + && VAR_DIG_PTR (Global->Unprotected[Index])->Flags.Valid) > + { > + InsertVariableDigestNode ( > + Global, > + VAR_DIG_PTR (Global->Unprotected[Index]), > + NULL > + ); > + } > + } > + > + // > + // Restore the key to the latest one. > + // > + if (PreviousKey) { > + Status =3D GetVariableKey ((VOID *)Global->RootKey, sizeof (Global->= RootKey)); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Derive the MetaDataHmacKey from root key > + // > + if (!GenerateMetaDataHmacKey ( > + Global->RootKey, > + sizeof (Global->RootKey), > + Global->MetaDataHmacKey, > + sizeof (Global->MetaDataHmacKey) > + )) > + { > + ASSERT (FALSE); > + } > + } > + > + // > + // Make sure that the RPMC counter is in-sync. > + // > + Status =3D SyncRpmcCounter (); > + > + // > + // Setup a hook to migrate data in Global once physical memory is read= y. > + // > + Status =3D PeiServicesNotifyPpi (mPostMemNotifyList); > + > + return Status; > +} > + > +/** > + > + Initialization for protected variable services. > + > + If the variable store is available than perform integrity check. > + Otherwise, defer integrity check until variable store is available. > + > + > + @param[in] ContextIn Pointer to variable service context needed by > + protected variable. > + > + @retval EFI_SUCCESS Protected variable services are read= y. > + @retval EFI_INVALID_PARAMETER If ContextIn =3D=3D NULL or somethin= g > missing or > + mismatching in the content in Contex= tIn. > + @retval EFI_COMPROMISED_DATA If failed to check integrity of prot= ected > variables. > + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource. > + @retval EFI_UNSUPPORTED Unsupported to process protected var= iable. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibInitialize ( > + IN PROTECTED_VARIABLE_CONTEXT_IN *ContextIn > + ) > +{ > + EFI_STATUS Status; > + VOID *ContextInHob; > + PROTECTED_VARIABLE_INFO VarInfo; > + > + if ((ContextIn =3D=3D NULL) || (ContextIn->GetNextVariableInfo =3D=3D = NULL)) { > + ASSERT (ContextIn !=3D NULL); > + ASSERT (ContextIn->GetNextVariableInfo !=3D NULL); > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // Keep a copy of ContextIn in HOB for later uses. > + // > + ContextIn->StructSize =3D (ContextIn->StructSize =3D=3D 0) ? sizeof (*= ContextIn) > + : ContextIn->Stru= ctSize; > + ContextInHob =3D BuildGuidHob (&gEdkiiProtectedVariableContextGuid, > ContextIn->StructSize); > + CopyMem (ContextInHob, ContextIn, ContextIn->StructSize); > + > + // > + // Discover if Variable Store Info Hob has been published by platform = driver. > + // It contains information regards to HOB or NV Variable Store availab= ility > + // > + ZeroMem ((VOID *)&VarInfo.Header, sizeof (VarInfo.Header)); > + VarInfo.StoreIndex =3D VAR_INDEX_INVALID; > + VarInfo.Buffer =3D AllocatePages (EFI_SIZE_TO_PAGES (MAX_VARIABLE_= SIZE)); > + if (VarInfo.Buffer =3D=3D NULL) { > + ASSERT (VarInfo.Buffer !=3D NULL); > + return EFI_OUT_OF_RESOURCES; > + } > + > + FreePages (VarInfo.Buffer, EFI_SIZE_TO_PAGES ((MAX_VARIABLE_SIZE))); > + > + Status =3D ContextIn->GetNextVariableInfo (&VarInfo); > + if (EFI_ERROR (Status)) { > + // > + // Register for platform driver callback when Variable Store is avai= lable. > + // > + DEBUG ((DEBUG_INFO, "Variable Store is not available. Register for a > integrity check callback\n")); > + Status =3D PeiServicesNotifyPpi (mVariableStoreNotifyList); > + return Status; > + } > + > + // > + // HOB Variable store is not available > + // Assume NV Variable store is available instead > + // Perform integrity check on NV Variable Store > + // > + DEBUG ((DEBUG_INFO, "NV Variable Store is available. Perform integrity > check\n")); > + Status =3D PerformVariableIntegrityCheck (ContextInHob); > + return Status; > +} > + > +/** > + > + Prepare for variable update. > + > + (Not suppported in PEI phase.) > + > + @retval EFI_UNSUPPORTED Updating variable is not supported. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibWriteInit ( > + VOID > + ) > +{ > + ASSERT (FALSE); > + return EFI_UNSUPPORTED; > +} > + > +/** > + > + Update a variable with protection provided by this library. > + > + Not supported in PEI phase. > + > + @param[in,out] CurrVariable Variable to be updated. It's NULL = if > + adding a new variable. > + @param[in] CurrVariableInDel In-delete-transition copy of updat= ing > variable. > + @param[in,out] NewVariable Buffer of new variable data. > + Buffer of "MetaDataHmacVar" and ne= w > + variable (encrypted). > + @param[in,out] NewVariableSize Size of NewVariable. > + Size of (encrypted) NewVariable an= d > + "MetaDataHmacVar". > + > + @retval EFI_UNSUPPORTED Not support updating variable in PEI p= hase. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibUpdate ( > + IN OUT VARIABLE_HEADER *CurrVariable, > + IN VARIABLE_HEADER *CurrVariableInDel, > + IN OUT VARIABLE_HEADER *NewVariable, > + IN OUT UINTN *NewVariableSize > + ) > +{ > + ASSERT (FALSE); > + return EFI_UNSUPPORTED; > +} > + > +/** > + > + Finalize a variable updating after it's written to NV variable storage > + successfully. > + > + @param[in] NewVariable Buffer of new variables and > MetaDataHmacVar. > + @param[in] VariableSize Size of buffer pointed by NewVariabl= e. > + @param[in] StoreIndex StoreIndex to NV variable storage fr= om where > the new > + variable and MetaDataHmacVar have be= en written. > + > + @retval EFI_UNSUPPORTED Not support updating variable in PEI= phase. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibWriteFinal ( > + IN VARIABLE_HEADER *NewVariable, > + IN UINTN VariableSize, > + IN UINT64 StoreIndex > + ) > +{ > + ASSERT (FALSE); > + return EFI_UNSUPPORTED; > +} > diff --git a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSm= m.c > b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c > new file mode 100644 > index 000000000000..8e964f4cd28d > --- /dev/null > +++ b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmm.c > @@ -0,0 +1,209 @@ > +/** @file > + Implemention of ProtectedVariableLib for SMM variable services. > + > +Copyright (c) 2022, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > + > +#include "Guid/SmmVariableCommon.h" > + > +#include "Library/MmServicesTableLib.h" > +#include "Library/MemoryAllocationLib.h" > + > +#include "ProtectedVariableInternal.h" > + > +PROTECTED_VARIABLE_CONTEXT_IN mVariableContextIn =3D { > + PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION, > + sizeof (PROTECTED_VARIABLE_CONTEXT_IN), > + 0, > + FromSmmModule, > + NULL, > + NULL, > + NULL, > + NULL, > + NULL > +}; > + > +PROTECTED_VARIABLE_GLOBAL mProtectedVariableGlobal =3D { > + PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION, > + sizeof (PROTECTED_VARIABLE_GLOBAL), > + { 0 }, > + { 0 }, > + 0, > + 0, > + 0, > + 0, > + 0, > + 0, > + { 0, 0, 0 }, > + 0, > + 0, > + { 0, 0, 0, 0} > +}; > + > +/** > + > + Callback function to call variable write. > + > + @param[in] Protocol Not Used. > + @param[in] Interface Not Used. > + @param[in] Handle Not Used. > + > + @retval EFI_SUCCESS Protected variable write successful. > + @retval others Protected variable write failed. > + > +**/ > +EFI_STATUS > +EFIAPI > +VariableWriteProtocolCallback ( > + IN CONST EFI_GUID *Protocol, > + IN VOID *Interface, > + IN EFI_HANDLE Handle > + ) > +{ > + EFI_STATUS Status; > + > + Status =3D ProtectedVariableLibWriteInit (); > + ASSERT_EFI_ERROR (Status); > + > + return EFI_SUCCESS; > +} > + > +/** > + > + Initialization for protected variable services. > + > + If this initialization failed upon any error, the whole variable servi= ces > + should not be used. A system reset might be needed to re-construct NV > + variable storage to be the default state. > + > + @param[in] ContextIn Pointer to variable service context needed by > + protected variable. > + > + @retval EFI_SUCCESS Protected variable services are read= y. > + @retval EFI_INVALID_PARAMETER If ContextIn =3D=3D NULL or somethin= g > missing or > + mismatching in the content in Contex= tIn. > + @retval EFI_COMPROMISED_DATA If failed to check integrity of prot= ected > variables. > + @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource. > + @retval EFI_UNSUPPORTED Unsupported to process protected var= iable. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibInitialize ( > + IN PROTECTED_VARIABLE_CONTEXT_IN *ContextIn > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_CONTEXT_IN *ProtectedVarContext; > + PROTECTED_VARIABLE_GLOBAL *OldGlobal; > + PROTECTED_VARIABLE_GLOBAL *NewGlobal; > + VARIABLE_DIGEST *VarDig; > + VARIABLE_DIGEST *NewVarDig; > + EFI_PHYSICAL_ADDRESS NewCacheIndex; > + UINTN VarSize; > + UNPROTECTED_VARIABLE_INDEX Index; > + > + if ( (ContextIn =3D=3D NULL) > + || (ContextIn->StructVersion !=3D > PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION) > + || (ContextIn->StructSize !=3D sizeof (PROTECTED_VARIABLE_CONTEXT_I= N)) > + || (ContextIn->GetVariableInfo =3D=3D NULL) > + || (ContextIn->GetNextVariableInfo =3D=3D NULL) > + || (ContextIn->UpdateVariableStore =3D=3D NULL) > + || (ContextIn->UpdateVariable =3D=3D NULL)) > + { > + ASSERT (ContextIn !=3D NULL); > + ASSERT (ContextIn->StructVersion =3D=3D > PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION); > + ASSERT (ContextIn->StructSize =3D=3D sizeof > (PROTECTED_VARIABLE_CONTEXT_IN)); > + ASSERT (ContextIn->GetVariableInfo !=3D NULL); > + ASSERT (ContextIn->GetNextVariableInfo !=3D NULL); > + ASSERT (ContextIn->UpdateVariableStore !=3D NULL); > + ASSERT (ContextIn->UpdateVariable !=3D NULL); > + return EFI_INVALID_PARAMETER; > + } > + > + GetProtectedVariableGlobal (&NewGlobal); > + ProtectedVarContext =3D GET_CNTX (NewGlobal); > + CopyMem (ProtectedVarContext, ContextIn, sizeof (mVariableContextIn)); > + ProtectedVarContext->VariableServiceUser =3D FromSmmModule; > + > + // > + // Get root key and HMAC key from HOB created by PEI variable driver. > + // > + Status =3D GetProtectedVariableGlobalFromHob (&OldGlobal); > + ASSERT_EFI_ERROR (Status); > + > + CopyMem ((VOID *)NewGlobal, (CONST VOID *)OldGlobal, sizeof > (*OldGlobal)); > + > + // > + // The keys must not be available outside SMM. > + // > + if (ProtectedVarContext->VariableServiceUser =3D=3D FromSmmModule) { > + ZeroMem (OldGlobal->RootKey, sizeof (OldGlobal->RootKey)); > + ZeroMem (OldGlobal->MetaDataHmacKey, sizeof (OldGlobal- > >MetaDataHmacKey)); > + } > + > + NewGlobal->Flags.WriteInit =3D FALSE; > + NewGlobal->Flags.WriteReady =3D FALSE; > + NewGlobal->LastAccessedVariable =3D 0; > + NewGlobal->VariableCache =3D GET_ADRS (AllocateZeroPool > (MAX_VARIABLE_SIZE)); > + NewGlobal->DigestContext =3D GET_ADRS (AllocateZeroPool > (DIGEST_CONTEXT_SIZE)); > + if (NewGlobal->DigestContext =3D=3D 0) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + // > + // Copy over variable from HOB to SMM memory > + // > + NewGlobal->VariableDigests =3D 0; > + VarDig =3D VAR_DIG_PTR (OldGlobal->VariableDigests= ); > + while (VarDig !=3D NULL) { > + // > + // Allocate new Var Digest in SMM memory > + // > + NewVarDig =3D (VARIABLE_DIGEST *)AllocateZeroPool ( > + sizeof (VARIABLE_DIGEST) + VarDig->= NameSize + > METADATA_HMAC_SIZE > + ); > + if (NewVarDig =3D=3D NULL) { > + ASSERT (NewVarDig !=3D NULL); > + return EFI_OUT_OF_RESOURCES; > + } > + > + CopyMem (NewVarDig, VarDig, sizeof (VARIABLE_DIGEST)); > + NewVarDig->Prev =3D 0; > + NewVarDig->Next =3D 0; > + > + CopyMem (VAR_DIG_NAME (NewVarDig), VAR_DIG_NAME (VarDig), VarDig- > >NameSize); > + CopyMem (VAR_DIG_VALUE (NewVarDig), VAR_DIG_VALUE (VarDig), > VarDig->DigestSize); > + > + VarSize =3D VARIABLE_HEADER_SIZE (NewGlobal->Flags.Auth); > + VarSize +=3D VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize); > + VarSize +=3D VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize); > + VarSize =3D HEADER_ALIGN (VarSize); > + > + NewCacheIndex =3D GET_ADRS (AllocateZeroPool (VarSize)); > + if (GET_BUFR (NewCacheIndex) =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + CopyMem (GET_BUFR (NewCacheIndex), GET_BUFR (VarDig->CacheIndex), > VarSize); > + NewVarDig->CacheIndex =3D NewCacheIndex; > + NewVarDig->Flags.Freeable =3D TRUE; > + > + for (Index =3D 0; Index < UnprotectedVarIndexMax; ++Index) { > + if (OldGlobal->Unprotected[Index] =3D=3D VAR_DIG_ADR (VarDig)) { > + NewGlobal->Unprotected[Index] =3D VAR_DIG_ADR (NewVarDig); > + } > + } > + > + InsertVariableDigestNode (NewGlobal, NewVarDig, NULL); > + > + VarDig =3D VAR_DIG_NEXT (VarDig); > + } > + > + return Status; > +} > diff --git > a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon > .c > b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon > .c > new file mode 100644 > index 000000000000..8472fc8a33c7 > --- /dev/null > +++ > b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmDxeCommon > .c > @@ -0,0 +1,967 @@ > +/** @file > + Implemention of ProtectedVariableLib for SMM variable services. > + > +Copyright (c) 2022, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > + > +#include "Guid/SmmVariableCommon.h" > + > +#include "Library/MmServicesTableLib.h" > +#include "Library/MemoryAllocationLib.h" > +#include > + > +#include "ProtectedVariableInternal.h" > + > +/** > + > + Get context and/or global data structure used to process protected var= iable. > + > + @param[out] Global Pointer to global configuration data. > + > + @retval EFI_SUCCESS Get requested structure successfully. > + > +**/ > +EFI_STATUS > +EFIAPI > +GetProtectedVariableGlobal ( > + OUT PROTECTED_VARIABLE_GLOBAL **Global OPTIONAL > + ) > +{ > + if (Global !=3D NULL) { > + mProtectedVariableGlobal.ContextIn =3D GET_ADRS (&mVariableContextIn= ); > + *Global =3D &mProtectedVariableGlobal; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Encrypt given variable data and generate new HMAC value against it. > + > + @param[in] Global Pointer to global configuration data. > + @param[in,out] NewVarInfo Pointer to buffer of new variable data= . > + @param[in,out] NewVarDig Pointer to buffer of new variable dige= st. > + > + @retval EFI_SUCCESS No error occurred during the encryption = and HMC > calculation. > + @retval EFI_ABORTED Failed to do HMC calculation. > + @return EFI_OUT_OF_RESOURCES Not enough resource to calculate HMC > value. > + @return EFI_NOT_FOUND The MetaDataHmacVar was not found in > storage. > + > +**/ > +STATIC > +EFI_STATUS > +UpdateVariableInternal ( > + IN PROTECTED_VARIABLE_GLOBAL *Global, > + IN OUT PROTECTED_VARIABLE_INFO *NewVarInfo, > + IN OUT VARIABLE_DIGEST *NewVarDig > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_INFO CachedVarInfo; > + VOID *Buffer; > + UINTN VarSize; > + > + if ((NewVarInfo =3D=3D NULL) || (NewVarDig =3D=3D NULL)) { > + return EFI_INVALID_PARAMETER; > + } > + > + // > + // If Add or update variable, encrypt new data first. > + // > + if (NewVarInfo->Buffer !=3D NULL) { > + Status =3D EFI_UNSUPPORTED; > + > + if (NewVarDig->Flags.Encrypted) { > + NewVarInfo->PlainData =3D NULL; > + NewVarInfo->PlainDataSize =3D 0; > + NewVarInfo->CipherData =3D NULL; > + NewVarInfo->CipherDataSize =3D 0; > + NewVarInfo->Key =3D Global->RootKey; > + NewVarInfo->KeySize =3D sizeof (Global->RootKey); > + NewVarInfo->Header.Attributes &=3D (~EFI_VARIABLE_APPEND_WRITE); > + Status =3D EncryptVariable (NewVarInfo); > + if (!EFI_ERROR (Status)) { > + // > + // Update new data size in variable header. > + // > + SET_VARIABLE_DATA_SIZE (NewVarInfo, NewVarInfo->CipherDataSize); > + } else if (Status !=3D EFI_UNSUPPORTED) { > + ASSERT (FALSE); > + return Status; > + } > + } > + > + if (Status =3D=3D EFI_UNSUPPORTED) { > + NewVarInfo->CipherData =3D NewVarInfo->Header.Data; > + NewVarInfo->CipherDataSize =3D (UINT32)NewVarInfo->Header.DataSize= ; > + NewVarInfo->PlainData =3D NULL; > + NewVarInfo->PlainDataSize =3D 0; > + } > + } else { > + NewVarInfo->CipherData =3D NULL; > + NewVarInfo->CipherDataSize =3D 0; > + NewVarInfo->PlainData =3D NULL; > + NewVarInfo->PlainDataSize =3D 0; > + } > + > + if (NewVarDig->CacheIndex !=3D 0) { > + // > + // Update the cached copy. > + // > + ZeroMem ((VOID *)&CachedVarInfo, sizeof (CachedVarInfo)); > + CachedVarInfo.Buffer =3D GET_BUFR (NewVarDig->CacheIndex); > + CachedVarInfo.StoreIndex =3D VAR_INDEX_INVALID; > + CachedVarInfo.Flags.Auth =3D NewVarInfo->Flags.Auth; > + > + Status =3D GET_CNTX (Global)->GetVariableInfo (&CachedVarInfo); > + ASSERT_EFI_ERROR (Status); > + > + if ((CachedVarInfo.Header.DataSize !=3D 0) && (NewVarInfo->CipherDat= aSize > > CachedVarInfo.Header.DataSize)) { > + // > + // allocate new VarInfo buffer that is of greater CipherDataSize > + // > + VarSize =3D VARIABLE_HEADER_SIZE (NewVarDig->Flags.Auth); > + VarSize +=3D NewVarInfo->Header.NameSize + GET_PAD_SIZE (NewVarInf= o- > >Header.NameSize); > + VarSize +=3D NewVarInfo->CipherDataSize + GET_PAD_SIZE (NewVarInfo= - > >CipherDataSize); > + VarSize =3D HEADER_ALIGN (VarSize); > + Buffer =3D AllocateZeroPool (VarSize); > + if (Buffer !=3D NULL) { > + VarSize =3D VARIABLE_HEADER_SIZE (NewVarDig->Flags.Auth); > + VarSize +=3D CachedVarInfo.Header.NameSize + GET_PAD_SIZE > (CachedVarInfo.Header.NameSize); > + VarSize +=3D CachedVarInfo.Header.DataSize + GET_PAD_SIZE > (CachedVarInfo.DataSize); > + VarSize =3D HEADER_ALIGN (VarSize); > + > + CopyMem ( > + Buffer, > + CachedVarInfo.Buffer, > + VarSize > + ); > + > + FreePool (CachedVarInfo.Buffer); > + > + // > + // Update the cached copy. > + // > + ZeroMem ((VOID *)&CachedVarInfo, sizeof (CachedVarInfo)); > + CachedVarInfo.Buffer =3D Buffer; > + CachedVarInfo.StoreIndex =3D VAR_INDEX_INVALID; > + CachedVarInfo.Flags.Auth =3D NewVarInfo->Flags.Auth; > + Status =3D GET_CNTX (Global)->GetVariableInfo = (&CachedVarInfo); > + ASSERT_EFI_ERROR (Status); > + NewVarDig->CacheIndex =3D (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer; > + } > + } > + > + CopyMem ( > + CachedVarInfo.Header.Data, > + NewVarInfo->CipherData, > + NewVarInfo->CipherDataSize > + ); > + SET_VARIABLE_DATA_SIZE (&CachedVarInfo, NewVarInfo->CipherDataSize); > + > + NewVarDig->State =3D VAR_ADDED; > + NewVarDig->DataSize =3D NewVarInfo->CipherDataSize; > + > + if (NewVarInfo->PlainDataSize > 0) { > + NewVarDig->PlainDataSize =3D NewVarInfo->PlainDataSize; > + } else { > + NewVarDig->PlainDataSize =3D NewVarDig->DataSize; > + } > + > + // > + // (Re-)Calculate the hash of the variable. > + // > + if (NewVarDig->Flags.Protected) { > + GetVariableDigest (Global, NewVarInfo, VAR_DIG_VALUE (NewVarDig)); > + } > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + > + Fix state of MetaDataHmacVar on NV variable storage, if there's failur= e at > + last boot during updating variable. > + > + This must be done before the first writing of variable in current boot= , > + including storage reclaim. > + > + @retval EFI_UNSUPPORTED Updating NV variable storage is not > supported. > + @retval EFI_OUT_OF_RESOURCES Not enough resource to complete the > operation. > + @retval EFI_SUCCESS Variable store was successfully updated= . > + > +**/ > +EFI_STATUS > +FixupHmacVariable ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_INFO HmacVarInfo; > + PROTECTED_VARIABLE_GLOBAL *Global; > + PROTECTED_VARIABLE_CONTEXT_IN *ContextIn; > + VARIABLE_DIGEST *VarDig; > + UINTN Index; > + > + Status =3D GetProtectedVariableGlobal (&Global); > + ASSERT_EFI_ERROR (Status); > + > + if (Global->Flags.WriteReady) { > + return EFI_SUCCESS; > + } > + > + ContextIn =3D GET_CNTX (Global); > + > + // > + // Delete invalid MetaDataHmacVar. > + // > + for (Index =3D 0; Index <=3D IndexHmacAdded; ++Index) { > + if (Global->Unprotected[Index] =3D=3D VAR_INDEX_INVALID) { > + continue; > + } > + > + VarDig =3D VAR_DIG_PTR (Global->Unprotected[Index]); > + if (VarDig->Flags.Valid) { > + continue; > + } > + > + ZeroMem ((VOID *)&HmacVarInfo, sizeof (HmacVarInfo)); > + HmacVarInfo.StoreIndex =3D VarDig->StoreIndex; > + HmacVarInfo.Flags.Auth =3D VarDig->Flags.Auth; > + > + Status =3D ContextIn->GetVariableInfo (&HmacVarInfo); > + if (!EFI_ERROR (Status) && (HmacVarInfo.Buffer !=3D NULL)) { > + HmacVarInfo.Buffer->State &=3D VAR_DELETED; > + Status =3D ContextIn->UpdateVariableStore ( > + &HmacVarInfo, > + OFFSET_OF (VARIABLE_HEAD= ER, State), > + sizeof (HmacVarInfo.Buff= er->State), > + &HmacVarInfo.Buffer->Sta= te > + ); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + } > + > + // > + // Release the resource and update related states. > + // > + VarDig->State &=3D VAR_DELETED; > + RemoveVariableDigestNode (Global, VarDig, FALSE); > + Global->Unprotected[Index] =3D VAR_INDEX_INVALID; > + } > + > + // > + // There should be no MetaDataHmacVar if in variable storage recovery = mode. > + // > + if (Global->Flags.RecoveryMode) { > + ASSERT (Global->Unprotected[IndexHmacAdded] =3D=3D VAR_INDEX_INVALID= ); > + ASSERT (Global->Unprotected[IndexHmacInDel] =3D=3D VAR_INDEX_INVALID= ); > + } > + > + Global->Flags.WriteReady =3D TRUE; > + > + return EFI_SUCCESS; > +} > + > +/** > + > + Prepare for variable update. > + > + This is needed only once during current boot to mitigate replay attack= . Its > + major job is to advance RPMC (Replay Protected Monotonic Counter). > + > + @retval EFI_SUCCESS Variable is ready to update hereafter. > + @retval EFI_UNSUPPORTED Updating variable is not supported. > + @retval EFI_DEVICE_ERROR Error in advancing RPMC. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibWriteInit ( > + VOID > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_GLOBAL *Global; > + PROTECTED_VARIABLE_CONTEXT_IN *ContextIn; > + PROTECTED_VARIABLE_INFO VarInfo; > + > + (VOID)GetProtectedVariableGlobal (&Global); > + ContextIn =3D GET_CNTX (Global); > + > + // > + // HmacVarInfo should be here > + // > + if (Global->Flags.RecoveryMode) { > + // > + // Flush default variables to variable storage if in variable recove= ry mode. > + // > + Status =3D ContextIn->UpdateVariableStore (NULL, 0, (UINT32)-1, NULL= ); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + } else { > + ContextIn =3D GET_CNTX (Global); > + > + // > + // Fix any wrong MetaDataHmacVar information before adding new one. > + // > + Status =3D FixupHmacVariable (); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + if (!Global->Flags.WriteReady) { > + return EFI_NOT_READY; > + } > + > + // > + // Refresh MetaDataHmacVar with RPMC2 by 1 in each boot before any > variable > + // update, by deleting (attr =3D=3D 0 && datasize =3D=3D 0) the old= one. > + // > + ZeroMem (&VarInfo, sizeof (PROTECTED_VARIABLE_INFO)); // Zero attr = & > datasize > + > + VarInfo.Flags.Auth =3D Global->Flags.Auth; > + VarInfo.Header.VariableName =3D METADATA_HMAC_VARIABLE_NAME; > + VarInfo.Header.NameSize =3D METADATA_HMAC_VARIABLE_NAME_SIZE; > + VarInfo.Header.VendorGuid =3D &METADATA_HMAC_VARIABLE_GUID; > + > + // > + // Pretend to delete MetaDataHmacVar. > + // > + Status =3D ContextIn->UpdateVariable (&VarInfo.Header); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + } > + > + mProtectedVariableGlobal.Flags.WriteInit =3D TRUE; > + > + return EFI_SUCCESS; > +} > + > +/** > + > + Update a variable with protection provided by this library. > + > + If variable encryption is employed, the new variable data will be encr= ypted > + before being written to NV variable storage. > + > + A special variable, called "MetaDataHmacVar", will always be updated a= long > + with variable being updated to reflect the changes (HMAC value) of all > + protected valid variables. The only exceptions, currently, is variable > + variable "VarErrorLog". > + > + The buffer passed by NewVariable must be double of maximum variable si= ze, > + which allows to pass the "MetaDataHmacVar" back to caller along with > encrypted > + new variable data, if any. This can make sure the new variable data an= d > + "MetaDataHmacVar" can be written at almost the same time to reduce the > chance > + of compromising the integrity. > + > + If *NewVariableSize is zero, it means to delete variable passed by Cur= rVariable > + and/or CurrVariableInDel. "MetaDataHmacVar" will be updated as well in= such > + case because of less variables in storage. NewVariable should be alway= s > passed > + in to convey new "MetaDataHmacVar" back. > + > + @param[in,out] CurrVariable Variable to be updated. It's NULL = if > + adding a new variable. > + @param[in] CurrVariableInDel In-delete-transition copy of updat= ing > variable. > + @param[in,out] NewVariable Buffer of new variable data. > + Buffer of "MetaDataHmacVar" and ne= w > + variable (encrypted). > + @param[in,out] NewVariableSize Size of NewVariable. > + Size of (encrypted) NewVariable an= d > + "MetaDataHmacVar". > + > + @retval EFI_SUCCESS The variable is updated with protectio= n > successfully. > + @retval EFI_INVALID_PARAMETER NewVariable is NULL. > + @retval EFI_NOT_FOUND Information missing to finish the oper= ation. > + @retval EFI_ABORTED Failed to encrypt variable or calculat= e HMAC. > + @retval EFI_NOT_READY The RPMC device is not yet initialized= . > + @retval EFI_DEVICE_ERROR The RPMC device has error in updating. > + @retval EFI_ACCESS_DENIED The given variable is not allowed to u= pdate. > + Currently this only happens on updatin= g > + "MetaDataHmacVar" from code outside of= this > + library. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibUpdate ( > + IN OUT VARIABLE_HEADER *CurrVariable, > + IN VARIABLE_HEADER *CurrVariableInDel, > + IN OUT VARIABLE_HEADER *NewVariable, > + IN OUT UINTN *NewVariableSize > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_CONTEXT_IN *ContextIn; > + PROTECTED_VARIABLE_GLOBAL *Global; > + PROTECTED_VARIABLE_INFO VarInfo; > + VARIABLE_DIGEST *VarDig; > + VARIABLE_DIGEST *CurrVarDig; > + VARIABLE_DIGEST *NewVarDig; > + PROTECTED_VARIABLE_INFO NewVarInfo; > + PROTECTED_VARIABLE_INFO NewHmacVarInfo; > + UINTN VarSize; > + UINT64 UnprotectedVarIndex; > + > + // > + // Advance RPMC > + // > + Status =3D IncrementMonotonicCounter (RPMC_COUNTER_1); > + ASSERT_EFI_ERROR (Status); > + > + // > + // Buffer for new variable is always needed, even this function is cal= led to > + // delete an existing one, because we need to pass the MetaDataHmacVar > back > + // which will be updated upon each variable addition or deletion. > + // > + if ((NewVariable =3D=3D NULL) || (NewVariableSize =3D=3D NULL)) { > + ASSERT (NewVariable !=3D NULL); > + ASSERT (NewVariableSize !=3D NULL); > + return EFI_INVALID_PARAMETER; > + } > + > + Status =3D GetProtectedVariableGlobal (&Global); > + ASSERT_EFI_ERROR (Status); > + ContextIn =3D GET_CNTX (Global); > + > + if (!Global->Flags.WriteReady && !Global->Flags.WriteInit) { > + return EFI_NOT_READY; > + } > + > + VarSize =3D 0; > + CurrVarDig =3D NULL; > + NewVarDig =3D NULL; > + UnprotectedVarIndex =3D VAR_INDEX_INVALID; > + > + // > + // Check existing copy of the same variable. > + // > + if (CurrVariable !=3D NULL) { > + // > + // Find local cached copy, if possible. > + // > + ZeroMem (&VarInfo, sizeof (VarInfo)); > + VarInfo.Buffer =3D CurrVariable; > + VarInfo.StoreIndex =3D VAR_INDEX_INVALID; > + VarInfo.Flags.Auth =3D Global->Flags.Auth; > + > + Status =3D ContextIn->GetVariableInfo (&VarInfo); // Retrieve the na= me/guid > + ASSERT_EFI_ERROR (Status); > + > + UnprotectedVarIndex =3D CheckKnownUnprotectedVariable (Global, &VarI= nfo); > + if (UnprotectedVarIndex < UnprotectedVarIndexMax) { > + CurrVarDig =3D VAR_DIG_PTR (Global->Unprotected[UnprotectedVarInde= x]); > + } else { > + CurrVarDig =3D FindVariableInternal (Global, &VarInfo, FALSE); > + } > + > + ASSERT (CurrVarDig !=3D NULL); > + CurrVarDig->State &=3D VAR_DELETED; > + } > + > + // > + // The old copy of the variable might haven't been deleted completely. > + // > + if (CurrVariableInDel !=3D NULL) { > + // > + // Find local cached copy, if possible. > + // > + ZeroMem (&VarInfo, sizeof (VarInfo)); > + VarInfo.Buffer =3D CurrVariableInDel; > + VarInfo.StoreIndex =3D VAR_INDEX_INVALID; > + VarInfo.Flags.Auth =3D Global->Flags.Auth; > + > + Status =3D ContextIn->GetVariableInfo (&VarInfo); // Retrieve the na= me/guid > + ASSERT_EFI_ERROR (Status); > + > + if (UnprotectedVarIndex =3D=3D VAR_INDEX_INVALID) { > + UnprotectedVarIndex =3D CheckKnownUnprotectedVariable (Global, > &VarInfo); > + } > + > + if (UnprotectedVarIndex < UnprotectedVarIndexMax) { > + VarDig =3D VAR_DIG_PTR (Global->Unprotected[UnprotectedVarIndex]); > + } else { > + VarDig =3D FindVariableInternal (Global, &VarInfo, FALSE); > + } > + > + if ((VarDig !=3D NULL) && (VAR_DIG_ADR (VarDig) !=3D VAR_INDEX_INVAL= ID)) { > + VarDig->State &=3D VAR_DELETED; > + > + // > + // Just need one node for the same variable. So remove the one > + // in-del-transition. > + // > + if ((CurrVarDig !=3D NULL) && (VarDig !=3D CurrVarDig)) { > + RemoveVariableDigestNode (Global, VarDig, TRUE); > + } else { > + CurrVarDig =3D VarDig; // Reuse the one in-del-transition. > + } > + } > + } > + > + // > + // New data of the variable or new variable to be added. > + // > + if (NewVariable !=3D NULL) { > + // > + // Completely new variable? > + // > + if (UnprotectedVarIndex =3D=3D VAR_INDEX_INVALID) { > + ZeroMem (&VarInfo, sizeof (VarInfo)); > + VarInfo.Buffer =3D NewVariable; > + VarInfo.StoreIndex =3D VAR_INDEX_INVALID; > + VarInfo.Flags.Auth =3D Global->Flags.Auth; > + > + Status =3D ContextIn->GetVariableInfo (&VarInfo); // Retrieve the = name/guid > + ASSERT_EFI_ERROR (Status); > + > + UnprotectedVarIndex =3D CheckKnownUnprotectedVariable (Global, > &VarInfo); > + } > + } > + > + // > + // Reserve space for MetaDataHmacVar (before the new variable so > + // that it can be written first). > + // > + ZeroMem (&NewVarInfo, sizeof (NewVarInfo)); > + ZeroMem (&NewHmacVarInfo, sizeof (NewHmacVarInfo)); > + > + // > + // Put the MetaDataHmacVar at the beginning of buffer. > + // > + NewHmacVarInfo.Buffer =3D NewVariable; > + > + if (*NewVariableSize =3D=3D 0) { > + // > + // Delete variable (but not MetaDataHmacVar) > + // > + if ( (UnprotectedVarIndex !=3D IndexHmacAdded) > + && (UnprotectedVarIndex !=3D IndexHmacInDel)) > + { > + RemoveVariableDigestNode (Global, CurrVarDig, TRUE); > + } > + > + NewVarInfo.Buffer =3D NULL; > + } else if (UnprotectedVarIndex >=3D IndexPlatformVar) { > + // > + // Add/update variable. Move new variable data to be after > MetaDataHmacVar. > + // > + // TRICK: New MetaDataHmacVar will be put at the beginning of buffer > + // for new variable so that they can be written into non-vola= tile > + // variable storage in one call. This can avoid writing one v= ariable > + // (NewHmacVarInfo) in the middle of writing another variable > + // (NewVarInfo), which will need two calls and introduce extr= a > + // complexities (from temp variable buffer reservation to var= iable > + // space reclaim, etc.) in current implementation of variable > + // services. The caller must make sure there's enough space i= n > + // variable buffer (i.e. at least 2 * MaxVariableSize). > + // > + NewVarInfo.Buffer =3D (VARIABLE_HEADER *)((UINTN)NewVariable > + + GetMetaDataHmacVarSize (Gl= obal->Flags.Auth)); > + CopyMem ((VOID *)NewVarInfo.Buffer, (VOID *)NewVariable, > *NewVariableSize); > + > + NewVarInfo.StoreIndex =3D VAR_INDEX_INVALID; // Skip offset calcul= ation > (it's new one) > + NewVarInfo.Flags.Auth =3D Global->Flags.Auth; > + > + Status =3D ContextIn->GetVariableInfo (&NewVarInfo); > + ASSERT_EFI_ERROR (Status); > + > + if (CurrVarDig !=3D NULL) { > + // > + // Update existing variable. Re-use the node. > + // > + NewVarDig =3D CurrVarDig; > + } else { > + // > + // Add new variable. > + // > + NewVarDig =3D CreateVariableDigestNode ( > + NewVarInfo.Header.VariableName, > + NewVarInfo.Header.VendorGuid, > + (UINT16)NewVarInfo.Header.NameSize, > + (UINT32)NewVarInfo.Header.DataSize, > + NewVarInfo.Flags.Auth, > + Global > + ); > + if (NewVarDig =3D=3D NULL) { > + return EFI_OUT_OF_RESOURCES; > + } > + > + NewVarDig->Attributes =3D NewVarInfo.Header.Attributes; > + if (UnprotectedVarIndex < UnprotectedVarIndexMax) { > + NewVarDig->Flags.Protected =3D FALSE; > + NewVarDig->Flags.Encrypted =3D FALSE; > + Global->Unprotected[UnprotectedVarIndex] =3D VAR_DIG_ADR (NewVar= Dig); > + } > + > + // > + // copy new variable to CacheIndex > + // > + VarSize =3D VARIABLE_HEADER_SIZE (NewVarInfo.Flags.Auth); > + VarSize +=3D NewVarInfo.Header.NameSize + GET_PAD_SIZE > (NewVarInfo.Header.NameSize); > + VarSize +=3D NewVarInfo.Header.DataSize + GET_PAD_SIZE > (NewVarInfo.Header.DataSize); > + VarSize =3D HEADER_ALIGN (VarSize); > + CopyMem (GET_BUFR (NewVarDig->CacheIndex), GET_BUFR > (NewVarInfo.Buffer), VarSize); > + InsertVariableDigestNode (Global, NewVarDig, NULL); > + } > + } > + > + if ( (UnprotectedVarIndex =3D=3D IndexHmacAdded) > + || (UnprotectedVarIndex =3D=3D IndexHmacInDel)) > + { > + // > + // MetaDataHmacVar should be managed only by this library. It's not > + // supposed to be updated by external users of variable service. The= only > + // exception is that deleting it (not really delete but refresh the = HMAC > + // value against RPMC+1) is allowed before WriteInit, as a way to al= ways > + // increment RPMC once in current boot before any variable updates. > + // > + if ((NewVarInfo.Buffer !=3D NULL) || Global->Flags.WriteInit) { > + return EFI_ACCESS_DENIED; > + } > + } else { > + // > + // Do encryption, if enabled. > + // > + if ((NewVarDig !=3D NULL) && (NewVarInfo.Buffer !=3D NULL)) { > + Status =3D UpdateVariableInternal (Global, &NewVarInfo, NewVarDig)= ; > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + } > + } > + > + // > + // Refresh MetaDataHmacVar. > + // > + Status =3D RefreshVariableMetadataHmac (Global, NULL, &NewHmacVarInfo)= ; > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + > + // > + // Return size for both MetaDataHmacVar and added/updated one. > + // > + VarSize =3D VARIABLE_SIZE (&NewHmacVarInfo); > + *NewVariableSize =3D HEADER_ALIGN (VarSize); > + if (NewVarInfo.Buffer !=3D NULL) { > + VarSize =3D VARIABLE_SIZE (&NewVarInfo); > + VarSize =3D HEADER_ALIGN (VarSize); > + > + if (VarSize > GET_CNTX (Global)->MaxVariableSize) { > + return EFI_BAD_BUFFER_SIZE; > + } > + > + *NewVariableSize +=3D VarSize; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + > + Finalize a variable updating after it's written to NV variable storage > + successfully. > + > + This usually includes works like increasing RPMC, synchronizing local = cache, > + updating new position of "MetaDataHmacVar", deleting old copy of > "MetaDataHmacVar" > + completely, etc. > + > + @param[in] NewVariable Buffer of new variables and > MetaDataHmacVar. > + @param[in] VariableSize Size of buffer pointed by NewVariabl= e. > + @param[in] StoreIndex StoreIndex to NV variable storage fr= om where > the new > + variable and MetaDataHmacVar have be= en written. > + > + @retval EFI_SUCCESS No problem in winding up the variable writ= e > operation. > + @retval Others Failed to updating state of old copy of up= dated > + variable, or failed to increase RPMC, etc. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibWriteFinal ( > + IN VARIABLE_HEADER *NewVariable, > + IN UINTN VariableSize, > + IN UINT64 StoreIndex > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_INFO VarInfo; > + PROTECTED_VARIABLE_CONTEXT_IN *ContextIn; > + PROTECTED_VARIABLE_GLOBAL *Global; > + UNPROTECTED_VARIABLE_INDEX Index; > + VARIABLE_DIGEST *VarDig; > + VOID *Buffer; > + UINTN VarSize; > + UINTN NewVarSize; > + > + Status =3D GetProtectedVariableGlobal (&Global); > + ASSERT_EFI_ERROR (Status); > + ContextIn =3D GET_CNTX (Global); > + > + ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo)); > + VarInfo.Buffer =3D NewVariable; > + VarInfo.StoreIndex =3D VAR_INDEX_INVALID; > + VarInfo.Flags.Auth =3D Global->Flags.Auth; > + > + Status =3D ContextIn->GetVariableInfo (&VarInfo); > + ASSERT_EFI_ERROR (Status); > + > + Index =3D CheckKnownUnprotectedVariable (Global, &VarInfo); > + if (Index < UnprotectedVarIndexMax) { > + VarDig =3D VAR_DIG_PTR (Global->Unprotected[Index]); > + } else { > + VarDig =3D FindVariableInternal (Global, &VarInfo, FALSE); > + } > + > + if (Index =3D=3D IndexHmacAdded) { > + // > + // Advance the RPMC to let it match new MetaDataHmacVar. > + // > + Status =3D IncrementMonotonicCounter (RPMC_COUNTER_2); > + ASSERT_EFI_ERROR (Status); > + > + if ((VarDig->StoreIndex !=3D VAR_INDEX_INVALID) && (VarDig->State != =3D > VAR_ADDED)) { > + ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo)); > + VarInfo.StoreIndex =3D VarDig->StoreIndex; // Still point to old = copy > + VarInfo.Flags.Auth =3D Global->Flags.Auth; > + > + // > + // Delete variable completely. > + // > + Status =3D ContextIn->GetVariableInfo (&VarInfo); > + ASSERT_EFI_ERROR (Status); > + > + if ( (VarInfo.Buffer->State =3D=3D VAR_ADDED) > + || (VarInfo.Buffer->State =3D=3D (VAR_ADDED & > VAR_IN_DELETED_TRANSITION))) > + { > + VarInfo.Buffer->State &=3D VAR_DELETED; > + Status =3D ContextIn->UpdateVariableStore ( > + &VarInfo, > + OFFSET_OF (VARIABLE_HEADER= , State), > + sizeof (VarInfo.Buffer->St= ate), > + &VarInfo.Buffer->State > + ); > + if (EFI_ERROR (Status)) { > + ASSERT_EFI_ERROR (Status); > + return Status; > + } > + } > + } > + } > + > + VarDig->StoreIndex =3D StoreIndex; > + VarDig->State =3D VAR_ADDED; > + > + ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo)); > + VarInfo.Buffer =3D NULL; > + VarInfo.StoreIndex =3D VarDig->StoreIndex; > + VarInfo.Flags.Auth =3D Global->Flags.Auth; > + Status =3D ContextIn->GetVariableInfo (&VarInfo); > + > + // > + // Check if cache pool need re-allocation due to variable size increas= e > + // > + VarSize =3D VARIABLE_HEADER_SIZE (VarDig->Flags.Auth); > + VarSize +=3D VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize); > + VarSize +=3D VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize); > + VarSize =3D HEADER_ALIGN (VarSize); > + > + NewVarSize =3D VARIABLE_HEADER_SIZE (VarInfo.Flags.Auth); > + NewVarSize +=3D VarInfo.Header.NameSize + GET_PAD_SIZE > (VarInfo.Header.NameSize); > + NewVarSize +=3D VarInfo.Header.DataSize + GET_PAD_SIZE > (VarInfo.Header.DataSize); > + NewVarSize =3D HEADER_ALIGN (NewVarSize); > + > + if (VarSize < NewVarSize) { > + if (VarDig->Flags.Freeable =3D=3D TRUE) { > + FreePool (GET_BUFR (VarDig->CacheIndex)); > + } > + > + Buffer =3D AllocatePool (NewVarSize); > + if (Buffer !=3D NULL) { > + VarDig->CacheIndex =3D (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer; > + } else { > + ASSERT (FALSE); > + return EFI_ABORTED; > + } > + } > + > + // > + // Update cached copy. > + // > + CopyMem (GET_BUFR (VarDig->CacheIndex), NewVariable, NewVarSize); > + > + // > + // Check if there is consecutive variable as part of the write or > + // is it just the MetaDataHmacVar variable > + // > + if (NewVarSize < VariableSize) { > + // > + // Advance to consecutive Variable > + // > + NewVariable =3D GET_BUFR (GET_ADRS (NewVariable) + NewVarSize); > + > + // > + // Update the StoreIndex of consecutive Variable > + // > + ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo)); > + VarInfo.Buffer =3D NULL; > + VarInfo.StoreIndex =3D VarDig->StoreIndex; > + VarInfo.Flags.Auth =3D Global->Flags.Auth; > + Status =3D ContextIn->GetNextVariableInfo (&VarInfo); > + StoreIndex =3D VarInfo.StoreIndex; > + > + // > + // The new StoreIndex does not exist in the variable digest. > + // It is yet to be updated. > + // Therefore, find variable by Name & Guid instead. > + // > + VarInfo.StoreIndex =3D VAR_INDEX_INVALID; > + VarDig =3D FindVariableInternal (Global, &VarInfo, FALSE= ); > + > + // > + // Check if cache pool need re-allocation due to variable size incre= ase > + // > + VarSize =3D VARIABLE_HEADER_SIZE (VarDig->Flags.Auth); > + VarSize +=3D VarDig->NameSize + GET_PAD_SIZE (VarDig->NameSize); > + VarSize +=3D VarDig->DataSize + GET_PAD_SIZE (VarDig->DataSize); > + VarSize =3D HEADER_ALIGN (VarSize); > + > + NewVarSize =3D VARIABLE_HEADER_SIZE (VarInfo.Flags.Auth); > + NewVarSize +=3D VarInfo.Header.NameSize + GET_PAD_SIZE > (VarInfo.Header.NameSize); > + NewVarSize +=3D VarInfo.Header.DataSize + GET_PAD_SIZE > (VarInfo.Header.DataSize); > + NewVarSize =3D HEADER_ALIGN (NewVarSize); > + > + if (VarSize < NewVarSize) { > + if (VarDig->Flags.Freeable =3D=3D TRUE) { > + FreePool (GET_BUFR (VarDig->CacheIndex)); > + } > + > + Buffer =3D AllocatePool (NewVarSize); > + if (Buffer !=3D NULL) { > + VarDig->CacheIndex =3D (EFI_PHYSICAL_ADDRESS)(UINTN)Buffer; > + } else { > + ASSERT (FALSE); > + return EFI_ABORTED; > + } > + } > + > + // > + // Update cached copy. > + // > + CopyMem (GET_BUFR (VarDig->CacheIndex), NewVariable, NewVarSize); > + VarDig->StoreIndex =3D StoreIndex; > + } > + > + return Status; > +} > + > +/** > + Refresh variable information changed by variable service. > + > + @param[in] Variable Pointer to buffer of the updated variable= . > + @param[in] VariableSize Size of variable pointed by Variable. > + @param[in] StoreIndex New index of the variable in store. > + @param[in] RefreshData Flag to indicate if the variable has been= updated. > + > + @return EFI_SUCCESS No error occurred in updating. > + @return EFI_NOT_FOUND The given variable was not found in > + ProtectedVariableLib. > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibRefresh ( > + IN VARIABLE_HEADER *Variable, > + IN UINTN VariableSize, > + IN UINT64 StoreIndex, > + IN BOOLEAN RefreshData > + ) > +{ > + EFI_STATUS Status; > + PROTECTED_VARIABLE_INFO VarInfo; > + PROTECTED_VARIABLE_GLOBAL *Global; > + VARIABLE_DIGEST *VarDig; > + > + (VOID)GetProtectedVariableGlobal (&Global); > + > + ZeroMem ((VOID *)&VarInfo, sizeof (VarInfo)); > + VarInfo.Buffer =3D Variable; > + VarInfo.StoreIndex =3D VAR_INDEX_INVALID; > + VarInfo.Flags.Auth =3D Global->Flags.Auth; > + > + Status =3D GET_CNTX (Global)->GetVariableInfo (&VarInfo); > + ASSERT_EFI_ERROR (Status); > + > + VarDig =3D FindVariableInternal (Global, &VarInfo, FALSE); > + if (VarDig =3D=3D NULL) { > + ASSERT (VarDig !=3D NULL); > + return EFI_NOT_FOUND; > + } > + > + if (StoreIndex !=3D VAR_INDEX_INVALID) { > + VarDig->StoreIndex =3D StoreIndex; > + } > + > + if (RefreshData) { > + if (VarDig->CacheIndex =3D=3D VAR_INDEX_INVALID) { > + VarDig->CacheIndex =3D (EFI_PHYSICAL_ADDRESS)(UINTN) > + AllocatePool (MAX_VARIABLE_SIZE); > + } > + > + CopyMem (GET_BUFR (VarDig->CacheIndex), Variable, VariableSize); > + } > + > + // > + // Information should stay the same other than following ones. > + // > + VarDig->State =3D VarInfo.Header.State; > + VarDig->DataSize =3D (UINT32)VarInfo.Header.DataSize; > + > + return EFI_SUCCESS; > +} > + > +/** > + > + Determine if the variable is the HMAC variable > + > + @param VariableName Pointer to variable name. > + > + @return TRUE Variable is HMAC variable > + @return FALSE Variable is not HMAC variable > + > +**/ > +BOOLEAN > +ProtectedVariableLibIsHmac ( > + IN CHAR16 *VariableName > + ) > +{ > + INTN Result; > + > + Result =3D StrnCmp ( > + METADATA_HMAC_VARIABLE_NAME, > + VariableName, > + METADATA_HMAC_VARIABLE_NAME_SIZE > + ); > + > + if (Result =3D=3D 0) { > + return TRUE; > + } > + > + return FALSE; > +} > diff --git > a/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c > b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c > new file mode 100644 > index 000000000000..4591d1cd59e5 > --- /dev/null > +++ > b/SecurityPkg/Library/ProtectedVariableLib/ProtectedVariableSmmRuntime.c > @@ -0,0 +1,233 @@ > +/** @file > + Implemention of ProtectedVariableLib for BootService/Runtime use cases= . > + > +Copyright (c) 2022, Intel Corporation. All rights reserved.
> +SPDX-License-Identifier: BSD-2-Clause-Patent > + > +**/ > + > +#include > +#include > + > +#include "Library/MemoryAllocationLib.h" > +#include "Library/UefiBootServicesTableLib.h" > +#include "Library/UefiRuntimeLib.h" > +#include "ProtectedVariableInternal.h" > + > +EFI_EVENT mVaChangeEvent =3D NULL; > + > +PROTECTED_VARIABLE_CONTEXT_IN mRtVariableContextIn =3D { > + PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION, > + sizeof (PROTECTED_VARIABLE_CONTEXT_IN), > + 0, > + FromRuntimeModule, > + NULL, > + NULL, > + NULL, > + NULL, > + NULL > +}; > + > +PROTECTED_VARIABLE_GLOBAL mRtProtectedVariableGlobal =3D { > + PROTECTED_VARIABLE_CONTEXT_OUT_STRUCT_VERSION, > + sizeof (PROTECTED_VARIABLE_GLOBAL), > + { 0 }, > + { 0 }, > + 0, > + 0, > + 0, > + 0, > + 0, > + 0, > + { 0, 0, 0 }, > + 0, > + 0, > + { 0, 0, 0, 0, 0, 0} > +}; > + > +/** > + > + Get global data structure used to process protected variable. > + > + @param[out] Global Pointer to global configuration data. > + > + @retval EFI_SUCCESS Get requested structure successfully. > + > +**/ > +EFI_STATUS > +EFIAPI > +GetProtectedVariableGlobal ( > + OUT PROTECTED_VARIABLE_GLOBAL **Global OPTIONAL > + ) > +{ > + if (Global !=3D NULL) { > + mRtProtectedVariableGlobal.ContextIn =3D GET_ADRS > (&mRtVariableContextIn); > + *Global =3D &mRtProtectedVariableGlobal= ; > + } > + > + return EFI_SUCCESS; > +} > + > +/** > + Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. > + > + This is a notification function registered on > EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. > + It convers pointer to new virtual address. > + > + @param[in] Event Event whose notification function is being in= voked. > + @param[in] Context Pointer to the notification function's contex= t. > + > +**/ > +VOID > +EFIAPI > +VirtualAddressChangeEvent ( > + IN EFI_EVENT Event, > + IN VOID *Context > + ) > +{ > + if (mRtVariableContextIn.FindVariableSmm !=3D NULL) { > + EfiConvertPointer (0x0, (VOID **)&mRtVariableContextIn.FindVariableS= mm); > + } > + > + if (mRtVariableContextIn.GetVariableInfo !=3D NULL) { > + EfiConvertPointer (0x0, (VOID **)&mRtVariableContextIn.GetVariableIn= fo); > + } > + > + if (mRtVariableContextIn.GetNextVariableInfo !=3D NULL) { > + EfiConvertPointer (0x0, (VOID > **)&mRtVariableContextIn.GetNextVariableInfo); > + } > + > + if (mRtVariableContextIn.UpdateVariableStore !=3D NULL) { > + EfiConvertPointer (0x0, (VOID > **)&mRtVariableContextIn.UpdateVariableStore); > + } > + > + EfiConvertPointer (0x0, (VOID **)&mRtVariableContextIn); > + if (mRtProtectedVariableGlobal.VariableCache !=3D 0) { > + EfiConvertPointer (0x0, (VOID > **)&mRtProtectedVariableGlobal.VariableCache); > + } > + > + EfiConvertPointer (0x0, (VOID **)&mRtProtectedVariableGlobal); > +} > + > +/** > + > + Initialization for protected variable services. > + > + If this initialization failed upon any error, the whole variable servi= ces > + should not be used. A system reset might be needed to re-construct NV > + variable storage to be the default state. > + > + @param[in] ContextIn Pointer to variable service context needed by > + protected variable. > + > + @retval EFI_SUCCESS Protected variable services are read= y. > + @retval EFI_INVALID_PARAMETER If ContextIn =3D=3D NULL or somethin= g > missing or > + mismatching in the content in Contex= tIn. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibInitialize ( > + IN PROTECTED_VARIABLE_CONTEXT_IN *ContextIn > + ) > +{ > + if ( (ContextIn =3D=3D NULL) > + || (ContextIn->StructVersion !=3D > PROTECTED_VARIABLE_CONTEXT_IN_STRUCT_VERSION) > + || (ContextIn->FindVariableSmm =3D=3D NULL) > + || (ContextIn->GetVariableInfo =3D=3D NULL)) > + { > + return EFI_INVALID_PARAMETER; > + } > + > + CopyMem (&mRtVariableContextIn, ContextIn, sizeof > (mRtVariableContextIn)); > + > + // > + // Register the event to convert the pointer for runtime. > + // > + gBS->CreateEventEx ( > + EVT_NOTIFY_SIGNAL, > + TPL_NOTIFY, > + VirtualAddressChangeEvent, > + NULL, > + &gEfiEventVirtualAddressChangeGuid, > + &mVaChangeEvent > + ); > + > + return EFI_SUCCESS; > +} > + > +/** > + > + Prepare for variable update. > + > + Not supported in DXE phase. > + > + @retval EFI_UNSUPPORTED Updating variable is not supported. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibWriteInit ( > + VOID > + ) > +{ > + ASSERT (FALSE); > + return EFI_UNSUPPORTED; > +} > + > +/** > + > + Update a variable with protection provided by this library. > + > + Not supported in DXE phase. > + > + @param[in,out] CurrVariable Variable to be updated. It's NULL = if > + adding a new variable. > + @param[in] CurrVariableInDel In-delete-transition copy of updat= ing > variable. > + @param[in,out] NewVariable Buffer of new variable data or > + Buffer of "MetaDataHmacVar" and ne= w variable > (encrypted). > + @param[in,out] NewVariableSize Size of NewVariable or > + Size of (encrypted) NewVariable an= d "MetaDataHmacVar". > + > + @retval EFI_UNSUPPORTED Not support updating variable. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibUpdate ( > + IN OUT VARIABLE_HEADER *CurrVariable, > + IN VARIABLE_HEADER *CurrVariableInDel, > + IN OUT VARIABLE_HEADER *NewVariable, > + IN OUT UINTN *NewVariableSize > + ) > +{ > + ASSERT (FALSE); > + return EFI_UNSUPPORTED; > +} > + > +/** > + > + Finalize a variable updating after it's written to NV variable storage > + successfully. > + > + (Not supported for BootService/Runtime use cases.) > + > + @param[in] NewVariable Buffer of new variables and > MetaDataHmacVar. > + @param[in] VariableSize Size of buffer pointed by NewVariabl= e. > + @param[in] StoreIndex StoreIndex to NV variable storage fr= om where > the new > + variable and MetaDataHmacVar have be= en written. > + > + @retval EFI_UNSUPPORTED Not supported for BootService/Runtim= e use > cases. > + > +**/ > +EFI_STATUS > +EFIAPI > +ProtectedVariableLibWriteFinal ( > + IN VARIABLE_HEADER *NewVariable, > + IN UINTN VariableSize, > + IN UINT64 StoreIndex > + ) > +{ > + ASSERT (FALSE); > + return EFI_UNSUPPORTED; > +} > -- > 2.35.1.windows.2