On Thu, Sep 27, 2018 at 04:07:34PM +0100, Grant Likely wrote:
- In related news, I'm considering proposing a "SetVariable on Disk" analogous
- to the current Capsule on Disk [UEFI]_ 8.5.5.
- That would allow the OS to write a standard format variable update file to
- the ESP that firmware can read, update, and clear at boot time.
- However, this could also be implemented using an OS provided variable-update
- UEFI application.
It doesn't need to be *analogous* to Capsule on Disk - that's already exactly the mechanism we're looking for. We just have to define a data structure to go in the capsule and a GUID to identify it. If we're careful we could probably use the same GUID and the same format for the config table to hand off boot-time generated variables to the OS.
That is a really good idea. Keeps it nice and simple.
Just brainstorming here, but I think when we have shared storage like eMMC, there's a fairly compelling story along these lines:
- UEFI writes a capsule to an EFI Config Table during boot with any generated variables as well as any persistent variables stored on e.g. an eMMC partition it sets as write protected during ExitBootServices()
- efivarfs picks up that capsule during boot and uses that as its seed data (maybe it uses it as is, maybe it translates it to some internal format and frees the ram back to the allocator. Doesn't make much difference.)
Wait, you've lost me. Are you suggesting that the OS read the capsule to get variables instead of using GetVariable()/GetNextVariableName()? I do not like the idea of having two different mechanisms for retrieving variables.
- for runtime updates, we do "best effort" at having the same security model as UEFI, and represent the changes in ram both in /sys/firmware/efi/efivars , as well as a capsule file in e.g. /sys/firmware/efi/efivars-updates.cap
Ah, clever. So that way the normal efibootmgr tool works, but userspace will still need to copy the new .cap from sysfs to the EFI, correct?
- during shutdown, we copy that .cap to the ESP as a Capsule on Disk
- during boot up, UEFI reads that .cap and applies the update to the storage. Any cases the OS was wrong about its "best effort" security model simply fail
Yes, completly agree here.
Alright, so I've taken a shot at this - here's my first attempt, let me know what's unclear/wrong/insane/etc :)
From: Peter Jones pjones@redhat.com Date: Thu, 11 Oct 2018 14:44:30 -0400 Subject: [PATCH] Update variable storage language
This patch updates the UEFI chapter of the spec, specifically the parts about UEFI variable storage. This language utilizes UEFI's existing Capsule Update on Disk and EFI Configuration table mechanisms, providing independent mechanisms for exporting variables to the OS and importing updates from the OS.
The mechanism for exporting variables from the firmware uses a UEFI Configuration Table rather than requiring the firmware to maintain the Capsule on Disk, so that a platform with no permanent storage can implement exporting variables to the OS without having to write to storage, and a system without permanent storage can implement exporting to the OS without having to implement importing from Capsule on Disk. To keep things simple, we do not specify Capsule on Disk as an export mechanism to the OS.
This text also specifies a de facto coherency protocol. As a result, in most cases requirements on the firmware producing the configuration table are "must" requirements, but they only apply if the export procedure is implemented. Likewise, the requirements on the OS to create a Variable Updates Capsule are mostly "should" requirements, but the requirements on the contents are "must" requirements. --- source/chapter2-uefi.rst | 237 ++++++++++++++++++++++++++++----------- 1 file changed, 174 insertions(+), 63 deletions(-)
diff --git a/source/chapter2-uefi.rst b/source/chapter2-uefi.rst index 0cbddff6b46..320d71d7456 100644 --- a/source/chapter2-uefi.rst +++ b/source/chapter2-uefi.rst @@ -196,66 +196,177 @@ command: Runtime Variable Access -----------------------
-.. todo:: - - There are many platforms where it is difficult to support SetVariable() for - non-volatile variables because the firmware cannot access storage after - ExitBootServices() is called. - e.g., If firmware accesses an eMMC device directly at runtime, it will - collide with transactions initiated by the OS. - Neither U-Boot nor Tianocore have a solution for accessing shared media for - variable updates. [#OPTEESupplicant]_ - - In these platforms SetVariable() calls with the EFI_VARIABLE_NON_VOLATILE - attribute set will work in boot services, but will fail in runtime services. - The [UEFI]_ specification doesn't address what to do in this situation. - We need feedback on options before writing this section of EBBR, or making a - proposal to modify UEFI. - - We need a solution that communicates to the OS that non-volatile variable - updates are not supported at runtime, and that defines the behaviour when - SetVariable() is called with the EFI_VARIABLE_NON_VOLATILE attribute. - - Presumably, the solution will require SetVariable() to return - EFI_INVALID_PARAMETER if called with the EFI_VARIABLE_NON_VOLATILE - attribute, but beyond that there are a number of options: - - #. Clear EFI_VARIABLE_NON_VOLATILE from all variables at ExitBootServices() - - If the platform is incapable of updating non-volatile variables from Runtime - Services then it must clear the EFI_VARIABLE_NON_VOLATILE attribute from all - non-volatile variables when ExitBootServices() is called. - - An OS can discover that non-volatile variables cannot be updated at - runtime by noticing that the NON_VOLATILE attribute is not set. - - #. Clear all variables at ExitBootServices() - - If the platform is incapable of updating non-volatile variables from Runtime - Services then it will clear all variables and return EFI_INVALID_PARAMETER - on all calls to SetVariable(). - - SUSE in particular currently uses this behaviour to decide whether or not - to treat the ESP as removable media. - - #. Advertise that SetVariable() doesn't work at runtime with another variable - - Platforms can check another variable to determine if they have this quirk, - perhaps by adding a new BootOptionSupport flag. - - This is not a complete list, and other options can still be proposed. We're - looking for feedback on what would be most faithful to the UEFI spec, and - would work for the OS distributions before filling out this section of the - specification. - - Comments can be sent to the boot-architecture@lists.linaro.org mailing list. - -.. [#OPTEESupplicant] It is worth noting that OP-TEE has a similar problem - regarding secure storage. - OP-TEE's chosen solution is to rely on an OS supplicant agent to perform - storage operations on behalf of OP-TEE. - The same solution may be applicable to solving the UEFI non-volatile - variable problem, but that approach is also not entirely UEFI compliant - because it requires additional OS support to work. - - https://github.com/OP-TEE/optee_os/blob/master/documentation/secure_storage.... +There are many platforms where it is difficult to implement SetVariable() for +non-volatile variables during runtime services because the firmware cannot +access storage after ExitBootServices() is called. + +e.g., If firmware accesses an eMMC device directly at runtime, it will +collide with transactions initiated by the OS. +Neither U-Boot nor Tianocore have a generic solution for accessing or updating +variables stored on shared media. [#OPTEESupplicant]_ + +If a platform does not implement modifying non-volatile variables with +SetVariable() after ExitBootServices(), then it must implement support for +discovering this during Boot Services via the "RuntimeServicesSupported" +variable (see UEFI Mantis 1961). + +Such a system may also support exporting the variable storage to the +kernel via a UEFI configuration table and re-loading it from a Capsule on +Disk as described in [UEFI]_ 8.5.5. If this is supported, the platform +must implement the following: + +- The firmware must provide BS variable named "CapsuleVariableSupport" + under the VARIABLE_STORAGE_GUID, with the following bits defined: + + #define EBBR_CAPSULE_VARIABLE_EXPORT 0x01 + #define EBBR_CAPSULE_VARIABLE_IMPORT 0x02 + #define EBBR_CAPSULE_VARIABLE_IMPORT_AUTH 0x04 + #define EBBR_CAPSULE_VARIABLE_IMPORT_AUTH_2 0x08 + #define EBBR_CAPSULE_VARIABLE_IMPORT_AUTH_3 0x10 + +- If the firmware supports exporting variables via a configuration table, + the EBBR_CAPSULE_VARIABLE_EXPORT bit must be set, and the firmware must + create a configuration table identified by the VARIABLE_STORAGE_GUID + (defined below) before any EFI applications are started, and must update it + any time a variable is altered via SetVariable(), until ExitBootServices() + has successfully returned. +- If the firmware supports importing non-volatile variables via a Capsule + on Disk, the EBBR_CAPSULE_VARIABLE_IMPORT bit must be set, and the + firmware must load its initial variable storage during boot services + from a capsule with the EFI_CAPSULE_HEADER.CapsuleGuid set to + VARIABLE_STORAGE_GUID. +- If the firmware supports authenticated variables, the bits + EBBR_CAPSULE_VARIABLE_IMPORT_AUTH, EBBR_CAPSULE_VARIABLE_IMPORT_AUTH_2, + and EBBR_CAPSULE_VARIABLE_IMPORT_AUTH_3 must be set to indicate support for + EFI_VARIABLE_AUTHENTICATION, EFI_VARIABLE_AUTHENTICATION_2, and + EFI_VARIABLE_AUTHENTICATION_3 descriptors defined in [UEFI]_ 8.2. +- If the CapsuleVariableSupport variable is not set, the OS must behave as if + all bits are 0. +- Any bits which are not present in the CapsuleVariableSupport variable must + be treated as 0. + +Variable storage data format +---------------------------- + +The Variable Configuration Table and the Variable Update Capsule structure +share the same data format, and are structured as a capsule update containing +a packed array of update records: + +#define VARIABLE_STORAGE_GUID \ + {0x1a3fb419, 0x2171, 0x458d,\ + {0xb8, 0xb4, 0xbe, 0xa3, 0x0c, 0x9f, 0x6b, 0xab }} + +typedef struct { + CHAR16[64] VariableName; + EFI_GUID VendorGuid; + UINT32 Attributes; + UINT32 DataSize; + UINT8[] Data; +} EBBR_VARIABLE; + +typedef struct { + EFI_CAPSULE_HEADER Header; + UINT8[Header.HeaderSize - sizeof(EFI_CAPSULE_HEADER)] Reserved; + EBBR_VARIABLE[] Variables; +} EBBR_VARIABLE_BUNDLE __attribute__((__packed__)); + +- EBBR_VARIABLE_BUNDLE.Header.CapsuleGuid must be VARIABLE_STORAGE_GUID +- EBBR_VARIABLE_BUNDLE.Reserved may be 0 or more bytes. +- EBBR_VARIABLE_BUNDLE.Header.HeaderSize is equal to the starting offset of + the EBBR_VARIABLE_BUNDLE.Variables array. +- EBBR_VARIABLE_BUNDLE.Variables may be 0 or more bytes. +- EBBR_VARIABLE_BUNDLE.Header.CapsuleImageSize is the full size of the capsule + including the Header, Reserved, and all Variable array members. +- EBBR_VARIABLE_BUNDLE.Header.Flags must not have any of the following set: + CAPSULE_FLAGS_INITIATE_RESET +- EBBR_VARIABLE_BUNDLE.Header.Flags should have all of the following set: + CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE + +Variable Configuration Table creation +------------------------------------- + +Any platform firmware which supports EBBR_CAPSULE_VARIABLE_EXPORT must +install a UEFI Configuration Table with all appropriate variables specified +in [UEFI]_ 3.3, as well as any variables which have been imported from a +Variable Update Capsule or set through SetVariable(). + +- The platform firmware must not include multiple entries for the same + variable. +- The platform should avoid storing any secrets in variables, including + variables without EFI_VARIABLE_RUNTIME_SERVICES set. + +Variable Configuration Table processing +--------------------------------------- + +When processing the Variable Configuration Table, the OS must treat each +EBBR_VARIABLE_BUNDLE.Variable entry as if it were a call to SetVariable() +before ExitBootServices() has been called: + +- The variables are processed according to the requirements in [UEFI]_ 8.2 +- Any update which would result in SetVariable() returning an error must + be ignored. +- The OS should preserve entries with EFI_VARIABLE_NON_VOLATILE set but + EFI_VARIABLE_RUNTIME_SERVICES unset, and save them to a Variable Updates + Capsule before system reset. +- Any entry without EFI_VARIABLE_RUNTIME_SERVICES set must not be exposed to + consumers of GetVariable(). +- Any entry authenticated with an Authentication Descriptor the OS does not + support should be preserved, but must not be exposed to consumers of + GetVariable(). Any following entry for any such variable must be treated + the same. +- All authenticated variables should have their Authentication Descriptors + preserved, but only the encapsulated data should be presented through + GetVariable()-like interfaces. +- The OS must take measures to prevent data in variables without + EFI_VARIABLE_RUNTIME_SERVICES set from being exposed to unprivileged tasks. + +Runtime Processing +------------------ + +The OS must take certain measures during runtime operation to insure +consistency: + +- The OS must keep a log of any updates to variables, including delete, + append, and create operations. +- The OS should attempt to simulate each operation as it would be applied + during the Variable Updates Capsule processing, in order to maintain a + view which is coherent across a reset. + +Variable Updates Capsule creation +--------------------------------- + +Before system reset, the OS should create a Variable Updates Capsule as a +Capsule on Disk defined in [UEFI]_ 8.5.5 . If a platform supports both +EBBR_CAPSULE_VARIABLE_EXPORT and EBBR_CAPSULE_VARIABLE_IMPORT, the capsule +should preserve the following from the Variable Configuration Table, if it +was present: + +- EBBR_VARIABLE_BUNDLE.Header.HeaderSize, EBBR_VARIABLE_BUNDLE.Header.Flags, + and EBBR_VARIABLE_BUNDLE.Reserved fields +- Any variables with EFI_VARIABLE_NON_VOLATILE set, including those without + EFI_VARIABLE_RUNTIME_SERVICES set +- Any variables authenticated with Authentication Descriptors not supported + by the OS. +- Runtime updates to authenticated variables must be included individually, + including any authenticated deletion. +- Runtime operations on newly created variables which are not authenticated + may be coalesced to a single entry. + +Variable Updates Capsule processing +----------------------------------- + +During boot, the system firmware must create the variables specified in [UEFI]_ +3.3 before processing the capsule update, and it must ensure that the variables +implemented in the UEFI spec are treated as specified at all times. When +processing a Variable Updates Capsule, the firmware must process each record in +the order they appear in the Variables array as if each were a call to +SetVariable() after ExitBootServices(): + +- The variables are processed according to the requirements in [UEFI]_ 8.2 +- Any update without the EFI_VARIABLE_NON_VOLATILE attribute set must be + ignored. +- Any update which would result in SetVariable() returning an error must + be ignored. +- Any variable authenticated with an unsupported Authentication Descriptor + not supported by the platform must be ignored.