]>
Commit | Line | Data |
---|---|---|
031e5cce SM |
1 | # UEFI shim bootloader secure boot life-cycle improvements |
2 | ||
3 | ## Background | |
4 | ||
5 | In the PC ecosystem, [UEFI Secure Boot](https://docs.microsoft.com/en-us/windows-hardware/design/device-experiences/oem-secure-boot) | |
6 | is typically configured to trust 2 authorities for signing UEFI boot code, the | |
7 | Microsoft UEFI Certificate Authority (CA) and Windows CA. When malicious or | |
8 | security compromised code is detected, 2 revocation mechanisms are provided by | |
8529e0f7 | 9 | compatible UEFI implementations: signing certificate or image hash. The UEFI |
031e5cce SM |
10 | Specification does not provides any well tested additional revocation |
11 | mechanisms. | |
12 | ||
13 | Signing certificate revocation is not practical for the Windows and Microsoft | |
14 | UEFI CAs because it would revoke too many UEFI applications and drivers, | |
15 | especially for Option ROMs. This is true even for the UEFI CA leaf certificates | |
16 | as they generally sign 1 entire year of UEFI images. For this reason UEFI | |
17 | revocations have, until recently, been performed via image hash. | |
18 | ||
19 | The UEFI shim bootloader provides a level of digital signature indirection, | |
20 | enabling more authorities to participate in UEFI Secure Boot. Shims' | |
21 | certificates typically sign targeted UEFI applications, enabling | |
22 | certificate-based revocation where it makes sense. As part of the recent | |
23 | "BootHole" security incident | |
24 | [CVE-2020-10713](https://nvd.nist.gov/vuln/detail/CVE-2020-10713), 3 | |
25 | certificates and 150 image hashes were added to the UEFI Secure Boot revocation | |
26 | database `dbx` on the popular x64 architecture. This single revocation event | |
27 | consumes 10kB of the 32kB, or roughly one third, of revocation storage | |
28 | typically available on UEFI platforms. Due to the way that UEFI merges | |
29 | revocation lists, this plus prior revocation events can result in a `dbx` that | |
30 | is almost 15kB in size, approaching 50% capacity. | |
31 | ||
32 | The large size of the BootHole revocation event is due to the inefficiency of | |
33 | revocation by image hash when there is a security vulnerability in a popular | |
34 | component signed by many authorities, sometimes with many versions. | |
35 | ||
36 | Coordinating the BootHole revocation has required numerous person months of | |
37 | planning, implementation, and testing multiplied by the number of authorities, | |
38 | deployments, & devices. It is not yet complete, and we anticipate many months | |
39 | of upgrades and testing with a long tail that may last years. | |
40 | ||
41 | Additionally, when bugs or features require updates to UEFI shim, the number of | |
42 | images signed are multiplied by the number of authorities. | |
43 | ||
44 | ## Summary | |
45 | ||
46 | Given the tremendous cost and disruption of a revocation event like BootHole, | |
47 | and increased activity by security researchers in the UEFI Secure Boot space, | |
48 | we should take action to greatly improve this process. Updating revocation | |
49 | capabilities in the UEFI specification and system firmware implementations will | |
50 | take years to deploy into the ecosystem. As such, the focus of this document is | |
51 | on improvements that can be made to the UEFI shim, which are compatible with | |
52 | existing UEFI implementations. Shim can move faster than the UEFI system | |
53 | firmware ecosystem while providing large impact to the in-market UEFI Secure | |
54 | Boot ecosystem. | |
55 | ||
56 | The background section identified 2 opportunities for improvement: | |
57 | ||
58 | 1. Improving the efficiency of revocation when a number of versions have a | |
59 | vulnerability | |
60 | ||
61 | * For example, a vulnerability spans some number of versions, it might be | |
62 | more efficient to be able to revoke by version, and simply modify the | |
63 | revocation entry to modify the version each time a vulnerability is | |
64 | detected. | |
65 | ||
66 | 2. Improving the efficiency of revocation when there are many shim variations | |
67 | ||
68 | * For example, a new shim is released to address bugs or adding features. In | |
69 | the current model, the number of images signed are multiplied by the | |
70 | number of authorities as they sign shims to gain the fixes and features. | |
71 | ||
72 | Microsoft has brainstormed with partners possible solutions for evaluation and | |
73 | feedback: | |
74 | ||
75 | 1. To improve revocation when there are many versions of vulnerable boot | |
76 | images, shim, GRUB, or otherwise, investigate methods of revoking by image | |
77 | metadata that includes generation numbers. Once targeting data is | |
78 | established (e.g. Company foo, product bar, boot component zed), each | |
79 | revocation event ideally edits an existing entry, increasing the trusted | |
80 | minimum security generation. | |
81 | ||
82 | 2. To improve revocation when there is a shim vulnerability, and there are many | |
83 | shim images, standardize on a single image shared by authorities. Each | |
84 | release of bug fixes and features result in 1 shim being signed, compressing | |
85 | the number by dozens. This has the stellar additional benefit of reducing | |
86 | the number of shim reviews, which should result in much rejoicing. The | |
87 | certificates used by a vendor to sign individual boot components would be | |
88 | picked up from additional PE files that are signed either by a shim-specific | |
89 | key controlled by Microsoft, or controlled by a vendor, but used only to | |
90 | sign additional key files. This key built into shim is functionally similar | |
91 | to a CA certificate. The certificates built into shim can be revoked by | |
92 | placing the image hash into dbx, similar to the many shim solution we have | |
93 | today. | |
94 | ||
95 | ## Proposals | |
96 | ||
97 | This document focuses on the shim bootloader, not the UEFI specification or | |
98 | updates to UEFI firmware. | |
99 | ||
100 | ### Generation Number Based Revocation | |
101 | ||
102 | Microsoft may refer to this as a form of UEFI Secure Boot Advanced Targeting | |
103 | (SBAT), perhaps to be named EFI_CERT_SBAT. This introduces a mechanism to | |
104 | require a specific level of resistance to UEFI Secure Boot bypasses. | |
105 | ||
106 | #### Generation-Based Revocation Overview | |
107 | ||
108 | Metadata that includes the vendor, product family, product, component, version | |
109 | and generation are added to artifacts. This metadata is protected by the | |
110 | digital signature. New image authorization data structures, akin to the | |
111 | EFI_CERT_foo EFI_SIGNATURE_DATA structure (see Signature Database in UEFI | |
112 | specification), describe how this metadata can be incorporated into allow or | |
113 | deny lists. In a simple implementation, 1 SBAT entry with security generations | |
114 | could be used for each revocable boot module, replacing many image hashes with | |
115 | 1 entry with security generations. To minimize the size of EFI_CERT_SBAT, the | |
116 | signature owner field might be omitted, and recommend that either metadata use | |
117 | shortened names, or perhaps the EFI_CERT_SBAT contains a hash of the | |
118 | non-generation metadata instead of the metadata itself. | |
119 | ||
120 | Ideally, servicing of the image authorization databases would be updated to | |
121 | support replacement of individual EFI_SIGNATURE_DATA items. However, if we | |
122 | assume that new UEFI variable(s) are used, to be serviced by 1 entity per | |
123 | variable (no sharing), then the existing, in-market SetVariable(), without the | |
124 | APPEND attribute, could be used. Microsoft currently issues dbx updates | |
125 | exclusively with the APPEND attribute under the assumption that multiple | |
126 | entities might be servicing dbx. When a new revocation event takes place, | |
127 | rather than increasing the size of variables with image hashes, existing | |
128 | variables can simply be updated with new security generations, consuming no | |
129 | additional space. This constrains the number of entries to the number of unique | |
130 | boot components revoked, independent of generations revoked. The solution may | |
131 | support several major/minor versions, limiting revocation to build/security | |
132 | generations, perhaps via wildcards. | |
133 | ||
134 | While previously the APPEND attribute guaranteed that it would not be possible | |
135 | to downgrade the set of revocations on a system using a previously signed | |
136 | variable update, this guarantee can also be accomplished by setting the | |
137 | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute. This will verify | |
138 | that the timestamp value of the signed data is later than the current timestamp | |
139 | value associated with the data currently stored in that variable. | |
140 | ||
141 | #### Generation-Based Revocation Scenarios | |
142 | ||
8529e0f7 | 143 | **Products** (**not** vendors, a vendor can have multiple products or even pass a |
031e5cce SM |
144 | product from one vendor to another over time) are assigned a name. Product |
145 | names can specify a specific version or refer to the entire product family. For | |
146 | example mydistro and mydistro,12. | |
147 | ||
8529e0f7 | 148 | **Components** that are used as a link in the UEFI Secure Boot chain of trust are |
031e5cce SM |
149 | assigned names. Examples of components are shim, GRUB, kernel, hypervisors, etc. |
150 | ||
8529e0f7 SM |
151 | Below is an example of a product and component, both in the same `sbat.csv` file. `sbat` |
152 | defines the version of the format of the revocation metadata itself. | |
153 | `grub.acme` is an example of a product name. | |
154 | ``` | |
155 | sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md | |
156 | grub.acme,1,Acme Corporation,grub,1.96-8191,https://acme.arpa/packages/grub | |
157 | ``` | |
158 | ||
031e5cce SM |
159 | We could conceivably support sub-components, but it's hard to conceive of a |
160 | scenario that would trigger a UEFI variable update that wouldn't justify a | |
161 | hypervisor or kernel re-release to enforce that sub-component level from there. | |
162 | Something like a "level 1.5 hypervisor" that can exist between different kernel | |
163 | generations can be considered its own component. | |
164 | ||
8529e0f7 | 165 | Each component is assigned a **minimum global generation number**. Vendors signing |
031e5cce SM |
166 | component binary artifacts with a specific global generation number are |
167 | required to include fixes for any public or pre-disclosed issue required for | |
168 | that generation. Additionally, in the event that a bypass only manifests in a | |
169 | specific product's component, vendors may ask for a product-specific generation | |
170 | number to be published for one of their product's components. This avoids | |
171 | triggering an industry wide re-publishing of otherwise safe components. | |
172 | ||
8529e0f7 SM |
173 | In the example above, 1 is sbat's minimum global generation number. |
174 | ||
175 | A **product-specific minimum generation number** only applies to the instance of | |
031e5cce SM |
176 | that component that is signed with that product name. Another product's |
177 | instance of the same component may be installed on the same system and would | |
178 | not be subject to the other product's product-specific minimum generation | |
179 | number. However, both of those components will need to meet the global minimum | |
180 | generation number for that component. A very likely scenario would be that a | |
181 | product is shipped with an incomplete fix required for a specific minimum | |
182 | generation number, but is labeled with that number. Rather than having the | |
183 | entire industry that uses that component re-release, just that product's | |
184 | minimum generation number would be incremented and that product's component | |
185 | re-released along with a UEFI variable update specifying that requirement. | |
186 | ||
8529e0f7 SM |
187 | In the example above, 1 is grub.acme's product-specific minimum generation number. |
188 | ||
031e5cce SM |
189 | The global and product-specific generation number name spaces are not tied to |
190 | each other. The global number is managed externally, and the vast majority of | |
191 | products will never publish a minimum product-specific generation number for | |
192 | any of their components. Unspecified, more specific generation numbers are | |
193 | treated as 0. | |
194 | ||
195 | A minimum feature set, for example enforced kernel lock down, may be required | |
196 | as well to sign and label a component with a specific generation number. As | |
197 | time goes on, it is likely that the minimum feature set required for the | |
198 | currently valid generation number will expand. (For example, hypervisors | |
199 | supporting UEFI Secure Boot guests may at some point require memory encryption | |
200 | or similar protection mechanism.) | |
201 | ||
202 | The footprint of the UEFI variable payload will expand as product-specific | |
203 | generation numbers ahead of the global number are added. However, it will | |
204 | shrink again as the global number for that component is incremented again. The | |
205 | expectation is that a product-specific or vendor-specific generation number is | |
206 | a rare event, and that the generation number for the upstream code base will | |
207 | suffice in most cases. | |
208 | ||
209 | A product-specific generation number is needed if a CVE is fixed in code that | |
210 | **only** exists in a specific product's branch. This would either be something | |
211 | like product-specific patches, or a mis-merge that only occurred in that | |
212 | product. Setting a product-specific generation number for such an event | |
213 | eliminates the need for other vendors to have to re-release the binaries for | |
214 | their products with an incremented global number. | |
215 | ||
216 | However, once the global number is bumped for the next upstream CVE fix there | |
217 | will be no further need to carry that product-specific generation number. | |
218 | Satisfying the check of the global number will also exclude any of the older | |
219 | product-specific binaries. | |
220 | ||
221 | For example: There is a global CVE disclosure and all vendors coordinate to | |
222 | release fixed components on the disclosure date. This release bumps the global | |
223 | generation number for GRUB to 4. | |
224 | ||
225 | SBAT revocation data would then require a GRUB with a global generation number | |
226 | of 4. | |
227 | ||
228 | However, Vendor C mis-merges the patches into one of their products and does | |
229 | not become aware of the fact that this mis-merge created an additional | |
230 | vulnerability until after they have published a signed binary in that, | |
231 | vulnerable, state. | |
232 | ||
233 | Vendor C's GRUB binary can now be used to compromise anyone's system. | |
234 | ||
235 | To remedy this, Vendor C will release a fixed binary with the same global | |
236 | generation number and the product-specific generation number set to 1. | |
237 | ||
238 | SBAT revocation data would then require a GRUB with a global generation number | |
239 | of 4, as well as a product-specific generation number of 1 for the product that | |
240 | had the vulnerable binary. | |
241 | ||
242 | If and when there is another upstream fix for a CVE that would bump the global | |
243 | number, this product-specific number can be dropped from the UEFI revocation | |
244 | variable. | |
245 | ||
246 | If this same Vendor C has a similar event after the global number is | |
8529e0f7 SM |
247 | incremented, they would again set their product-specific or **version-specific |
248 | number** to 1. If they have a second event on the same component, they would | |
031e5cce SM |
249 | set their product-specific or version-specific number to 2. |
250 | ||
251 | In such an event, a vendor would set the product-specific or version-specific | |
252 | generation number based on whether the mis-merge occurred in all of their | |
253 | branches or in just a subset of them. The goal is generally to limit end | |
254 | customer impact with as few re-releases as possible, while not creating an | |
255 | unnecessarily large UEFI revocation variable payload. | |
256 | ||
8529e0f7 | 257 | | | prior to<br>disclosure\* | after<br>disclosure | after Vendor C's<br>first update | after Vendor C's<br>second update | after next global<br>disclosure | |
fd2d9f03 SM |
258 | |--------------------------------------------------------------------------------------|--------------------------|---------------------|----------------------------------|-----------------------------------|---------------------------------| |
259 | | GRUB global<br>generation number in<br>artifacts .sbat section | 3 | 4 | 4 | 4 | 5 | | |
260 | | Vendor C's product-specific<br>generation number in artifact's<br>.sbat section | 1 | 1 | 2 | 3 | 1 | | |
261 | | GRUB global<br>generation number in<br>UEFI SBAT revocation variable | 3 | 4 | 4 | 4 | 5 | | |
262 | | Vendor C's product-specific<br>generation number in<br>UEFI SBAT revocation variable | not set | not set | 2 | 3 | not set | | |
8529e0f7 SM |
263 | |
264 | \* A disclosure is the event/date where a CVE and fixes for it are made public. | |
031e5cce SM |
265 | |
266 | The product-specific generation number does not reset and continues to | |
8529e0f7 | 267 | monotonically increase over the course of these non-global events. Continuity of more |
031e5cce SM |
268 | specific generation numbers must be maintained in this way in order to satisfy |
269 | checks against older revocation data. | |
270 | ||
271 | The variable payload will be stored publicly in the shim source base and | |
272 | identify the global generation associated with a product or version-specific | |
273 | one. The payload is also built into shim to additionally limit exposure. | |
274 | ||
8529e0f7 SM |
275 | At this time of writing, all version-numbers are set to 1. Presumably at some point, |
276 | updated numbers will be published on the respective websites of the associated vendors | |
277 | and components. | |
278 | ||
031e5cce SM |
279 | #### Retiring Signed Releases |
280 | ||
281 | Products that have reached the end of their support life by definition no | |
282 | longer receive patches. They are also generally not examined for CVEs. Allowing | |
283 | such unsupported products to continue to participate in UEFI Secure Boot is at | |
284 | the very least questionable. If an EoSL product is made up of commonly used | |
285 | components, such as the GRUB and the Linux kernel, it is reasonable to assume | |
286 | that the global generation numbers will eventually move forward and exclude | |
287 | those products from booting on a UEFI Secure Boot enabled system. However a | |
288 | product made up of GRUB and a closed source kernel is just as conceivable. In | |
289 | that case the kernel version may never move forward once the product reaches | |
8529e0f7 | 290 | its end of support. Therefore it is recommended that the product-specific |
031e5cce SM |
291 | generation number be incremented past the latest one shown in any binary for |
292 | that product, effectively disabling that product on UEFI Secure Boot enabled | |
293 | systems. | |
294 | ||
295 | A subset of this case would be a beta-release that may contain eventually | |
296 | abandoned, experimental, kernel code. Such releases should have their | |
297 | product-specific generation numbers incremented past the latest one shown in | |
298 | any released, or unreleased, binary signed with a production key. | |
299 | ||
300 | Until a release is retired in this manner, vendors are responsible for keeping | |
301 | up with fixes for CVEs and ensuring that any known signed binaries containing | |
302 | known CVEs are denied from booting on UEFI Secure Boot enabled systems via the | |
303 | most up to date UEFI metadata. | |
304 | ||
305 | #### Vendor Key Files | |
306 | ||
307 | Even prior to or without moving to one-shim, it is desirable to get every | |
308 | vendor onto as few shims as possible. Ideally a vendor would have a single shim | |
309 | signed with their certificate embedded and then use that certificate to sign | |
fd2d9f03 | 310 | additional `<Vendor>_key.EFI` key files that then contain all the keys that the |
031e5cce SM |
311 | individual components for their products are signed with. This file name needs |
312 | to be registered at the time of shim review and should not be changed without | |
313 | going back to a shim review. A vendor should be able to store as many | |
314 | certificated (or a CA certificate) as they need for all the components of all | |
315 | of their products. Older versions of this file can be revoked via SBAT. In | |
316 | order to limit the footprint of the SBAT revocation metadata, it is vital that | |
317 | vendors do not create additional key files beyond what they have been approved | |
318 | for at shim review. | |
319 | ||
320 | #### Key Revocations | |
321 | ||
322 | Since Vendor Product keys are brought into Shim as signed binaries, generation | |
323 | numbering can and should be used to revoke them in case of a private key | |
324 | compromise. | |
325 | ||
326 | #### Kernel support for SBAT | |
327 | ||
328 | The initial SBAT implementation will add SBAT metadata to Shim and GRUB and | |
329 | enforce SBAT on all components labeled with it. Until a component (e.g. the | |
8529e0f7 SM |
330 | Linux kernel) gains SBAT metadata it can not be revoked via SBAT, but only by |
331 | revoking the keys signing that component. These keys will live in | |
031e5cce SM |
332 | separate, product-specific signed PE files that contain **only** the |
333 | certificate and SBAT metadata for the key files. These key files can then be | |
334 | revoked via SBAT in order to invalidate and replace a specific key. While | |
335 | certificates built into Shim can be revoked via SBAT and Shim introspection, | |
336 | this practice would still result in a proliferation of Shim binaries that would | |
337 | need to be revoked via dbx in the event of an early Shim code bug. Therefore, | |
338 | SBAT must be used in conjunction with separate Vendor Product Key binaries. | |
339 | ||
340 | At the time of this writing, revoking a Linux kernel with a lockdown compromise | |
341 | is not spelled out as a requirement for shim signing. In fact, with limited dbx | |
342 | space and the size of the attack surface for lockdown it would be impractical | |
343 | do so without SBAT. With SBAT it should be possible to raise the bar, and treat | |
344 | lockdown bugs that would allow a kexec of a tampered kernel as revocations. | |
345 | ||
346 | #### Kernels execing other kernels (aka kexec, fast reboot) | |
347 | ||
348 | It is expected that kexec and other similar implementations of kernels spawning | |
349 | other kernels will eventually consume and honor SBAT metadata. Until they do, | |
350 | the same Vendor Product Key binary based revocation will need to be used for | |
351 | them. | |
352 | ||
353 | #### Generation-Based Revocation Metadata | |
354 | ||
355 | Adding a .sbat section containing the SBAT metadata structure to PE images. | |
356 | ||
fd2d9f03 SM |
357 | | field | meaning | |
358 | |----------------------|----------------------------------------------------------------------------------| | |
359 | | component_name | the name we're comparing | | |
360 | | component_generation | the generation number for the comparison | | |
361 | | vendor_name | human readable vendor name | | |
362 | | vendor_package_name | human readable package name | | |
363 | | vendor_version | human readable package version (maybe machine parseable too, not specified here) | | |
364 | | vendor_url | url to look stuff up, contact, whatever. | | |
031e5cce SM |
365 | |
366 | The format of this .sbat section is comma separated values, or more | |
8529e0f7 | 367 | specifically ASCII encoded strings. |
031e5cce SM |
368 | |
369 | ## Example sbat sections | |
370 | ||
371 | For grub, a build from a fresh checkout of upstream might have the following in | |
372 | `.sbat`: | |
373 | ``` | |
374 | sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md | |
375 | grub,1,Free Software Foundation,grub,2.04,https://www.gnu.org/software/grub/ | |
376 | ``` | |
377 | ||
378 | A Fedora build believed to have exactly the same set of vulnerabilities plus | |
379 | one that was never upstream might have: | |
380 | ``` | |
381 | sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md | |
382 | grub,1,Free Software Foundation,grub,2.04,https://www.gnu.org/software/grub/ | |
383 | grub.fedora,1,The Fedora Project,grub2,2.04-31.fc33,https://src.fedoraproject.org/rpms/grub2 | |
384 | ``` | |
385 | ||
386 | Likewise, Red Hat has various builds for RHEL 7 and RHEL 8, all of which have | |
387 | something akin to the following in `.sbat`: | |
388 | ``` | |
389 | sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md | |
390 | grub,1,Free Software Foundation,grub,2.02,https://www.gnu.org/software/grub/ | |
391 | grub.fedora,1,Red Hat Enterprise Linux,grub2,2.02-0.34.fc24,mail:secalert@redhat.com | |
392 | grub.rhel,1,Red Hat Enterprise Linux,grub2,2.02-0.34.el7_2,mail:secalert@redhat.com | |
393 | ``` | |
394 | ||
395 | The Debian package believed to have the same set of vulnerabilities as upstream | |
396 | might have: | |
397 | ``` | |
398 | sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md | |
399 | grub,1,Free Software Foundation,grub,2.04,https://www.gnu.org/software/grub/ | |
400 | grub.debian,1,Debian,grub2,2.04-12,https://packages.debian.org/source/sid/grub2 | |
401 | ``` | |
402 | ||
403 | Another party known for less than high quality software who carry a bunch of | |
404 | out of tree grub patches on top of a very old grub version from before any of | |
405 | the upstream vulns were committed to the tree. They haven't ever had the | |
406 | upstream vulns, and in fact have never shipped any vulnerabilities. Their grub | |
407 | `.sbat` might have the following (which we'd be very suspect of signing, but | |
408 | hey, suppose it turns out to be correct): | |
409 | ``` | |
410 | sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md | |
411 | grub.acme,1,Acme Corporation,grub,1.96-8191,https://acme.arpa/packages/grub | |
412 | ``` | |
413 | ||
414 | At the same time, we're all shipping the same `shim-16` codebase, and in our | |
415 | `shim` builds, we all have the following in `.sbat`: | |
416 | ``` | |
417 | sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md | |
418 | shim,1,UEFI shim,shim,16,https://github.com/rhboot/shim | |
419 | ``` | |
420 | ||
421 | ## How to add .sbat sections | |
422 | ||
423 | Components that do not have special code to construct the final PE files can | |
424 | simply add this section using objcopy(1): | |
425 | ||
426 | ``` | |
427 | objcopy --set-section-alignment '.sbat=512' --add-section .sbat=sbat.csv foo.efi | |
428 | ||
429 | ``` | |
430 | ||
431 | Older versions of objcopy(1) do not support --set-section-alignment which is | |
432 | required to force the correct alignment expected from a PE file. As long as | |
433 | there is another step, later in the build process, such as an linker invocation | |
434 | that forces alignment, objcopy(1) does not need to align an intermediate file. | |
435 | ||
436 | #### UEFI SBAT Variable content | |
437 | ||
438 | The SBAT UEFI variable contains a descriptive form of all components used by | |
439 | all UEFI signed Operating Systems, along with a minimum generation number for | |
440 | each one. It may also contain a product-specific generation number, which in | |
441 | turn may also specify version-specific generation numbers. It is expected that | |
442 | specific generation numbers will be exceptions that will be obsoleted if and | |
443 | when the global number for a component is incremented. | |
444 | ||
445 | Initially the SBAT UEFI variable will set generation numbers for | |
446 | components to 1, but is expected to grow as CVEs are discovered and | |
447 | fixed. The following show the evolution over a sample set of events: | |
448 | ||
449 | ## Starting point | |
450 | ||
fd2d9f03 | 451 | Before CVEs are encountered, an undesirable module was built into Fedora's |
031e5cce SM |
452 | grub, so it's product-specific generation number has been bumped: |
453 | ||
454 | ``` | |
455 | sbat,1 | |
456 | shim,1 | |
457 | grub,1 | |
458 | grub.fedora,2 | |
459 | ``` | |
460 | ||
461 | ## Along comes bug 1 | |
462 | ||
463 | Another kind security researcher shows up with a serious bug, and this one was | |
464 | in upstream grub-0.94 and every version after that, and is shipped by all | |
465 | vendors. | |
466 | ||
467 | At this point, each vendor updates their grub builds, and updates the | |
468 | `component_generation` in `.sbat` to `2`. The GRUB upstream build now looks like: | |
469 | ``` | |
470 | sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md | |
471 | grub,2,Free Software Foundation,grub,2.05,https://www.gnu.org/software/grub/ | |
472 | ``` | |
473 | ||
474 | But Fedora's now looks like: | |
475 | ``` | |
476 | sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md | |
477 | grub,2,Free Software Foundation,grub,2.04,https://www.gnu.org/software/grub/ | |
478 | grub.fedora,2,The Fedora Project,grub2,2.04-33.fc33,https://src.fedoraproject.org/rpms/grub2 | |
479 | ``` | |
480 | ||
481 | Other distros either rebase on 2.05 or theirs change similarly to Fedora's. We | |
482 | now have two options for Acme Corp: | |
483 | - add a `grub.acme,2` entry to `SBAT` | |
484 | - have Acme Corp add | |
485 | `grub,2,Free Software Foundation,grub,1.96,https://www.gnu.org/software/grub/` | |
486 | to their new build's `.sbat` | |
487 | ||
488 | We talk to Acme and they agree to do the latter, thus saving flash real estate | |
489 | to be developed on another day. Their binary now looks like: | |
490 | ``` | |
491 | sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md | |
492 | grub,2,Free Software Foundation,grub,1.96,https://www.gnu.org/software/grub/ | |
493 | grub.acme,1,Acme Corporation,grub,1.96-8192,https://acme.arpa/packages/grub | |
494 | ``` | |
495 | ||
496 | The UEFI CA issues an update which looks like: | |
497 | ``` | |
498 | sbat,1 | |
499 | shim,1 | |
500 | grub,2 | |
501 | grub.fedora,2 | |
502 | ``` | |
503 | ||
504 | Which is literally the byte array: | |
505 | ``` | |
506 | { | |
507 | 's', 'b', 'a', 't', ',', '1', '\n', | |
508 | 's', 'h', 'i', 'm', ',', '1', '\n', | |
509 | 'g', 'r', 'u', 'b', ',', '2', '\n', | |
510 | 'g', 'r', 'u', 'b', '.', 'f', 'e', 'd', 'o', 'r', 'a', ',', '2', '\n', | |
511 | } | |
512 | ``` | |
513 | ||
514 | ## Acme Corp gets with the program | |
515 | ||
516 | Acme at this point discovers some features have been added to grub and they | |
517 | want them. They ship a new grub build that's completely rebased on top of | |
518 | upstream and has no known vulnerabilities. Its `.sbat` data looks like: | |
519 | ``` | |
520 | sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md | |
521 | grub,2,Free Software Foundation,grub,2.05,https://www.gnu.org/software/grub/ | |
522 | grub.acme,1,Acme Corporation,grub,2.05-1,https://acme.arpa/packages/grub | |
523 | ``` | |
524 | ||
525 | ## Someone was wrong on the Internet and bug 2 | |
526 | ||
527 | Debian discovers that they actually shipped bug 0 as well (woops). They | |
528 | produce a new build which fixes it and has the following in `.sbat`: | |
529 | ``` | |
530 | sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md | |
531 | grub,2,Free Software Foundation,grub,2.04,https://www.gnu.org/software/grub/ | |
532 | grub.debian,2,Debian,grub2,2.04-13,https://packages.debian.org/source/sid/grub2 | |
533 | ``` | |
534 | ||
535 | Before the UEFI CA has released an update, though, another upstream issue is | |
536 | found. Everybody updates their builds as they did for bug 1. Debian also | |
537 | updates theirs, as they would, and their new build has: | |
538 | ``` | |
539 | sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md | |
540 | grub,3,Free Software Foundation,grub,2.04,https://www.gnu.org/software/grub/ | |
541 | grub.debian,2,Debian,grub2,2.04-13,https://packages.debian.org/source/sid/grub2 | |
542 | ``` | |
543 | ||
544 | And the UEFI CA issues an update to SBAT which has: | |
545 | ``` | |
546 | sbat,1 | |
547 | shim,1 | |
548 | grub,3 | |
549 | grub.fedora,2 | |
550 | ``` | |
551 | ||
552 | The grub.fedora product-specific line could be dropped since a Fedora GRUB with | |
553 | a global generation number that also contained the bug that prompted the | |
554 | fedora-specific revocation was never published. This results in the following | |
555 | reduced UEFI SBAT revocation update: | |
556 | ``` | |
557 | sbat,1 | |
558 | shim,1 | |
559 | grub,3 | |
560 | ``` | |
561 | ||
562 | Two key things here: | |
563 | - `grub.debian` still got updated to `2` in their `.sbat` data, because a | |
564 | vulnerability was fixed that is only covered by that updated number. | |
565 | - There is still no `SBAT` update for `grub.debian`, because there's no binary | |
566 | that needs it which is not covered by updating `grub` to `3`. |