From 28577a2a2237a010abb01b27cc39990c96d1dafa Mon Sep 17 00:00:00 2001 From: Krzesimir Nowak Date: Thu, 12 Oct 2023 13:08:18 +0200 Subject: [PATCH 1/3] sys-boot/grub: Sync with Gentoo It's from Gentoo commit e6dcbcd25a2e4c2df04f6d4023f8675abc82ba06. --- .../coreos-overlay/sys-boot/grub/Manifest | 5 +- .../coreos-overlay/sys-boot/grub/README.md | 460 --- .../grub-2.06-add-gpt-partition-scheme.patch | 2792 ----------------- .../files/grub-2.06-add-verity-hash.patch | 134 - ...ub-2.06-fs-ext2-ignore-checksum-seed.patch | 62 - ...move-.interp-section-from-.img-files.patch | 31 - ...rub-2.06-grub-mkconfig-restore-umask.patch | 41 - .../grub/files/grub-2.06-locale.patch | 68 - .../sys-boot/grub/files/grub-2.06-riscv.patch | 49 - ...5_bli.in-fix-shebang-on-unmerged-usr.patch | 31 - ...rub-2.06-r7.ebuild => grub-2.06-r9.ebuild} | 16 +- 11 files changed, 3 insertions(+), 3686 deletions(-) delete mode 100644 sdk_container/src/third_party/coreos-overlay/sys-boot/grub/README.md delete mode 100644 sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-gpt-partition-scheme.patch delete mode 100644 sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-verity-hash.patch delete mode 100644 sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-fs-ext2-ignore-checksum-seed.patch delete mode 100644 sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-gentpl.py-Remove-.interp-section-from-.img-files.patch delete mode 100644 sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-grub-mkconfig-restore-umask.patch delete mode 100644 sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-locale.patch delete mode 100644 sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-riscv.patch delete mode 100644 sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.12_rc1-util-grub.d-25_bli.in-fix-shebang-on-unmerged-usr.patch rename sdk_container/src/third_party/coreos-overlay/sys-boot/grub/{grub-2.06-r7.ebuild => grub-2.06-r9.ebuild} (93%) diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/Manifest b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/Manifest index e69bf3b0ad4..9adaa7a4b23 100644 --- a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/Manifest +++ b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/Manifest @@ -1,8 +1,5 @@ DIST dejavu-sans-ttf-2.37.zip 417746 BLAKE2B c8904f3cd5a49370a7dc10e456684c88aeae998a99090bf4d0a5baa4f36cc8fb8f70586cf6d610a5ffeee97261d28c80f55bbe9dcfc3ed796d5c2d60e79adb58 SHA512 ede5899daa1984c5aa8cacb1c850eb53f189dddef3d9bb78bf9774d8976b7c0d6eb0bcf86237cd7d11f5b36cf5b5058d42cd94d3bd76f2bd0931c7ceb1271fae -DIST grub-2.06-backports-r2.tar.xz 40416 BLAKE2B d9b4a8274a24aa35023eef7450bc4311045d0872250b1d11b1714b9daa32f7862fe1444b5b86db8b885a9f7b3af2459a5b2f87f0beaf4326a982fd96ec51d602 SHA512 99cf40b3d3d10cf6ba928ccc571c3a8baab217f650267fa7de4ba4ce807a895ff9414156647cc4dcb34bfbe48747a0c486bf60fee1c188a2dc89f26c2db3840f +DIST grub-2.06-backports-r3.tar.xz 47612 BLAKE2B 235610e826c7a76d05872fb51e74564fb3861590f95377d5dcb9a5a4b0f5037d0b71c9f334bfe0bbe399f65036088d808f7af8e43090007ab7394002d05f7b4a SHA512 561f031dca2cdc13fc1b3f3cfdbdccd7decd67ef18ddcc588327f141b026eadcda5d64d729929859cad54959b3855ff86c1f62e3ff1d8ae5f6f5ac5761fa6ba4 DIST grub-2.06.tar.xz 6581924 BLAKE2B 2a40b9b03d7bb3b9e7b1309ab274d686f01b3c42e7035ebc6e5a0e59a59c3b7362ba518341664b314cb0dbc8222bb10ea05ce09f08ce9d58a293207cb909e417 SHA512 4f11c648f3078567e53fc0c74d5026fdc6da4be27d188975e79d9a4df817ade0fe5ad2ddd694238a07edc45adfa02943d83c57767dd51548102b375e529e8efe DIST grub-2.06.tar.xz.sig 566 BLAKE2B 2ff18fb40d9cce36cac110ba9996f88236dbaa261d19e777a6d23a0e9754a9fc8bc45a01896f4838c88bb44edff0172a97611202cb3ffd5653a3cbdfc102ae16 SHA512 797683dafade76b5981bd02f079d7dcecb36f5d07eca652181fd69f3df821931f84cc0d8771bfb80506ef41fbd96edfb202b6698af1fec3c8228dd320a05fa84 -DIST grub-2.12~rc1.tar.xz 6589460 BLAKE2B edfad62a01970026ca4ad088056da6225ef1319a08e8a95418b24cc8102be7fe45bb1412797aab13f8c1f4f690cf2fa9e5b4725f6769013ce76aa81c43952557 SHA512 6f1fbce004b6dccf58e203bf6a6eeb771bac5ecc54b503265e56a97e9adce0221677bb3e64328144ec921f327a099f0345e7a9952be41cd8808f7635cded52cb -DIST grub-2.12~rc1.tar.xz.sig 566 BLAKE2B 4b0563623498d06f512d29d9a84a4f8386e7d5adf257d0f2ea8f3301e5112b7ad669741d78519dfa35d16e7f1695b0c74740d679f07e41774ecc8910c3f6bc5c SHA512 b8b3c818679b50810e2d9e597a01c34b05fbc1218a88bdf35aaec798ce29b376c7aa696c50233d416306a480f6ee602dfcbe7eaf481c503f3c203a7b8e8db7a2 DIST unifont-12.1.02.pcf.gz 1335424 BLAKE2B 97080312468e3f3c8aa6f49cef08f5622641e8c9c035f3ede1e09d8d98de4e78d3b23c8aba2e8070eb46cbebd2d55e8568e467d7f15f35aa8fc8db792b7e5f14 SHA512 b280b2db7cf5f480b0668c331130dede2c0cc87d5e02e44566b77787113d0f6604d0105522858288f2ac6b8e77df7a2d9878725013a6c778dc5bfb183156e2f0 -DIST unifont-15.0.06.pcf.gz 1358322 BLAKE2B 81811e3de390ca35d1a2dc1f1dee73464e97f44907ba522c218ba9c5e39ca3c9d767552780a257a97c156eb623c17786d9c0d2b67786d61df5ca33a1e10db7ca SHA512 0a28a406629c604f5cbf51f501528239a7ed50d19f93ea505bc5bdc72639e4b926b03f4b8782a5733041f7cdb4aebb9948ac7cfd5a8ad9a0fe309944e595517b diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/README.md b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/README.md deleted file mode 100644 index c41786a2bc4..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/README.md +++ /dev/null @@ -1,460 +0,0 @@ -Flatcar uses a patched version of the GRUB, which implements the functionality to -read the [Flatcar Container Linux partition table](https://www.flatcar.org/docs/latest/reference/developer-guides/sdk-disk-partitions/#partition-table) - -## History - -CoreOS Container Linux maintained a fork of the [grub](https://github.com/coreos/grub) and then was referenced -in the coreos-overlay. Any changes were made through [PRs](https://github.com/coreos/grub/pulls?q=is%3Apr+is%3Aclosed) to the grub repository. - -When Flatcar was born, a `grub` repo under the flatcar-linux org was created -and referenced in the Flatcar's coreos-overlay. Except for a few, now many changes -where brought into the system. - -The repo was maintained at 2.02 version. During the 2.06 migration, the philosophy -to use a separate repo was scraped, and a single patch file was created. The patch -files migrated only the essential commits, and dropped all the other commits, which -were either half-baked, or redundant at the point of migration. The two patches are applied -on top of the grub sources, and emerge is done. - -Given below are the list of commits that were referenced to create the two patches. - -## Summary of the patches - -The patch starts with adding a new implementation of reading the GPT instead -of using the traditional module. It provides essential functionality to interact -with GPT structures on disk, and checking/validating data integrity & GPT specification. - -The commits goes on to add the following modules gptprio, gptrepair, and search -commands by label and partition. - -The `gptprio` command which provides a mechanism to prioritize and select the -next bootable partition based on the GPT attributes and results in flexible -partition booting. The `gptrepair` command implements the repair functions for -GPT information on a specified device. Few other functions include searching -devices by partition label or partition UUID. - -## Commits - -Below are the commits that are picked to create the two patches for the grub. One is -descriptive, and other is comprehensive. - -
- (click to expand) The descriptive log for all the commits picked - -``` -commit f69a9e0fdcf63ac33906e2753e14152bab2fcd05 -Author: Michael Marineau -Date: Sun Sep 28 21:26:21 2014 -0700 - - gpt: start new GPT module - - This module is a new implementation for reading GUID Partition Tables - which is much stricter than the existing part_gpt module and exports GPT - data directly instead of the generic grub_partition structure. It will - be the basis for modules that need to read/write/update GPT data. - - The current code does nothing more than read and verify the table. - -commit c26743a145c918958b862d580c4261735d1c1a6e -Author: Michael Marineau -Date: Sat Oct 18 15:39:13 2014 -0700 - - gpt: rename misnamed header location fields - - The header location fields refer to 'this header' and 'alternate header' - respectively, not 'primary header' and 'backup header'. The previous - field names are backwards for the backup header. - -commit 94f04a532d2b0e2b81e47a92488ebb1613bda1a0 -Author: Michael Marineau -Date: Sat Oct 18 16:46:17 2014 -0700 - - gpt: record size of of the entries table - - The size of the entries table will be needed later when writing it back - to disk. Restructure the entries reading code to flow a little better. - -commit 3d066264ac13198e45dc151b863a9aac4c095225 -Author: Michael Marineau -Date: Sat Oct 18 18:18:17 2014 -0700 - - gpt: consolidate crc32 computation code - - The gcrypt API is overly verbose, wrap it up in a helper function to - keep this rather common operation easy to use. - -commit dab6fac705bdad7e6ec130b24085189bcb15a5c9 -Author: Michael Marineau -Date: Sat Oct 18 18:21:07 2014 -0700 - - gpt: add new repair function to sync up primary and backup tables. - -commit 5e1829d4141343617b5e13e84298d118eac15bdf -Author: Michael Marineau -Date: Sun Oct 19 14:21:29 2014 -0700 - - gpt: add write function and gptrepair command - - The first hint of something practical, a command that can restore any of - the GPT structures from the alternate location. New test case must run - under QEMU because the loopback device used by the other unit tests does - not support writing. - -commit 2cd009dffe98c19672394608661767e4c3c84764 -Author: Michael Marineau -Date: Thu Oct 30 20:55:21 2014 -0700 - - gpt: add a new generic GUID type - - In order to do anything with partition GUIDs they need to be stored in a - proper structure like the partition type GUIDs. Additionally add an - initializer macro to simplify defining both GUID types. - -commit 508b02fc8a1fe58413ec8938ed1a7b149b5855fe -Author: Michael Marineau -Date: Mon Nov 3 17:14:37 2014 -0800 - - gpt: new gptprio.next command for selecting priority based partitions - - Basic usage would look something like this: - - gptprio.next -d usr_dev -u usr_uuid - linuxefi ($usr_dev)/boot/vmlinuz mount.usr=PARTUUID=$usr_uuid - - After booting the system should set the 'successful' bit on the - partition that was used. - -commit f8f6f790aa7448a35c2e3aae2d1a35d9d323a1b2 -Author: Michael Marineau -Date: Sat Nov 15 13:27:13 2014 -0800 - - gpt: split out checksum recomputation - - For basic data modifications the full repair function is overkill. - -commit d9bdbc10485a5c6f610569077631294683da4e34 -Author: Michael Marineau -Date: Thu Nov 27 12:55:53 2014 -0800 - - gpt: move gpt guid printing function to common library - -commit ffb13159f1e88d8c66954c3dfbeb027f943b3b1d -Author: Michael Marineau -Date: Thu Nov 27 14:54:27 2014 -0800 - - gpt: switch partition names to a 16 bit type - - In UEFI/GPT strings are UTF-16 so use a uint16 to make dealing with the - string practical. - -commit febf4666fbabc3ab4eaab32f4972b45b5c64c06d -Author: Michael Marineau -Date: Thu Nov 27 15:49:57 2014 -0800 - - tests: add some partitions to the gpt unit test data - -commit 67475f53e0ac4a844f793296ba2e4af707d5b20e -Author: Michael Marineau -Date: Thu Nov 27 16:34:21 2014 -0800 - - gpt: add search by partition label and uuid commands - - Builds on the existing filesystem search code. Only for GPT right now. - -commit d1270a2ba31cc3dd747d410a907f272ff03a6d68 -Author: Michael Marineau -Date: Fri Jul 31 15:03:11 2015 -0700 - - gpt: clean up little-endian crc32 computation - - - Remove problematic cast from *uint8_t to *uint32_t (alignment issue). - - Remove dynamic allocation and associated error handling paths. - - Match parameter ordering to existing grub_crypto_hash function. - -commit bacbed2c07f4b4e21c70310814a75fa9a1c3a155 -Author: Alex Crawford -Date: Mon Aug 31 15:23:39 2015 -0700 - - gpt: minor cleanup - -commit 1545295ad49d2aff2b75c6c0e7db58214351768e -Author: Alex Crawford -Date: Mon Aug 31 15:15:48 2015 -0700 - - gpt: add search by disk uuid command - -commit 6d4ea47541db4e0a1eab81de8843a491973e6b40 -Author: Michael Marineau -Date: Mon Jul 25 14:59:29 2016 -0700 - - gpt: do not use disk sizes GRUB will reject as invalid later on - - GRUB assumes that no disk is ever larger than 1EiB and rejects - reads/writes to such locations. Unfortunately this is not conveyed in - the usual way with the special GRUB_DISK_SIZE_UNKNOWN value. - -commit 99959fa2fb8bfafadc1fa5aec773a8d605a1df4e -Author: Michael Marineau -Date: Wed Aug 10 18:26:03 2016 -0700 - - gpt: add verbose debug logging - -commit f6b89ec3156a549999a13b3d15e9a67b4a9bf824 -Author: Michael Marineau -Date: Wed Aug 10 18:26:03 2016 -0700 - - gpt: improve validation of GPT headers - - Adds basic validation of all the disk locations in the headers, reducing - the chance of corrupting weird locations on disk. - -commit fa18d3a292bdcd61012d549c61e25d557481a05e -Author: Michael Marineau -Date: Thu Aug 11 15:02:21 2016 -0700 - - gpt: refuse to write to sector 0 - -commit b1ef48849c8dc12756793567520dfd3654539a27 -Author: Michael Marineau -Date: Sat Aug 20 17:42:12 2016 -0700 - - gpt: properly detect and repair invalid tables - - GPT_BOTH_VALID is 4 bits so simple a boolean check is not sufficient. - This broken condition allowed gptprio to trust bogus disk locations in - headers that were marked invalid causing arbitrary disk corruption. - -commit 9af98c2bfd31a73b899268e67f01bca785681d52 -Author: Michael Marineau -Date: Mon Aug 22 16:44:30 2016 -0700 - - gptrepair_test: fix typo in cleanup trap - -commit d457364d1d811ad262519cf6dde3d098caf7c778 -Author: Michael Marineau -Date: Mon Aug 22 16:45:10 2016 -0700 - - gptprio_test: check GPT is repaired when appropriate - -commit 3a3e45823dd677b428ceb40d8963676aff63f8d2 -Author: Michael Marineau -Date: Mon Aug 22 18:30:56 2016 -0700 - - fix checking alternate_lba - -commit 72b178950d313d567dfdf11f403199370d81a9f3 -Author: Michael Marineau -Date: Wed Aug 24 16:14:20 2016 -0700 - - gpt: fix partition table indexing and validation - - Portions of the code attempted to handle the fact that GPT entries on - disk may be larger than the currently defined struct while others - assumed the data could be indexed by the struct size directly. This - never came up because no utility uses a size larger than 128 bytes but - for the sake of safety we need to do this by the spec. - -commit 1d358a2061f40ad89567754f4787d0c76001d48a -Author: Michael Marineau -Date: Tue Aug 23 13:09:14 2016 -0700 - - gpt: prefer disk size from header over firmware - - The firmware and the OS may disagree on the disk configuration and size. - Although such a setup should be avoided users are unlikely to know about - the problem, assuming everything behaves like the OS. Tolerate this as - best we can and trust the reported on-disk location over the firmware - when looking for the backup GPT. If the location is inaccessible report - the error as best we can and move on. - -commit 2ed905dc03c757c92064486b380f59166cc704e8 -Author: Vito Caputo -Date: Thu Aug 25 17:21:18 2016 -0700 - - gpt: add helper for picking a valid header - - Eliminate some repetition in primary vs. backup header acquisition. - -commit 4af1d7a8b7d0cefa41a1ea4df050b161ea6cdf50 -Author: Michael Marineau -Date: Tue Sep 20 13:06:05 2016 -0700 - - gptrepair: fix status checking - - None of these status bit checks were correct. Fix and simplify. - -commit a794435ae9f5b1a2e0281d36b10545c6e643fd8d -Author: Michael Marineau -Date: Tue Sep 20 12:43:01 2016 -0700 - - gpt: use inline functions for checking status bits - - This should prevent bugs like 6078f836 and 4268f3da. - -commit 38cc185319b74d7d33ad380fe4d519fb0b0c85a6 -Author: Michael Marineau -Date: Tue Sep 20 13:40:11 2016 -0700 - - gpt: allow repair function to noop - - Simplifies usage a little. - -commit 2aeadda52929bb47089ef99c2bad0f928eadeffa -Author: Michael Marineau -Date: Wed Sep 21 13:22:06 2016 -0700 - - gpt: do not use an enum for status bit values - -commit 34652e500d64dc747ca17091b4490f9adf93ff82 -Author: Michael Marineau -Date: Wed Sep 21 13:44:11 2016 -0700 - - gpt: check header and entries status bits together - - Use the new status function which checks *_HEADER_VALID and - *_ENTRIES_VALID bits together. It doesn't make sense for the header and - entries bits to mismatch so don't allow for it. - -commit 753dd9201306e8cd7092a1231ceb194524397b04 -Author: Michael Marineau -Date: Wed Sep 21 13:52:52 2016 -0700 - - gpt: be more careful about relocating backup header - - The header was being relocated without checking the new location is - actually safe. If the BIOS thinks the disk is smaller than the OS then - repair may relocate the header into allocated space, failing the final - validation check. So only move it if the disk has grown. - - Additionally, if the backup is valid then we can assume its current - location is good enough and leave it as-is. - -commit f1f618740d1379000b04130a632f4d53bc2392b8 -Author: Michael Marineau -Date: Wed Sep 21 14:33:48 2016 -0700 - - gpt: selectively update fields during repair - - Just a little cleanup/refactor to skip touching data we don't need to. - -commit 285368e3753b1dbd631c1f5a4a127b7321a6941f -Author: Michael Marineau -Date: Wed Sep 21 14:55:19 2016 -0700 - - gpt: always revalidate when recomputing checksums - - This ensures all code modifying GPT data include the same sanity check - that repair does. If revalidation fails the status flags are left in the - appropriate state. - -commit f19f5cc49dc00752f6b267c2d580a25c31697afb -Author: Michael Marineau -Date: Wed Sep 21 15:01:09 2016 -0700 - - gpt: include backup-in-sync check in revalidation - -commit 7b25acebc343895adf942975bba5a52ef3408437 -Author: Michael Marineau -Date: Wed Sep 21 15:29:55 2016 -0700 - - gpt: read entries table at the same time as the header - - I personally think this reads easier. Also has the side effect of - directly comparing the primary and backup tables instead of presuming - they are equal if the crc32 matches. - -commit edd01f055a8a8f922491ba7077bf26fcaf015516 -Author: Michael Marineau -Date: Wed Sep 21 16:02:53 2016 -0700 - - gpt: report all revalidation errors - - Before returning an error that the primary or backup GPT is invalid push - the existing error onto the stack so the user will be told what is bad. - -commit 176fe49cf03ffdd72b8bd174a149032c3867ddde -Author: Michael Marineau -Date: Thu Sep 22 10:00:27 2016 -0700 - - gpt: rename and update documentation for grub_gpt_update - - The function now does more than just recompute checksums so give it a - more general name to reflect that. - -commit eb28d32081be2d224874c430345e7ef97bfbba07 -Author: Michael Marineau -Date: Thu Sep 22 11:18:42 2016 -0700 - - gpt: write backup GPT first, skip if inaccessible. - - Writing the primary GPT before the backup may lead to a confusing - situation: booting a freshly updated system could consistently fail and - next boot will fall back to the old system if writing the primary works - but writing the backup fails. If the backup is written first and fails - the primary is left in the old state so the next boot will re-try and - possibly fail in the exact same way. Making that repeatable should make - it easier for users to identify the error. - - Additionally if the firmware and OS disagree on the disk size, making - the backup inaccessible to GRUB, then just skip writing the backup. - When this happens the automatic call to `coreos-setgoodroot` after boot - will take care of repairing the backup. - -commit 03b547c21ec3475980a54b71e909034ed5ed5254 -Author: Matthew Garrett -Date: Thu May 28 11:15:30 2015 -0700 - - Add verity hash passthrough - - Read the verity hash from the kernel binary and pass it to the running - system via the kernel command line -``` -
- -
- (click to expand) Comprehensive log of the commits - -``` -f69a9e0fd gpt: start new GPT module -c26743a14 gpt: rename misnamed header location fields -94f04a532 gpt: record size of of the entries table -3d066264a gpt: consolidate crc32 computation code -dab6fac70 gpt: add new repair function to sync up primary and backup tables. -5e1829d41 gpt: add write function and gptrepair command -2cd009dff gpt: add a new generic GUID type -508b02fc8 gpt: new gptprio.next command for selecting priority based partitions -f8f6f790a gpt: split out checksum recomputation -d9bdbc104 gpt: move gpt guid printing function to common library -ffb13159f gpt: switch partition names to a 16 bit type -febf4666f tests: add some partitions to the gpt unit test data -67475f53e gpt: add search by partition label and uuid commands -d1270a2ba gpt: clean up little-endian crc32 computation -bacbed2c0 gpt: minor cleanup -1545295ad gpt: add search by disk uuid command -6d4ea4754 gpt: do not use disk sizes GRUB will reject as invalid later on -99959fa2f gpt: add verbose debug logging -f6b89ec31 gpt: improve validation of GPT headers -fa18d3a29 gpt: refuse to write to sector 0 -b1ef48849 gpt: properly detect and repair invalid tables -9af98c2bf gptrepair_test: fix typo in cleanup trap -d457364d1 gptprio_test: check GPT is repaired when appropriate -3a3e45823 fix checking alternate_lba -72b178950 gpt: fix partition table indexing and validation -1d358a206 gpt: prefer disk size from header over firmware -2ed905dc0 gpt: add helper for picking a valid header -4af1d7a8b gptrepair: fix status checking -a794435ae gpt: use inline functions for checking status bits -38cc18531 gpt: allow repair function to noop -2aeadda52 gpt: do not use an enum for status bit values -34652e500 gpt: check header and entries status bits together -753dd9201 gpt: be more careful about relocating backup header -f1f618740 gpt: selectively update fields during repair -285368e37 gpt: always revalidate when recomputing checksums -f19f5cc49 gpt: include backup-in-sync check in revalidation -7b25acebc gpt: read entries table at the same time as the header -edd01f055 gpt: report all revalidation errors -176fe49cf gpt: rename and update documentation for grub_gpt_update -eb28d3208 gpt: write backup GPT first, skip if inaccessible. -03b547c21 Add verity hash passthrough -``` -
diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-gpt-partition-scheme.patch b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-gpt-partition-scheme.patch deleted file mode 100644 index cef57e856a9..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-gpt-partition-scheme.patch +++ /dev/null @@ -1,2792 +0,0 @@ -From 026cab86883e256607f6df30375bfda4468ae71e Mon Sep 17 00:00:00 2001 -From: Sayan Chowdhury -Date: Thu, 24 Aug 2023 00:00:00 +0530 -Subject: [PATCH] gpt: Add patch to implement the custom GPT module - -This module is a new implementation for reading GUID Partition Tables -which is much stricter than the existing part_gpt module and exports GPT -data directly instead of the generic grub_partition structure. It will -be the basis for modules that need to read/write/update GPT data. - -This patch also includes the supporting functions like gptprio, -gptrepair, search commands. - -The patch is prepared using the coreos/grub PRs, picking the only -required ones, and dropping the others. The README.md file in the -coreos-overlay/sys-boot/grub/ contains more contexual information -along with the commits used to create the patch. - -Authored-by: Michael Marineau -Signed-off-by: Sayan Chowdhury ---- - Makefile.util.def | 30 + - grub-core/Makefile.core.def | 25 + - grub-core/commands/gptprio.c | 223 +++++++ - grub-core/commands/gptrepair.c | 110 ++++ - grub-core/commands/search.c | 49 ++ - grub-core/commands/search_part_label.c | 5 + - grub-core/commands/search_part_uuid.c | 5 + - grub-core/commands/search_wrap.c | 12 + - grub-core/lib/gpt.c | 757 +++++++++++++++++++++++ - include/grub/gpt_partition.h | 211 ++++++- - include/grub/search.h | 4 + - tests/gpt_unit_test.c | 807 +++++++++++++++++++++++++ - tests/gptprio_test.in | 207 +++++++ - tests/gptrepair_test.in | 102 ++++ - 14 files changed, 2530 insertions(+), 17 deletions(-) - create mode 100644 grub-core/commands/gptprio.c - create mode 100644 grub-core/commands/gptrepair.c - create mode 100644 grub-core/commands/search_part_label.c - create mode 100644 grub-core/commands/search_part_uuid.c - create mode 100644 grub-core/lib/gpt.c - create mode 100644 tests/gpt_unit_test.c - create mode 100644 tests/gptprio_test.in - create mode 100644 tests/gptrepair_test.in - -diff --git a/Makefile.util.def b/Makefile.util.def -index f8b356cc1..07df521ec 100644 ---- a/Makefile.util.def -+++ b/Makefile.util.def -@@ -1211,6 +1211,18 @@ script = { - common = tests/syslinux_test.in; - }; - -+script = { -+ testcase; -+ name = gptrepair_test; -+ common = tests/gptrepair_test.in; -+}; -+ -+script = { -+ testcase; -+ name = gptprio_test; -+ common = tests/gptprio_test.in; -+}; -+ - program = { - testcase; - name = example_unit_test; -@@ -1288,6 +1300,24 @@ program = { - ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; - }; - -+program = { -+ testcase; -+ name = gpt_unit_test; -+ common = tests/gpt_unit_test.c; -+ common = tests/lib/unit_test.c; -+ common = grub-core/commands/search_part_label.c; -+ common = grub-core/commands/search_part_uuid.c; -+ common = grub-core/disk/host.c; -+ common = grub-core/kern/emu/hostfs.c; -+ common = grub-core/lib/gpt.c; -+ common = grub-core/tests/lib/test.c; -+ ldadd = libgrubmods.a; -+ ldadd = libgrubgcry.a; -+ ldadd = libgrubkern.a; -+ ldadd = grub-core/gnulib/libgnu.a; -+ ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; -+}; -+ - program = { - name = grub-menulst2cfg; - mansection = 1; -diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index 8022e1c0a..e9baa2144 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -897,6 +897,21 @@ module = { - common = commands/gptsync.c; - }; - -+module = { -+ name = gptrepair; -+ common = commands/gptrepair.c; -+}; -+ -+module = { -+ name = gptprio; -+ common = commands/gptprio.c; -+}; -+ -+module = { -+ name = gpt; -+ common = lib/gpt.c; -+}; -+ - module = { - name = halt; - nopc = commands/halt.c; -@@ -1073,6 +1088,16 @@ module = { - common = commands/search_label.c; - }; - -+module = { -+ name = search_part_uuid; -+ common = commands/search_part_uuid.c; -+}; -+ -+module = { -+ name = search_part_label; -+ common = commands/search_part_label.c; -+}; -+ - module = { - name = setpci; - common = commands/setpci.c; -diff --git a/grub-core/commands/gptprio.c b/grub-core/commands/gptprio.c -new file mode 100644 -index 000000000..4a24fa62d ---- /dev/null -+++ b/grub-core/commands/gptprio.c -@@ -0,0 +1,223 @@ -+/* gptprio.c - manage priority based partition selection. */ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2009 Free Software Foundation, Inc. -+ * Copyright (C) 2014 CoreOS, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+GRUB_MOD_LICENSE ("GPLv3+"); -+ -+static const struct grub_arg_option options_next[] = { -+ {"set-device", 'd', 0, -+ N_("Set a variable to the name of selected partition."), -+ N_("VARNAME"), ARG_TYPE_STRING}, -+ {"set-uuid", 'u', 0, -+ N_("Set a variable to the GPT UUID of selected partition."), -+ N_("VARNAME"), ARG_TYPE_STRING}, -+ {0, 0, 0, 0, 0, 0} -+}; -+ -+enum options_next -+{ -+ NEXT_SET_DEVICE, -+ NEXT_SET_UUID, -+}; -+ -+static unsigned int -+grub_gptprio_priority (struct grub_gpt_partentry *entry) -+{ -+ return (unsigned int) grub_gpt_entry_attribute -+ (entry, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_PRIORITY, 4); -+} -+ -+static unsigned int -+grub_gptprio_tries_left (struct grub_gpt_partentry *entry) -+{ -+ return (unsigned int) grub_gpt_entry_attribute -+ (entry, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_TRIES_LEFT, 4); -+} -+ -+static void -+grub_gptprio_set_tries_left (struct grub_gpt_partentry *entry, -+ unsigned int tries_left) -+{ -+ grub_gpt_entry_set_attribute -+ (entry, tries_left, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_TRIES_LEFT, 4); -+} -+ -+static unsigned int -+grub_gptprio_successful (struct grub_gpt_partentry *entry) -+{ -+ return (unsigned int) grub_gpt_entry_attribute -+ (entry, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_SUCCESSFUL, 1); -+} -+ -+static grub_err_t -+grub_find_next (const char *disk_name, -+ const grub_gpt_part_type_t *part_type, -+ char **part_name, char **part_guid) -+{ -+ struct grub_gpt_partentry *part, *part_found = NULL; -+ grub_device_t dev = NULL; -+ grub_gpt_t gpt = NULL; -+ grub_uint32_t i, part_index; -+ -+ dev = grub_device_open (disk_name); -+ if (!dev) -+ goto done; -+ -+ gpt = grub_gpt_read (dev->disk); -+ if (!gpt) -+ goto done; -+ -+ if (grub_gpt_repair (dev->disk, gpt)) -+ goto done; -+ -+ for (i = 0; (part = grub_gpt_get_partentry (gpt, i)) != NULL; i++) -+ { -+ if (grub_memcmp (part_type, &part->type, sizeof (*part_type)) == 0) -+ { -+ unsigned int priority, tries_left, successful, old_priority = 0; -+ -+ priority = grub_gptprio_priority (part); -+ tries_left = grub_gptprio_tries_left (part); -+ successful = grub_gptprio_successful (part); -+ -+ if (part_found) -+ old_priority = grub_gptprio_priority (part_found); -+ -+ if ((tries_left || successful) && priority > old_priority) -+ { -+ part_index = i; -+ part_found = part; -+ } -+ } -+ } -+ -+ if (!part_found) -+ { -+ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("no such partition")); -+ goto done; -+ } -+ -+ if (grub_gptprio_tries_left (part_found)) -+ { -+ unsigned int tries_left = grub_gptprio_tries_left (part_found); -+ -+ grub_gptprio_set_tries_left (part_found, tries_left - 1); -+ -+ if (grub_gpt_update (gpt)) -+ goto done; -+ -+ if (grub_gpt_write (dev->disk, gpt)) -+ goto done; -+ } -+ -+ *part_name = grub_xasprintf ("%s,gpt%u", disk_name, part_index + 1); -+ if (!*part_name) -+ goto done; -+ -+ *part_guid = grub_gpt_guid_to_str (&part_found->guid); -+ if (!*part_guid) -+ goto done; -+ -+ grub_errno = GRUB_ERR_NONE; -+ -+done: -+ grub_gpt_free (gpt); -+ -+ if (dev) -+ grub_device_close (dev); -+ -+ return grub_errno; -+} -+ -+ -+ -+static grub_err_t -+grub_cmd_next (grub_extcmd_context_t ctxt, int argc, char **args) -+{ -+ struct grub_arg_list *state = ctxt->state; -+ char *p, *root = NULL, *part_name = NULL, *part_guid = NULL; -+ -+ /* TODO: Add a uuid parser and a command line flag for providing type. */ -+ grub_gpt_part_type_t part_type = GRUB_GPT_PARTITION_TYPE_USR_X86_64; -+ -+ if (!state[NEXT_SET_DEVICE].set || !state[NEXT_SET_UUID].set) -+ { -+ grub_error (GRUB_ERR_INVALID_COMMAND, N_("-d and -u are required")); -+ goto done; -+ } -+ -+ if (argc == 0) -+ root = grub_strdup (grub_env_get ("root")); -+ else if (argc == 1) -+ root = grub_strdup (args[0]); -+ else -+ { -+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unexpected arguments")); -+ goto done; -+ } -+ -+ if (!root) -+ goto done; -+ -+ /* To make using $root practical strip off the partition name. */ -+ p = grub_strchr (root, ','); -+ if (p) -+ *p = '\0'; -+ -+ if (grub_find_next (root, &part_type, &part_name, &part_guid)) -+ goto done; -+ -+ if (grub_env_set (state[NEXT_SET_DEVICE].arg, part_name)) -+ goto done; -+ -+ if (grub_env_set (state[NEXT_SET_UUID].arg, part_guid)) -+ goto done; -+ -+ grub_errno = GRUB_ERR_NONE; -+ -+done: -+ grub_free (root); -+ grub_free (part_name); -+ grub_free (part_guid); -+ -+ return grub_errno; -+} -+ -+static grub_extcmd_t cmd_next; -+ -+GRUB_MOD_INIT(gptprio) -+{ -+ cmd_next = grub_register_extcmd ("gptprio.next", grub_cmd_next, 0, -+ N_("-d VARNAME -u VARNAME [DEVICE]"), -+ N_("Select next partition to boot."), -+ options_next); -+} -+ -+GRUB_MOD_FINI(gptprio) -+{ -+ grub_unregister_extcmd (cmd_next); -+} -diff --git a/grub-core/commands/gptrepair.c b/grub-core/commands/gptrepair.c -new file mode 100644 -index 000000000..c17c7346c ---- /dev/null -+++ b/grub-core/commands/gptrepair.c -@@ -0,0 +1,110 @@ -+/* gptrepair.c - verify and restore GPT info from alternate location. */ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2009 Free Software Foundation, Inc. -+ * Copyright (C) 2014 CoreOS, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+GRUB_MOD_LICENSE ("GPLv3+"); -+ -+static char * -+trim_dev_name (char *name) -+{ -+ grub_size_t len = grub_strlen (name); -+ if (len && name[0] == '(' && name[len - 1] == ')') -+ { -+ name[len - 1] = '\0'; -+ name = name + 1; -+ } -+ return name; -+} -+ -+static grub_err_t -+grub_cmd_gptrepair (grub_command_t cmd __attribute__ ((unused)), -+ int argc, char **args) -+{ -+ grub_device_t dev = NULL; -+ grub_gpt_t gpt = NULL; -+ char *dev_name; -+ -+ if (argc != 1 || !grub_strlen(args[0])) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); -+ -+ dev_name = trim_dev_name (args[0]); -+ dev = grub_device_open (dev_name); -+ if (!dev) -+ goto done; -+ -+ if (!dev->disk) -+ { -+ grub_error (GRUB_ERR_BAD_ARGUMENT, "not a disk"); -+ goto done; -+ } -+ -+ gpt = grub_gpt_read (dev->disk); -+ if (!gpt) -+ goto done; -+ -+ if (grub_gpt_both_valid (gpt)) -+ { -+ grub_printf_ (N_("GPT already valid, %s unmodified.\n"), dev_name); -+ goto done; -+ } -+ -+ if (!grub_gpt_primary_valid (gpt)) -+ grub_printf_ (N_("Found invalid primary GPT on %s\n"), dev_name); -+ -+ if (!grub_gpt_backup_valid (gpt)) -+ grub_printf_ (N_("Found invalid backup GPT on %s\n"), dev_name); -+ -+ if (grub_gpt_repair (dev->disk, gpt)) -+ goto done; -+ -+ if (grub_gpt_write (dev->disk, gpt)) -+ goto done; -+ -+ grub_printf_ (N_("Repaired GPT on %s\n"), dev_name); -+ -+done: -+ if (gpt) -+ grub_gpt_free (gpt); -+ -+ if (dev) -+ grub_device_close (dev); -+ -+ return grub_errno; -+} -+ -+static grub_command_t cmd; -+ -+GRUB_MOD_INIT(gptrepair) -+{ -+ cmd = grub_register_command ("gptrepair", grub_cmd_gptrepair, -+ N_("DEVICE"), -+ N_("Verify and repair GPT on drive DEVICE.")); -+} -+ -+GRUB_MOD_FINI(gptrepair) -+{ -+ grub_unregister_command (cmd); -+} -diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c -index ed090b3af..4ad72c5b4 100644 ---- a/grub-core/commands/search.c -+++ b/grub-core/commands/search.c -@@ -30,6 +30,9 @@ - #include - #include - #include -+#if defined(DO_SEARCH_PART_UUID) || defined(DO_SEARCH_PART_LABEL) -+#include -+#endif - - GRUB_MOD_LICENSE ("GPLv3+"); - -@@ -90,6 +93,44 @@ iterate_device (const char *name, void *data) - } - grub_free (buf); - } -+#elif defined(DO_SEARCH_PART_UUID) -+ { -+ grub_device_t dev; -+ char *quid; -+ -+ dev = grub_device_open (name); -+ if (dev) -+ { -+ if (grub_gpt_part_uuid (dev, &quid) == GRUB_ERR_NONE) -+ { -+ if (grub_strcasecmp (quid, ctx->key) == 0) -+ found = 1; -+ -+ grub_free (quid); -+ } -+ -+ grub_device_close (dev); -+ } -+ } -+#elif defined(DO_SEARCH_PART_LABEL) -+ { -+ grub_device_t dev; -+ char *quid; -+ -+ dev = grub_device_open (name); -+ if (dev) -+ { -+ if (grub_gpt_part_label (dev, &quid) == GRUB_ERR_NONE) -+ { -+ if (grub_strcmp (quid, ctx->key) == 0) -+ found = 1; -+ -+ grub_free (quid); -+ } -+ -+ grub_device_close (dev); -+ } -+ } - #else - { - /* SEARCH_FS_UUID or SEARCH_LABEL */ -@@ -313,6 +354,10 @@ static grub_command_t cmd; - - #ifdef DO_SEARCH_FILE - GRUB_MOD_INIT(search_fs_file) -+#elif defined(DO_SEARCH_PART_UUID) -+GRUB_MOD_INIT(search_part_uuid) -+#elif defined(DO_SEARCH_PART_LABEL) -+GRUB_MOD_INIT(search_part_label) - #elif defined (DO_SEARCH_FS_UUID) - GRUB_MOD_INIT(search_fs_uuid) - #else -@@ -327,6 +372,10 @@ GRUB_MOD_INIT(search_label) - - #ifdef DO_SEARCH_FILE - GRUB_MOD_FINI(search_fs_file) -+#elif defined(DO_SEARCH_PART_UUID) -+GRUB_MOD_FINI(search_part_uuid) -+#elif defined(DO_SEARCH_PART_LABEL) -+GRUB_MOD_FINI(search_part_label) - #elif defined (DO_SEARCH_FS_UUID) - GRUB_MOD_FINI(search_fs_uuid) - #else -diff --git a/grub-core/commands/search_part_label.c b/grub-core/commands/search_part_label.c -new file mode 100644 -index 000000000..ca906cbd9 ---- /dev/null -+++ b/grub-core/commands/search_part_label.c -@@ -0,0 +1,5 @@ -+#define DO_SEARCH_PART_LABEL 1 -+#define FUNC_NAME grub_search_part_label -+#define COMMAND_NAME "search.part_label" -+#define HELP_MESSAGE N_("Search devices by partition label. If VARIABLE is specified, the first device found is set to a variable.") -+#include "search.c" -diff --git a/grub-core/commands/search_part_uuid.c b/grub-core/commands/search_part_uuid.c -new file mode 100644 -index 000000000..2d1d3d0d7 ---- /dev/null -+++ b/grub-core/commands/search_part_uuid.c -@@ -0,0 +1,5 @@ -+#define DO_SEARCH_PART_UUID 1 -+#define FUNC_NAME grub_search_part_uuid -+#define COMMAND_NAME "search.part_uuid" -+#define HELP_MESSAGE N_("Search devices by partition UUID. If VARIABLE is specified, the first device found is set to a variable.") -+#include "search.c" -diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c -index 47fc8eb99..d357454a9 100644 ---- a/grub-core/commands/search_wrap.c -+++ b/grub-core/commands/search_wrap.c -@@ -36,6 +36,10 @@ static const struct grub_arg_option options[] = - 0, 0}, - {"fs-uuid", 'u', 0, N_("Search devices by a filesystem UUID."), - 0, 0}, -+ {"part-label", 'L', 0, N_("Search devices by a partition label."), -+ 0, 0}, -+ {"part-uuid", 'U', 0, N_("Search devices by a partition UUID."), -+ 0, 0}, - {"set", 's', GRUB_ARG_OPTION_OPTIONAL, - N_("Set a variable to the first device found."), N_("VARNAME"), - ARG_TYPE_STRING}, -@@ -71,6 +75,8 @@ enum options - SEARCH_FILE, - SEARCH_LABEL, - SEARCH_FS_UUID, -+ SEARCH_PART_LABEL, -+ SEARCH_PART_UUID, - SEARCH_SET, - SEARCH_NO_FLOPPY, - SEARCH_HINT, -@@ -186,6 +192,12 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args) - else if (state[SEARCH_FS_UUID].set) - grub_search_fs_uuid (id, var, state[SEARCH_NO_FLOPPY].set, - hints, nhints); -+ else if (state[SEARCH_PART_LABEL].set) -+ grub_search_part_label (id, var, state[SEARCH_NO_FLOPPY].set, -+ hints, nhints); -+ else if (state[SEARCH_PART_UUID].set) -+ grub_search_part_uuid (id, var, state[SEARCH_NO_FLOPPY].set, -+ hints, nhints); - else if (state[SEARCH_FILE].set) - grub_search_fs_file (id, var, state[SEARCH_NO_FLOPPY].set, - hints, nhints); -diff --git a/grub-core/lib/gpt.c b/grub-core/lib/gpt.c -new file mode 100644 -index 000000000..098fa65c4 ---- /dev/null -+++ b/grub-core/lib/gpt.c -@@ -0,0 +1,757 @@ -+/* gpt.c - Read/Verify/Write GUID Partition Tables (GPT). */ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2002,2005,2006,2007,2008 Free Software Foundation, Inc. -+ * Copyright (C) 2014 CoreOS, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+GRUB_MOD_LICENSE ("GPLv3+"); -+ -+static grub_uint8_t grub_gpt_magic[] = GRUB_GPT_HEADER_MAGIC; -+ -+static grub_err_t -+grub_gpt_read_entries (grub_disk_t disk, grub_gpt_t gpt, -+ struct grub_gpt_header *header, -+ void **ret_entries, -+ grub_size_t *ret_entries_size); -+ -+char * -+grub_gpt_guid_to_str (grub_gpt_guid_t *guid) -+{ -+ return grub_xasprintf ("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", -+ grub_le_to_cpu32 (guid->data1), -+ grub_le_to_cpu16 (guid->data2), -+ grub_le_to_cpu16 (guid->data3), -+ guid->data4[0], guid->data4[1], -+ guid->data4[2], guid->data4[3], -+ guid->data4[4], guid->data4[5], -+ guid->data4[6], guid->data4[7]); -+} -+ -+static grub_err_t -+grub_gpt_device_partentry (grub_device_t device, -+ struct grub_gpt_partentry *entry) -+{ -+ grub_disk_t disk = device->disk; -+ grub_partition_t p; -+ grub_err_t err; -+ -+ if (!disk || !disk->partition) -+ return grub_error (GRUB_ERR_BUG, "not a partition"); -+ -+ if (grub_strcmp (disk->partition->partmap->name, "gpt")) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a GPT partition"); -+ -+ p = disk->partition; -+ disk->partition = p->parent; -+ err = grub_disk_read (disk, p->offset, p->index, sizeof (*entry), entry); -+ disk->partition = p; -+ -+ return err; -+} -+ -+grub_err_t -+grub_gpt_part_label (grub_device_t device, char **label) -+{ -+ struct grub_gpt_partentry entry; -+ const grub_size_t name_len = ARRAY_SIZE (entry.name); -+ const grub_size_t label_len = name_len * GRUB_MAX_UTF8_PER_UTF16 + 1; -+ grub_size_t i; -+ grub_uint8_t *end; -+ -+ if (grub_gpt_device_partentry (device, &entry)) -+ return grub_errno; -+ -+ *label = grub_malloc (label_len); -+ if (!*label) -+ return grub_errno; -+ -+ for (i = 0; i < name_len; i++) -+ entry.name[i] = grub_le_to_cpu16 (entry.name[i]); -+ -+ end = grub_utf16_to_utf8 ((grub_uint8_t *) *label, entry.name, name_len); -+ *end = '\0'; -+ -+ return GRUB_ERR_NONE; -+} -+ -+grub_err_t -+grub_gpt_part_uuid (grub_device_t device, char **uuid) -+{ -+ struct grub_gpt_partentry entry; -+ -+ if (grub_gpt_device_partentry (device, &entry)) -+ return grub_errno; -+ -+ *uuid = grub_gpt_guid_to_str (&entry.guid); -+ if (!*uuid) -+ return grub_errno; -+ -+ return GRUB_ERR_NONE; -+} -+ -+static struct grub_gpt_header * -+grub_gpt_get_header (grub_gpt_t gpt) -+{ -+ if (gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID) -+ return &gpt->primary; -+ else if (gpt->status & GRUB_GPT_BACKUP_HEADER_VALID) -+ return &gpt->backup; -+ -+ grub_error (GRUB_ERR_BUG, "No valid GPT header"); -+ return NULL; -+} -+ -+static grub_uint64_t -+grub_gpt_size_to_sectors (grub_gpt_t gpt, grub_size_t size) -+{ -+ unsigned int sector_size; -+ grub_uint64_t sectors; -+ -+ sector_size = 1U << gpt->log_sector_size; -+ sectors = size / sector_size; -+ if (size % sector_size) -+ sectors++; -+ -+ return sectors; -+} -+ -+/* Copied from grub-core/kern/disk_common.c grub_disk_adjust_range so we can -+ * avoid attempting to use disk->total_sectors when GRUB won't let us. -+ * TODO: Why is disk->total_sectors not set to GRUB_DISK_SIZE_UNKNOWN? */ -+static int -+grub_gpt_disk_size_valid (grub_disk_t disk) -+{ -+ grub_disk_addr_t total_sectors; -+ -+ /* Transform total_sectors to number of 512B blocks. */ -+ total_sectors = disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS); -+ -+ /* Some drivers have problems with disks above reasonable. -+ Treat unknown as 1EiB disk. While on it, clamp the size to 1EiB. -+ Just one condition is enough since GRUB_DISK_UNKNOWN_SIZE << ls is always -+ above 9EiB. -+ */ -+ if (total_sectors > (1ULL << 51)) -+ return 0; -+ -+ return 1; -+} -+ -+static void -+grub_gpt_lecrc32 (grub_uint32_t *crc, const void *data, grub_size_t len) -+{ -+ grub_uint32_t crc32_val; -+ -+ grub_crypto_hash (GRUB_MD_CRC32, &crc32_val, data, len); -+ -+ /* GRUB_MD_CRC32 always uses big endian, gpt is always little. */ -+ *crc = grub_swap_bytes32 (crc32_val); -+} -+ -+static void -+grub_gpt_header_lecrc32 (grub_uint32_t *crc, struct grub_gpt_header *header) -+{ -+ grub_uint32_t old, new; -+ -+ /* crc32 must be computed with the field cleared. */ -+ old = header->crc32; -+ header->crc32 = 0; -+ grub_gpt_lecrc32 (&new, header, sizeof (*header)); -+ header->crc32 = old; -+ -+ *crc = new; -+} -+ -+/* Make sure the MBR is a protective MBR and not a normal MBR. */ -+grub_err_t -+grub_gpt_pmbr_check (struct grub_msdos_partition_mbr *mbr) -+{ -+ unsigned int i; -+ -+ if (mbr->signature != -+ grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE)) -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid MBR signature"); -+ -+ for (i = 0; i < sizeof (mbr->entries); i++) -+ if (mbr->entries[i].type == GRUB_PC_PARTITION_TYPE_GPT_DISK) -+ return GRUB_ERR_NONE; -+ -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid protective MBR"); -+} -+ -+static grub_uint64_t -+grub_gpt_entries_size (struct grub_gpt_header *gpt) -+{ -+ return (grub_uint64_t) grub_le_to_cpu32 (gpt->maxpart) * -+ (grub_uint64_t) grub_le_to_cpu32 (gpt->partentry_size); -+} -+ -+static grub_uint64_t -+grub_gpt_entries_sectors (struct grub_gpt_header *gpt, -+ unsigned int log_sector_size) -+{ -+ grub_uint64_t sector_bytes, entries_bytes; -+ -+ sector_bytes = 1ULL << log_sector_size; -+ entries_bytes = grub_gpt_entries_size (gpt); -+ return grub_divmod64(entries_bytes + sector_bytes - 1, sector_bytes, NULL); -+} -+ -+static int -+is_pow2 (grub_uint32_t n) -+{ -+ return (n & (n - 1)) == 0; -+} -+ -+grub_err_t -+grub_gpt_header_check (struct grub_gpt_header *gpt, -+ unsigned int log_sector_size) -+{ -+ grub_uint32_t crc = 0, size; -+ grub_uint64_t start, end; -+ -+ if (grub_memcmp (gpt->magic, grub_gpt_magic, sizeof (grub_gpt_magic)) != 0) -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT signature"); -+ -+ if (gpt->version != GRUB_GPT_HEADER_VERSION) -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "unknown GPT version"); -+ -+ grub_gpt_header_lecrc32 (&crc, gpt); -+ if (gpt->crc32 != crc) -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT header crc32"); -+ -+ /* The header size "must be greater than or equal to 92 and must be less -+ * than or equal to the logical block size." */ -+ size = grub_le_to_cpu32 (gpt->headersize); -+ if (size < 92U || size > (1U << log_sector_size)) -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT header size"); -+ -+ /* The partition entry size must be "a value of 128*(2^n) where n is an -+ * integer greater than or equal to zero (e.g., 128, 256, 512, etc.)." */ -+ size = grub_le_to_cpu32 (gpt->partentry_size); -+ if (size < 128U || size % 128U || !is_pow2 (size / 128U)) -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT entry size"); -+ -+ /* The minimum entries table size is specified in terms of bytes, -+ * regardless of how large the individual entry size is. */ -+ if (grub_gpt_entries_size (gpt) < GRUB_GPT_DEFAULT_ENTRIES_SIZE) -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT entry table size"); -+ -+ /* And of course there better be some space for partitions! */ -+ start = grub_le_to_cpu64 (gpt->start); -+ end = grub_le_to_cpu64 (gpt->end); -+ if (start > end) -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid usable sectors"); -+ -+ return GRUB_ERR_NONE; -+} -+ -+static int -+grub_gpt_headers_equal (grub_gpt_t gpt) -+{ -+ /* Assume headers passed grub_gpt_header_check so skip magic and version. -+ * Individual fields must be checked instead of just using memcmp because -+ * crc32, header, alternate, and partitions will all normally differ. */ -+ -+ if (gpt->primary.headersize != gpt->backup.headersize || -+ gpt->primary.header_lba != gpt->backup.alternate_lba || -+ gpt->primary.alternate_lba != gpt->backup.header_lba || -+ gpt->primary.start != gpt->backup.start || -+ gpt->primary.end != gpt->backup.end || -+ gpt->primary.maxpart != gpt->backup.maxpart || -+ gpt->primary.partentry_size != gpt->backup.partentry_size || -+ gpt->primary.partentry_crc32 != gpt->backup.partentry_crc32) -+ return 0; -+ -+ return grub_memcmp(&gpt->primary.guid, &gpt->backup.guid, -+ sizeof(grub_gpt_guid_t)) == 0; -+} -+ -+static grub_err_t -+grub_gpt_check_primary (grub_gpt_t gpt) -+{ -+ grub_uint64_t backup, primary, entries, entries_len, start, end; -+ -+ primary = grub_le_to_cpu64 (gpt->primary.header_lba); -+ backup = grub_le_to_cpu64 (gpt->primary.alternate_lba); -+ entries = grub_le_to_cpu64 (gpt->primary.partitions); -+ entries_len = grub_gpt_entries_sectors(&gpt->primary, gpt->log_sector_size); -+ start = grub_le_to_cpu64 (gpt->primary.start); -+ end = grub_le_to_cpu64 (gpt->primary.end); -+ -+ grub_dprintf ("gpt", "Primary GPT layout:\n" -+ "primary header = 0x%llx backup header = 0x%llx\n" -+ "entries location = 0x%llx length = 0x%llx\n" -+ "first usable = 0x%llx last usable = 0x%llx\n", -+ (unsigned long long) primary, -+ (unsigned long long) backup, -+ (unsigned long long) entries, -+ (unsigned long long) entries_len, -+ (unsigned long long) start, -+ (unsigned long long) end); -+ -+ if (grub_gpt_header_check (&gpt->primary, gpt->log_sector_size)) -+ return grub_errno; -+ if (primary != 1) -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid primary GPT LBA"); -+ if (entries <= 1 || entries+entries_len > start) -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid entries location"); -+ if (backup <= end) -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid backup GPT LBA"); -+ -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+grub_gpt_check_backup (grub_gpt_t gpt) -+{ -+ grub_uint64_t backup, primary, entries, entries_len, start, end; -+ -+ backup = grub_le_to_cpu64 (gpt->backup.header_lba); -+ primary = grub_le_to_cpu64 (gpt->backup.alternate_lba); -+ entries = grub_le_to_cpu64 (gpt->backup.partitions); -+ entries_len = grub_gpt_entries_sectors(&gpt->backup, gpt->log_sector_size); -+ start = grub_le_to_cpu64 (gpt->backup.start); -+ end = grub_le_to_cpu64 (gpt->backup.end); -+ -+ grub_dprintf ("gpt", "Backup GPT layout:\n" -+ "primary header = 0x%llx backup header = 0x%llx\n" -+ "entries location = 0x%llx length = 0x%llx\n" -+ "first usable = 0x%llx last usable = 0x%llx\n", -+ (unsigned long long) primary, -+ (unsigned long long) backup, -+ (unsigned long long) entries, -+ (unsigned long long) entries_len, -+ (unsigned long long) start, -+ (unsigned long long) end); -+ -+ if (grub_gpt_header_check (&gpt->backup, gpt->log_sector_size)) -+ return grub_errno; -+ if (primary != 1) -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid primary GPT LBA"); -+ if (entries <= end || entries+entries_len > backup) -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid entries location"); -+ if (backup <= end) -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid backup GPT LBA"); -+ -+ /* If both primary and backup are valid but differ prefer the primary. */ -+ if ((gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID) && -+ !grub_gpt_headers_equal (gpt)) -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "backup GPT out of sync"); -+ -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+grub_gpt_read_primary (grub_disk_t disk, grub_gpt_t gpt) -+{ -+ grub_disk_addr_t addr; -+ -+ /* TODO: The gpt partmap module searches for the primary header instead -+ * of relying on the disk's sector size. For now trust the disk driver -+ * but eventually this code should match the existing behavior. */ -+ gpt->log_sector_size = disk->log_sector_size; -+ -+ grub_dprintf ("gpt", "reading primary GPT from sector 0x1\n"); -+ -+ addr = grub_gpt_sector_to_addr (gpt, 1); -+ if (grub_disk_read (disk, addr, 0, sizeof (gpt->primary), &gpt->primary)) -+ return grub_errno; -+ -+ if (grub_gpt_check_primary (gpt)) -+ return grub_errno; -+ -+ gpt->status |= GRUB_GPT_PRIMARY_HEADER_VALID; -+ -+ if (grub_gpt_read_entries (disk, gpt, &gpt->primary, -+ &gpt->entries, &gpt->entries_size)) -+ return grub_errno; -+ -+ gpt->status |= GRUB_GPT_PRIMARY_ENTRIES_VALID; -+ -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+grub_gpt_read_backup (grub_disk_t disk, grub_gpt_t gpt) -+{ -+ void *entries = NULL; -+ grub_size_t entries_size; -+ grub_uint64_t sector; -+ grub_disk_addr_t addr; -+ -+ /* Assumes gpt->log_sector_size == disk->log_sector_size */ -+ if (gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID) -+ { -+ sector = grub_le_to_cpu64 (gpt->primary.alternate_lba); -+ if (grub_gpt_disk_size_valid (disk) && sector >= disk->total_sectors) -+ return grub_error (GRUB_ERR_OUT_OF_RANGE, -+ "backup GPT located at 0x%llx, " -+ "beyond last disk sector at 0x%llx", -+ (unsigned long long) sector, -+ (unsigned long long) disk->total_sectors - 1); -+ } -+ else if (grub_gpt_disk_size_valid (disk)) -+ sector = disk->total_sectors - 1; -+ else -+ return grub_error (GRUB_ERR_OUT_OF_RANGE, -+ "size of disk unknown, cannot locate backup GPT"); -+ -+ grub_dprintf ("gpt", "reading backup GPT from sector 0x%llx\n", -+ (unsigned long long) sector); -+ -+ addr = grub_gpt_sector_to_addr (gpt, sector); -+ if (grub_disk_read (disk, addr, 0, sizeof (gpt->backup), &gpt->backup)) -+ return grub_errno; -+ -+ if (grub_gpt_check_backup (gpt)) -+ return grub_errno; -+ -+ /* Ensure the backup header thinks it is located where we found it. */ -+ if (grub_le_to_cpu64 (gpt->backup.header_lba) != sector) -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid backup GPT LBA"); -+ -+ gpt->status |= GRUB_GPT_BACKUP_HEADER_VALID; -+ -+ if (grub_gpt_read_entries (disk, gpt, &gpt->backup, -+ &entries, &entries_size)) -+ return grub_errno; -+ -+ if (gpt->status & GRUB_GPT_PRIMARY_ENTRIES_VALID) -+ { -+ if (entries_size != gpt->entries_size || -+ grub_memcmp (entries, gpt->entries, entries_size) != 0) -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "backup GPT out of sync"); -+ -+ grub_free (entries); -+ } -+ else -+ { -+ gpt->entries = entries; -+ gpt->entries_size = entries_size; -+ } -+ -+ gpt->status |= GRUB_GPT_BACKUP_ENTRIES_VALID; -+ -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+grub_gpt_read_entries (grub_disk_t disk, grub_gpt_t gpt, -+ struct grub_gpt_header *header, -+ void **ret_entries, -+ grub_size_t *ret_entries_size) -+{ -+ void *entries = NULL; -+ grub_uint32_t count, size, crc; -+ grub_uint64_t sector; -+ grub_disk_addr_t addr; -+ grub_size_t entries_size; -+ -+ /* Grub doesn't include calloc, hence the manual overflow check. */ -+ count = grub_le_to_cpu32 (header->maxpart); -+ size = grub_le_to_cpu32 (header->partentry_size); -+ entries_size = count *size; -+ if (size && entries_size / size != count) -+ { -+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); -+ goto fail; -+ } -+ -+ /* Double check that the header was validated properly. */ -+ if (entries_size < GRUB_GPT_DEFAULT_ENTRIES_SIZE) -+ return grub_error (GRUB_ERR_BUG, "invalid GPT entries table size"); -+ -+ entries = grub_malloc (entries_size); -+ if (!entries) -+ goto fail; -+ -+ sector = grub_le_to_cpu64 (header->partitions); -+ grub_dprintf ("gpt", "reading GPT %lu entries from sector 0x%llx\n", -+ (unsigned long) count, -+ (unsigned long long) sector); -+ -+ addr = grub_gpt_sector_to_addr (gpt, sector); -+ if (grub_disk_read (disk, addr, 0, entries_size, entries)) -+ goto fail; -+ -+ grub_gpt_lecrc32 (&crc, entries, entries_size); -+ if (crc != header->partentry_crc32) -+ { -+ grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT entry crc32"); -+ goto fail; -+ } -+ -+ *ret_entries = entries; -+ *ret_entries_size = entries_size; -+ return GRUB_ERR_NONE; -+ -+fail: -+ grub_free (entries); -+ return grub_errno; -+} -+ -+grub_gpt_t -+grub_gpt_read (grub_disk_t disk) -+{ -+ grub_gpt_t gpt; -+ -+ grub_dprintf ("gpt", "reading GPT from %s\n", disk->name); -+ -+ gpt = grub_zalloc (sizeof (*gpt)); -+ if (!gpt) -+ goto fail; -+ -+ if (grub_disk_read (disk, 0, 0, sizeof (gpt->mbr), &gpt->mbr)) -+ goto fail; -+ -+ /* Check the MBR but errors aren't reported beyond the status bit. */ -+ if (grub_gpt_pmbr_check (&gpt->mbr)) -+ grub_errno = GRUB_ERR_NONE; -+ else -+ gpt->status |= GRUB_GPT_PROTECTIVE_MBR; -+ -+ /* If both the primary and backup fail report the primary's error. */ -+ if (grub_gpt_read_primary (disk, gpt)) -+ { -+ grub_error_push (); -+ grub_gpt_read_backup (disk, gpt); -+ grub_error_pop (); -+ } -+ else -+ grub_gpt_read_backup (disk, gpt); -+ -+ /* If either succeeded clear any possible error from the other. */ -+ if (grub_gpt_primary_valid (gpt) || grub_gpt_backup_valid (gpt)) -+ grub_errno = GRUB_ERR_NONE; -+ else -+ goto fail; -+ -+ return gpt; -+ -+fail: -+ grub_gpt_free (gpt); -+ return NULL; -+} -+ -+struct grub_gpt_partentry * -+grub_gpt_get_partentry (grub_gpt_t gpt, grub_uint32_t n) -+{ -+ struct grub_gpt_header *header; -+ grub_size_t offset; -+ -+ header = grub_gpt_get_header (gpt); -+ if (!header) -+ return NULL; -+ -+ if (n >= grub_le_to_cpu32 (header->maxpart)) -+ return NULL; -+ -+ offset = (grub_size_t) grub_le_to_cpu32 (header->partentry_size) * n; -+ return (struct grub_gpt_partentry *) ((char *) gpt->entries + offset); -+} -+ -+grub_err_t -+grub_gpt_repair (grub_disk_t disk, grub_gpt_t gpt) -+{ -+ /* Skip if there is nothing to do. */ -+ if (grub_gpt_both_valid (gpt)) -+ return GRUB_ERR_NONE; -+ -+ grub_dprintf ("gpt", "repairing GPT for %s\n", disk->name); -+ -+ if (disk->log_sector_size != gpt->log_sector_size) -+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, -+ "GPT sector size must match disk sector size"); -+ -+ if (grub_gpt_primary_valid (gpt)) -+ { -+ grub_uint64_t backup_header; -+ -+ grub_dprintf ("gpt", "primary GPT is valid\n"); -+ -+ /* Relocate backup to end if disk if the disk has grown. */ -+ backup_header = grub_le_to_cpu64 (gpt->primary.alternate_lba); -+ if (grub_gpt_disk_size_valid (disk) && -+ disk->total_sectors - 1 > backup_header) -+ { -+ backup_header = disk->total_sectors - 1; -+ grub_dprintf ("gpt", "backup GPT header relocated to 0x%llx\n", -+ (unsigned long long) backup_header); -+ -+ gpt->primary.alternate_lba = grub_cpu_to_le64 (backup_header); -+ } -+ -+ grub_memcpy (&gpt->backup, &gpt->primary, sizeof (gpt->backup)); -+ gpt->backup.header_lba = gpt->primary.alternate_lba; -+ gpt->backup.alternate_lba = gpt->primary.header_lba; -+ gpt->backup.partitions = grub_cpu_to_le64 (backup_header - -+ grub_gpt_size_to_sectors (gpt, gpt->entries_size)); -+ } -+ else if (grub_gpt_backup_valid (gpt)) -+ { -+ grub_dprintf ("gpt", "backup GPT is valid\n"); -+ -+ grub_memcpy (&gpt->primary, &gpt->backup, sizeof (gpt->primary)); -+ gpt->primary.header_lba = gpt->backup.alternate_lba; -+ gpt->primary.alternate_lba = gpt->backup.header_lba; -+ gpt->primary.partitions = grub_cpu_to_le64_compile_time (2); -+ } -+ else -+ return grub_error (GRUB_ERR_BUG, "No valid GPT"); -+ -+ if (grub_gpt_update (gpt)) -+ return grub_errno; -+ -+ grub_dprintf ("gpt", "repairing GPT for %s successful\n", disk->name); -+ -+ return GRUB_ERR_NONE; -+} -+ -+grub_err_t -+grub_gpt_update (grub_gpt_t gpt) -+{ -+ grub_uint32_t crc; -+ -+ /* Clear status bits, require revalidation of everything. */ -+ gpt->status &= ~(GRUB_GPT_PRIMARY_HEADER_VALID | -+ GRUB_GPT_PRIMARY_ENTRIES_VALID | -+ GRUB_GPT_BACKUP_HEADER_VALID | -+ GRUB_GPT_BACKUP_ENTRIES_VALID); -+ -+ /* Writing headers larger than our header structure are unsupported. */ -+ gpt->primary.headersize = -+ grub_cpu_to_le32_compile_time (sizeof (gpt->primary)); -+ gpt->backup.headersize = -+ grub_cpu_to_le32_compile_time (sizeof (gpt->backup)); -+ -+ grub_gpt_lecrc32 (&crc, gpt->entries, gpt->entries_size); -+ gpt->primary.partentry_crc32 = crc; -+ gpt->backup.partentry_crc32 = crc; -+ -+ grub_gpt_header_lecrc32 (&gpt->primary.crc32, &gpt->primary); -+ grub_gpt_header_lecrc32 (&gpt->backup.crc32, &gpt->backup); -+ -+ if (grub_gpt_check_primary (gpt)) -+ { -+ grub_error_push (); -+ return grub_error (GRUB_ERR_BUG, "Generated invalid GPT primary header"); -+ } -+ -+ gpt->status |= (GRUB_GPT_PRIMARY_HEADER_VALID | -+ GRUB_GPT_PRIMARY_ENTRIES_VALID); -+ -+ if (grub_gpt_check_backup (gpt)) -+ { -+ grub_error_push (); -+ return grub_error (GRUB_ERR_BUG, "Generated invalid GPT backup header"); -+ } -+ -+ gpt->status |= (GRUB_GPT_BACKUP_HEADER_VALID | -+ GRUB_GPT_BACKUP_ENTRIES_VALID); -+ -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+grub_gpt_write_table (grub_disk_t disk, grub_gpt_t gpt, -+ struct grub_gpt_header *header) -+{ -+ grub_disk_addr_t addr; -+ -+ if (grub_le_to_cpu32 (header->headersize) != sizeof (*header)) -+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, -+ "Header size is %u, must be %u", -+ grub_le_to_cpu32 (header->headersize), -+ sizeof (*header)); -+ -+ addr = grub_gpt_sector_to_addr (gpt, grub_le_to_cpu64 (header->header_lba)); -+ if (addr == 0) -+ return grub_error (GRUB_ERR_BUG, -+ "Refusing to write GPT header to address 0x0"); -+ if (grub_disk_write (disk, addr, 0, sizeof (*header), header)) -+ return grub_errno; -+ -+ addr = grub_gpt_sector_to_addr (gpt, grub_le_to_cpu64 (header->partitions)); -+ if (addr < 2) -+ return grub_error (GRUB_ERR_BUG, -+ "Refusing to write GPT entries to address 0x%llx", -+ (unsigned long long) addr); -+ if (grub_disk_write (disk, addr, 0, gpt->entries_size, gpt->entries)) -+ return grub_errno; -+ -+ return GRUB_ERR_NONE; -+} -+ -+grub_err_t -+grub_gpt_write (grub_disk_t disk, grub_gpt_t gpt) -+{ -+ grub_uint64_t backup_header; -+ -+ /* TODO: update/repair protective MBRs too. */ -+ -+ if (!grub_gpt_both_valid (gpt)) -+ return grub_error (GRUB_ERR_BAD_PART_TABLE, "Invalid GPT data"); -+ -+ /* Write the backup GPT first so if writing fails the update is aborted -+ * and the primary is left intact. However if the backup location is -+ * inaccessible we have to just skip and hope for the best, the backup -+ * will need to be repaired in the OS. */ -+ backup_header = grub_le_to_cpu64 (gpt->backup.header_lba); -+ if (grub_gpt_disk_size_valid (disk) && -+ backup_header >= disk->total_sectors) -+ { -+ grub_printf ("warning: backup GPT located at 0x%llx, " -+ "beyond last disk sector at 0x%llx\n", -+ (unsigned long long) backup_header, -+ (unsigned long long) disk->total_sectors - 1); -+ grub_printf ("warning: only writing primary GPT, " -+ "the backup GPT must be repaired from the OS\n"); -+ } -+ else -+ { -+ grub_dprintf ("gpt", "writing backup GPT to %s\n", disk->name); -+ if (grub_gpt_write_table (disk, gpt, &gpt->backup)) -+ return grub_errno; -+ } -+ -+ grub_dprintf ("gpt", "writing primary GPT to %s\n", disk->name); -+ if (grub_gpt_write_table (disk, gpt, &gpt->primary)) -+ return grub_errno; -+ -+ return GRUB_ERR_NONE; -+} -+ -+void -+grub_gpt_free (grub_gpt_t gpt) -+{ -+ if (!gpt) -+ return; -+ -+ grub_free (gpt->entries); -+ grub_free (gpt); -+} -diff --git a/include/grub/gpt_partition.h b/include/grub/gpt_partition.h -index 7a93f4329..5c4372dce 100644 ---- a/include/grub/gpt_partition.h -+++ b/include/grub/gpt_partition.h -@@ -21,6 +21,7 @@ - - #include - #include -+#include - - struct grub_gpt_part_guid - { -@@ -30,25 +31,46 @@ struct grub_gpt_part_guid - grub_uint8_t data4[8]; - } GRUB_PACKED; - typedef struct grub_gpt_part_guid grub_gpt_part_guid_t; -+typedef struct grub_gpt_part_guid grub_gpt_guid_t; -+typedef struct grub_gpt_part_guid grub_gpt_part_type_t; - --#define GRUB_GPT_PARTITION_TYPE_EMPTY \ -- { 0x0, 0x0, 0x0, \ -- { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } \ -+/* Format the raw little-endian GUID as a newly allocated string. */ -+char * grub_gpt_guid_to_str (grub_gpt_guid_t *guid); -+ -+ -+#define GRUB_GPT_GUID_INIT(a, b, c, d1, d2, d3, d4, d5, d6, d7, d8) \ -+ { \ -+ grub_cpu_to_le32_compile_time (a), \ -+ grub_cpu_to_le16_compile_time (b), \ -+ grub_cpu_to_le16_compile_time (c), \ -+ { d1, d2, d3, d4, d5, d6, d7, d8 } \ - } - -+#define GRUB_GPT_PARTITION_TYPE_EMPTY \ -+ GRUB_GPT_GUID_INIT (0x0, 0x0, 0x0, \ -+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0) -+ -+#define GRUB_GPT_PARTITION_TYPE_EFI_SYSTEM \ -+ GRUB_GPT_GUID_INIT (0xc12a7328, 0xf81f, 0x11d2, \ -+ 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b) -+ - #define GRUB_GPT_PARTITION_TYPE_BIOS_BOOT \ -- { grub_cpu_to_le32_compile_time (0x21686148), \ -- grub_cpu_to_le16_compile_time (0x6449), \ -- grub_cpu_to_le16_compile_time (0x6e6f), \ -- { 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 } \ -- } -+ GRUB_GPT_GUID_INIT (0x21686148, 0x6449, 0x6e6f, \ -+ 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49) - - #define GRUB_GPT_PARTITION_TYPE_LDM \ -- { grub_cpu_to_le32_compile_time (0x5808C8AAU),\ -- grub_cpu_to_le16_compile_time (0x7E8F), \ -- grub_cpu_to_le16_compile_time (0x42E0), \ -- { 0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34, 0xCF, 0xB3 } \ -- } -+ GRUB_GPT_GUID_INIT (0x5808c8aa, 0x7e8f, 0x42e0, \ -+ 0x85, 0xd2, 0xe1, 0xe9, 0x04, 0x34, 0xcf, 0xb3) -+ -+#define GRUB_GPT_PARTITION_TYPE_USR_X86_64 \ -+ GRUB_GPT_GUID_INIT (0x5dfbf5f4, 0x2848, 0x4bac, \ -+ 0xaa, 0x5e, 0x0d, 0x9a, 0x20, 0xb7, 0x45, 0xa6) -+ -+#define GRUB_GPT_HEADER_MAGIC \ -+ { 0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54 } -+ -+#define GRUB_GPT_HEADER_VERSION \ -+ grub_cpu_to_le32_compile_time (0x00010000U) - - struct grub_gpt_header - { -@@ -57,11 +79,11 @@ struct grub_gpt_header - grub_uint32_t headersize; - grub_uint32_t crc32; - grub_uint32_t unused1; -- grub_uint64_t primary; -- grub_uint64_t backup; -+ grub_uint64_t header_lba; -+ grub_uint64_t alternate_lba; - grub_uint64_t start; - grub_uint64_t end; -- grub_uint8_t guid[16]; -+ grub_gpt_part_guid_t guid; - grub_uint64_t partitions; - grub_uint32_t maxpart; - grub_uint32_t partentry_size; -@@ -75,13 +97,168 @@ struct grub_gpt_partentry - grub_uint64_t start; - grub_uint64_t end; - grub_uint64_t attrib; -- char name[72]; -+ grub_uint16_t name[36]; - } GRUB_PACKED; - -+enum grub_gpt_part_attr_offset -+{ -+ /* Standard partition attribute bits defined by UEFI. */ -+ GRUB_GPT_PART_ATTR_OFFSET_REQUIRED = 0, -+ GRUB_GPT_PART_ATTR_OFFSET_NO_BLOCK_IO_PROTOCOL = 1, -+ GRUB_GPT_PART_ATTR_OFFSET_LEGACY_BIOS_BOOTABLE = 2, -+ -+ /* De facto standard attribute bits defined by Microsoft and reused by -+ * http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec */ -+ GRUB_GPT_PART_ATTR_OFFSET_READ_ONLY = 60, -+ GRUB_GPT_PART_ATTR_OFFSET_NO_AUTO = 63, -+ -+ /* Partition attributes for priority based selection, -+ * Currently only valid for PARTITION_TYPE_USR_X86_64. -+ * TRIES_LEFT and PRIORITY are 4 bit wide fields. */ -+ GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_PRIORITY = 48, -+ GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_TRIES_LEFT = 52, -+ GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_SUCCESSFUL = 56, -+}; -+ -+/* Helpers for reading/writing partition attributes. */ -+static inline grub_uint64_t -+grub_gpt_entry_attribute (struct grub_gpt_partentry *entry, -+ enum grub_gpt_part_attr_offset offset, -+ unsigned int bits) -+{ -+ grub_uint64_t attrib = grub_le_to_cpu64 (entry->attrib); -+ -+ return (attrib >> offset) & ((1ULL << bits) - 1); -+} -+ -+static inline void -+grub_gpt_entry_set_attribute (struct grub_gpt_partentry *entry, -+ grub_uint64_t value, -+ enum grub_gpt_part_attr_offset offset, -+ unsigned int bits) -+{ -+ grub_uint64_t attrib, mask; -+ -+ mask = (((1ULL << bits) - 1) << offset); -+ attrib = grub_le_to_cpu64 (entry->attrib) & ~mask; -+ attrib |= ((value << offset) & mask); -+ entry->attrib = grub_cpu_to_le64 (attrib); -+} -+ -+/* Basic GPT partmap module. */ - grub_err_t - grub_gpt_partition_map_iterate (grub_disk_t disk, - grub_partition_iterate_hook_t hook, - void *hook_data); - -+/* Advanced GPT library. */ -+ -+/* Status bits for the grub_gpt.status field. */ -+#define GRUB_GPT_PROTECTIVE_MBR 0x01 -+#define GRUB_GPT_HYBRID_MBR 0x02 -+#define GRUB_GPT_PRIMARY_HEADER_VALID 0x04 -+#define GRUB_GPT_PRIMARY_ENTRIES_VALID 0x08 -+#define GRUB_GPT_BACKUP_HEADER_VALID 0x10 -+#define GRUB_GPT_BACKUP_ENTRIES_VALID 0x20 -+ -+/* UEFI requires the entries table to be at least 16384 bytes for a -+ * total of 128 entries given the standard 128 byte entry size. */ -+#define GRUB_GPT_DEFAULT_ENTRIES_SIZE 16384 -+#define GRUB_GPT_DEFAULT_ENTRIES_LENGTH \ -+ (GRUB_GPT_DEFAULT_ENTRIES_SIZE / sizeof (struct grub_gpt_partentry)) -+ -+struct grub_gpt -+{ -+ /* Bit field indicating which structures on disk are valid. */ -+ unsigned status; -+ -+ /* Protective or hybrid MBR. */ -+ struct grub_msdos_partition_mbr mbr; -+ -+ /* Each of the two GPT headers. */ -+ struct grub_gpt_header primary; -+ struct grub_gpt_header backup; -+ -+ /* Only need one entries table, on disk both copies are identical. -+ * The on disk entry size may be larger than our partentry struct so -+ * the table cannot be indexed directly. */ -+ void *entries; -+ grub_size_t entries_size; -+ -+ /* Logarithm of sector size, in case GPT and disk driver disagree. */ -+ unsigned int log_sector_size; -+}; -+typedef struct grub_gpt *grub_gpt_t; -+ -+/* Helpers for checking the gpt status field. */ -+static inline int -+grub_gpt_mbr_valid (grub_gpt_t gpt) -+{ -+ return ((gpt->status & GRUB_GPT_PROTECTIVE_MBR) || -+ (gpt->status & GRUB_GPT_HYBRID_MBR)); -+} -+ -+static inline int -+grub_gpt_primary_valid (grub_gpt_t gpt) -+{ -+ return ((gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID) && -+ (gpt->status & GRUB_GPT_PRIMARY_ENTRIES_VALID)); -+} -+ -+static inline int -+grub_gpt_backup_valid (grub_gpt_t gpt) -+{ -+ return ((gpt->status & GRUB_GPT_BACKUP_HEADER_VALID) && -+ (gpt->status & GRUB_GPT_BACKUP_ENTRIES_VALID)); -+} -+ -+static inline int -+grub_gpt_both_valid (grub_gpt_t gpt) -+{ -+ return grub_gpt_primary_valid (gpt) && grub_gpt_backup_valid (gpt); -+} -+ -+/* Translate GPT sectors to GRUB's 512 byte block addresses. */ -+static inline grub_disk_addr_t -+grub_gpt_sector_to_addr (grub_gpt_t gpt, grub_uint64_t sector) -+{ -+ return (sector << (gpt->log_sector_size - GRUB_DISK_SECTOR_BITS)); -+} -+ -+/* Allocates and fills new grub_gpt structure, free with grub_gpt_free. */ -+grub_gpt_t grub_gpt_read (grub_disk_t disk); -+ -+/* Helper for indexing into the entries table. -+ * Returns NULL when the end of the table has been reached. */ -+struct grub_gpt_partentry * grub_gpt_get_partentry (grub_gpt_t gpt, -+ grub_uint32_t n); -+ -+/* Sync and update primary and backup headers if either are invalid. */ -+grub_err_t grub_gpt_repair (grub_disk_t disk, grub_gpt_t gpt); -+ -+/* Recompute checksums and revalidate everything, must be called after -+ * modifying any GPT data. */ -+grub_err_t grub_gpt_update (grub_gpt_t gpt); -+ -+/* Write headers and entry tables back to disk. */ -+grub_err_t grub_gpt_write (grub_disk_t disk, grub_gpt_t gpt); -+ -+void grub_gpt_free (grub_gpt_t gpt); -+ -+grub_err_t grub_gpt_pmbr_check (struct grub_msdos_partition_mbr *mbr); -+grub_err_t grub_gpt_header_check (struct grub_gpt_header *gpt, -+ unsigned int log_sector_size); -+ -+ -+/* Utilities for simple partition data lookups, usage is intended to -+ * be similar to fs->label and fs->uuid functions. */ -+ -+/* Return the partition label of the device DEVICE in LABEL. -+ * The label is in a new buffer and should be freed by the caller. */ -+grub_err_t grub_gpt_part_label (grub_device_t device, char **label); -+ -+/* Return the partition uuid of the device DEVICE in UUID. -+ * The uuid is in a new buffer and should be freed by the caller. */ -+grub_err_t grub_gpt_part_uuid (grub_device_t device, char **uuid); - - #endif /* ! GRUB_GPT_PARTITION_HEADER */ -diff --git a/include/grub/search.h b/include/grub/search.h -index d80347df3..c2f40abe9 100644 ---- a/include/grub/search.h -+++ b/include/grub/search.h -@@ -25,5 +25,9 @@ void grub_search_fs_uuid (const char *key, const char *var, int no_floppy, - char **hints, unsigned nhints); - void grub_search_label (const char *key, const char *var, int no_floppy, - char **hints, unsigned nhints); -+void grub_search_part_uuid (const char *key, const char *var, int no_floppy, -+ char **hints, unsigned nhints); -+void grub_search_part_label (const char *key, const char *var, int no_floppy, -+ char **hints, unsigned nhints); - - #endif -diff --git a/tests/gpt_unit_test.c b/tests/gpt_unit_test.c -new file mode 100644 -index 000000000..53f686912 ---- /dev/null -+++ b/tests/gpt_unit_test.c -@@ -0,0 +1,807 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2014 CoreOS, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* from gnulib */ -+#include -+ -+/* Confirm that the GPT structures conform to the sizes in the spec: -+ * The header size "must be greater than or equal to 92 and must be less -+ * than or equal to the logical block size." -+ * The partition entry size must be "a value of 128*(2^n) where n is an -+ * integer greater than or equal to zero (e.g., 128, 256, 512, etc.)." */ -+verify (sizeof (struct grub_gpt_header) == 92); -+verify (sizeof (struct grub_gpt_partentry) == 128); -+ -+/* GPT section sizes. */ -+#define HEADER_SIZE (sizeof (struct grub_gpt_header)) -+#define HEADER_PAD (GRUB_DISK_SECTOR_SIZE - HEADER_SIZE) -+#define ENTRY_SIZE (sizeof (struct grub_gpt_partentry)) -+#define TABLE_ENTRIES 0x80 -+#define TABLE_SIZE (TABLE_ENTRIES * ENTRY_SIZE) -+#define TABLE_SECTORS (TABLE_SIZE / GRUB_DISK_SECTOR_SIZE) -+ -+/* Double check that the table size calculation was valid. */ -+verify (TABLE_SECTORS * GRUB_DISK_SECTOR_SIZE == TABLE_SIZE); -+ -+/* GPT section locations for a 1MiB disk. */ -+#define DISK_SECTORS 0x800 -+#define DISK_SIZE (GRUB_DISK_SECTOR_SIZE * DISK_SECTORS) -+#define PRIMARY_HEADER_SECTOR 0x1 -+#define PRIMARY_TABLE_SECTOR 0x2 -+#define BACKUP_HEADER_SECTOR (DISK_SECTORS - 0x1) -+#define BACKUP_TABLE_SECTOR (BACKUP_HEADER_SECTOR - TABLE_SECTORS) -+ -+#define DATA_START_SECTOR (PRIMARY_TABLE_SECTOR + TABLE_SECTORS) -+#define DATA_END_SECTOR (BACKUP_TABLE_SECTOR - 0x1) -+#define DATA_SECTORS (BACKUP_TABLE_SECTOR - DATA_START_SECTOR) -+#define DATA_SIZE (GRUB_DISK_SECTOR_SIZE * DATA_SECTORS) -+ -+struct test_disk -+{ -+ struct grub_msdos_partition_mbr mbr; -+ -+ struct grub_gpt_header primary_header; -+ grub_uint8_t primary_header_pad[HEADER_PAD]; -+ struct grub_gpt_partentry primary_entries[TABLE_ENTRIES]; -+ -+ grub_uint8_t data[DATA_SIZE]; -+ -+ struct grub_gpt_partentry backup_entries[TABLE_ENTRIES]; -+ struct grub_gpt_header backup_header; -+ grub_uint8_t backup_header_pad[HEADER_PAD]; -+} GRUB_PACKED; -+ -+/* Sanity check that all the above ugly math was correct. */ -+verify (sizeof (struct test_disk) == DISK_SIZE); -+ -+struct test_data -+{ -+ int fd; -+ grub_device_t dev; -+ struct test_disk *raw; -+}; -+ -+ -+/* Sample primary GPT header for a 1MB disk. */ -+static const struct grub_gpt_header example_primary = { -+ .magic = GRUB_GPT_HEADER_MAGIC, -+ .version = GRUB_GPT_HEADER_VERSION, -+ .headersize = sizeof (struct grub_gpt_header), -+ .crc32 = grub_cpu_to_le32_compile_time (0xb985abe0), -+ .header_lba = grub_cpu_to_le64_compile_time (PRIMARY_HEADER_SECTOR), -+ .alternate_lba = grub_cpu_to_le64_compile_time (BACKUP_HEADER_SECTOR), -+ .start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR), -+ .end = grub_cpu_to_le64_compile_time (DATA_END_SECTOR), -+ .guid = GRUB_GPT_GUID_INIT(0x69c131ad, 0x67d6, 0x46c6, -+ 0x93, 0xc4, 0x12, 0x4c, 0x75, 0x52, 0x56, 0xac), -+ .partitions = grub_cpu_to_le64_compile_time (PRIMARY_TABLE_SECTOR), -+ .maxpart = grub_cpu_to_le32_compile_time (TABLE_ENTRIES), -+ .partentry_size = grub_cpu_to_le32_compile_time (ENTRY_SIZE), -+ .partentry_crc32 = grub_cpu_to_le32_compile_time (0x074e052c), -+}; -+ -+static const struct grub_gpt_partentry example_entries[TABLE_ENTRIES] = { -+ { -+ .type = GRUB_GPT_PARTITION_TYPE_EFI_SYSTEM, -+ .guid = GRUB_GPT_GUID_INIT (0xa0f1792e, 0xb4ce, 0x4136, 0xbc, 0xf2, -+ 0x1a, 0xfc, 0x13, 0x3c, 0x28, 0x28), -+ .start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR), -+ .end = grub_cpu_to_le64_compile_time (0x3f), -+ .attrib = 0x0, -+ .name = { -+ grub_cpu_to_le16_compile_time ('E'), -+ grub_cpu_to_le16_compile_time ('F'), -+ grub_cpu_to_le16_compile_time ('I'), -+ grub_cpu_to_le16_compile_time (' '), -+ grub_cpu_to_le16_compile_time ('S'), -+ grub_cpu_to_le16_compile_time ('Y'), -+ grub_cpu_to_le16_compile_time ('S'), -+ grub_cpu_to_le16_compile_time ('T'), -+ grub_cpu_to_le16_compile_time ('E'), -+ grub_cpu_to_le16_compile_time ('M'), -+ 0x0, -+ } -+ }, -+ { -+ .type = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT, -+ .guid = GRUB_GPT_GUID_INIT (0x876c898d, 0x1b40, 0x4727, 0xa1, 0x61, -+ 0xed, 0xf9, 0xb5, 0x48, 0x66, 0x74), -+ .start = grub_cpu_to_le64_compile_time (0x40), -+ .end = grub_cpu_to_le64_compile_time (0x7f), -+ .attrib = grub_cpu_to_le64_compile_time ( -+ 1ULL << GRUB_GPT_PART_ATTR_OFFSET_LEGACY_BIOS_BOOTABLE), -+ .name = { -+ grub_cpu_to_le16_compile_time ('B'), -+ grub_cpu_to_le16_compile_time ('I'), -+ grub_cpu_to_le16_compile_time ('O'), -+ grub_cpu_to_le16_compile_time ('S'), -+ grub_cpu_to_le16_compile_time (' '), -+ grub_cpu_to_le16_compile_time ('B'), -+ grub_cpu_to_le16_compile_time ('O'), -+ grub_cpu_to_le16_compile_time ('O'), -+ grub_cpu_to_le16_compile_time ('T'), -+ 0x0, -+ } -+ }, -+}; -+ -+/* And the backup header. */ -+static const struct grub_gpt_header example_backup = { -+ .magic = GRUB_GPT_HEADER_MAGIC, -+ .version = GRUB_GPT_HEADER_VERSION, -+ .headersize = sizeof (struct grub_gpt_header), -+ .crc32 = grub_cpu_to_le32_compile_time (0x0af785eb), -+ .header_lba = grub_cpu_to_le64_compile_time (BACKUP_HEADER_SECTOR), -+ .alternate_lba = grub_cpu_to_le64_compile_time (PRIMARY_HEADER_SECTOR), -+ .start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR), -+ .end = grub_cpu_to_le64_compile_time (DATA_END_SECTOR), -+ .guid = GRUB_GPT_GUID_INIT(0x69c131ad, 0x67d6, 0x46c6, -+ 0x93, 0xc4, 0x12, 0x4c, 0x75, 0x52, 0x56, 0xac), -+ .partitions = grub_cpu_to_le64_compile_time (BACKUP_TABLE_SECTOR), -+ .maxpart = grub_cpu_to_le32_compile_time (TABLE_ENTRIES), -+ .partentry_size = grub_cpu_to_le32_compile_time (ENTRY_SIZE), -+ .partentry_crc32 = grub_cpu_to_le32_compile_time (0x074e052c), -+}; -+ -+/* Sample protective MBR for the same 1MB disk. Note, this matches -+ * parted and fdisk behavior. The UEFI spec uses different values. */ -+static const struct grub_msdos_partition_mbr example_pmbr = { -+ .entries = {{.flag = 0x00, -+ .start_head = 0x00, -+ .start_sector = 0x01, -+ .start_cylinder = 0x00, -+ .type = 0xee, -+ .end_head = 0xfe, -+ .end_sector = 0xff, -+ .end_cylinder = 0xff, -+ .start = grub_cpu_to_le32_compile_time (0x1), -+ .length = grub_cpu_to_le32_compile_time (DISK_SECTORS - 0x1), -+ }}, -+ .signature = grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE), -+}; -+ -+/* If errors are left in grub's error stack things can get confused. */ -+static void -+assert_error_stack_empty (void) -+{ -+ do -+ { -+ grub_test_assert (grub_errno == GRUB_ERR_NONE, -+ "error on stack: %s", grub_errmsg); -+ } -+ while (grub_error_pop ()); -+} -+ -+static grub_err_t -+execute_command2 (const char *name, const char *arg1, const char *arg2) -+{ -+ grub_command_t cmd; -+ grub_err_t err; -+ char *argv[2]; -+ -+ cmd = grub_command_find (name); -+ if (!cmd) -+ grub_fatal ("can't find command %s", name); -+ -+ argv[0] = strdup (arg1); -+ argv[1] = strdup (arg2); -+ err = (cmd->func) (cmd, 2, argv); -+ free (argv[0]); -+ free (argv[1]); -+ -+ return err; -+} -+ -+static void -+sync_disk (struct test_data *data) -+{ -+ if (msync (data->raw, DISK_SIZE, MS_SYNC | MS_INVALIDATE) < 0) -+ grub_fatal ("Syncing disk failed: %s", strerror (errno)); -+ -+ grub_disk_cache_invalidate_all (); -+} -+ -+static void -+reset_disk (struct test_data *data) -+{ -+ memset (data->raw, 0, DISK_SIZE); -+ -+ /* Initialize image with valid example tables. */ -+ memcpy (&data->raw->mbr, &example_pmbr, sizeof (data->raw->mbr)); -+ memcpy (&data->raw->primary_header, &example_primary, -+ sizeof (data->raw->primary_header)); -+ memcpy (&data->raw->primary_entries, &example_entries, -+ sizeof (data->raw->primary_entries)); -+ memcpy (&data->raw->backup_entries, &example_entries, -+ sizeof (data->raw->backup_entries)); -+ memcpy (&data->raw->backup_header, &example_backup, -+ sizeof (data->raw->backup_header)); -+ -+ sync_disk (data); -+} -+ -+static void -+open_disk (struct test_data *data) -+{ -+ const char *loop = "loop0"; -+ char template[] = "/tmp/grub_gpt_test.XXXXXX"; -+ char host[sizeof ("(host)") + sizeof (template)]; -+ -+ data->fd = mkstemp (template); -+ if (data->fd < 0) -+ grub_fatal ("Creating %s failed: %s", template, strerror (errno)); -+ -+ if (ftruncate (data->fd, DISK_SIZE) < 0) -+ { -+ int err = errno; -+ unlink (template); -+ grub_fatal ("Resizing %s failed: %s", template, strerror (err)); -+ } -+ -+ data->raw = mmap (NULL, DISK_SIZE, PROT_READ | PROT_WRITE, -+ MAP_SHARED, data->fd, 0); -+ if (data->raw == MAP_FAILED) -+ { -+ int err = errno; -+ unlink (template); -+ grub_fatal ("Maping %s failed: %s", template, strerror (err)); -+ } -+ -+ snprintf (host, sizeof (host), "(host)%s", template); -+ if (execute_command2 ("loopback", loop, host) != GRUB_ERR_NONE) -+ { -+ unlink (template); -+ grub_fatal ("loopback %s %s failed: %s", loop, host, grub_errmsg); -+ } -+ -+ if (unlink (template) < 0) -+ grub_fatal ("Unlinking %s failed: %s", template, strerror (errno)); -+ -+ reset_disk (data); -+ -+ data->dev = grub_device_open (loop); -+ if (!data->dev) -+ grub_fatal ("Opening %s failed: %s", loop, grub_errmsg); -+} -+ -+static void -+close_disk (struct test_data *data) -+{ -+ char *loop; -+ -+ assert_error_stack_empty (); -+ -+ if (munmap (data->raw, DISK_SIZE) || close (data->fd)) -+ grub_fatal ("Closing disk image failed: %s", strerror (errno)); -+ -+ loop = strdup (data->dev->disk->name); -+ grub_test_assert (grub_device_close (data->dev) == GRUB_ERR_NONE, -+ "Closing disk device failed: %s", grub_errmsg); -+ -+ grub_test_assert (execute_command2 ("loopback", "-d", loop) == -+ GRUB_ERR_NONE, "loopback -d %s failed: %s", loop, -+ grub_errmsg); -+ -+ free (loop); -+} -+ -+static grub_gpt_t -+read_disk (struct test_data *data) -+{ -+ grub_gpt_t gpt; -+ -+ gpt = grub_gpt_read (data->dev->disk); -+ if (gpt == NULL) -+ grub_fatal ("grub_gpt_read failed: %s", grub_errmsg); -+ -+ return gpt; -+} -+ -+static void -+pmbr_test (void) -+{ -+ struct grub_msdos_partition_mbr mbr; -+ -+ memset (&mbr, 0, sizeof (mbr)); -+ -+ /* Empty is invalid. */ -+ grub_gpt_pmbr_check (&mbr); -+ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE, -+ "unexpected error: %s", grub_errmsg); -+ grub_errno = GRUB_ERR_NONE; -+ -+ /* A table without a protective partition is invalid. */ -+ mbr.signature = grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE); -+ grub_gpt_pmbr_check (&mbr); -+ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE, -+ "unexpected error: %s", grub_errmsg); -+ grub_errno = GRUB_ERR_NONE; -+ -+ /* A table with a protective type is ok. */ -+ memcpy (&mbr, &example_pmbr, sizeof (mbr)); -+ grub_gpt_pmbr_check (&mbr); -+ grub_test_assert (grub_errno == GRUB_ERR_NONE, -+ "unexpected error: %s", grub_errmsg); -+ grub_errno = GRUB_ERR_NONE; -+} -+ -+static void -+header_test (void) -+{ -+ struct grub_gpt_header primary, backup; -+ -+ /* Example headers should be valid. */ -+ memcpy (&primary, &example_primary, sizeof (primary)); -+ grub_gpt_header_check (&primary, GRUB_DISK_SECTOR_BITS); -+ grub_test_assert (grub_errno == GRUB_ERR_NONE, -+ "unexpected error: %s", grub_errmsg); -+ grub_errno = GRUB_ERR_NONE; -+ -+ memcpy (&backup, &example_backup, sizeof (backup)); -+ grub_gpt_header_check (&backup, GRUB_DISK_SECTOR_BITS); -+ grub_test_assert (grub_errno == GRUB_ERR_NONE, -+ "unexpected error: %s", grub_errmsg); -+ grub_errno = GRUB_ERR_NONE; -+ -+ /* Twiddle the GUID to invalidate the CRC. */ -+ primary.guid.data1 = 0; -+ grub_gpt_header_check (&primary, GRUB_DISK_SECTOR_BITS); -+ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE, -+ "unexpected error: %s", grub_errmsg); -+ grub_errno = GRUB_ERR_NONE; -+ -+ backup.guid.data1 = 0; -+ grub_gpt_header_check (&backup, GRUB_DISK_SECTOR_BITS); -+ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE, -+ "unexpected error: %s", grub_errmsg); -+ grub_errno = GRUB_ERR_NONE; -+} -+ -+static void -+read_valid_test (void) -+{ -+ struct test_data data; -+ grub_gpt_t gpt; -+ -+ open_disk (&data); -+ gpt = read_disk (&data); -+ grub_test_assert (gpt->status == (GRUB_GPT_PROTECTIVE_MBR | -+ GRUB_GPT_PRIMARY_HEADER_VALID | -+ GRUB_GPT_PRIMARY_ENTRIES_VALID | -+ GRUB_GPT_BACKUP_HEADER_VALID | -+ GRUB_GPT_BACKUP_ENTRIES_VALID), -+ "unexpected status: 0x%02x", gpt->status); -+ grub_gpt_free (gpt); -+ close_disk (&data); -+} -+ -+static void -+read_invalid_entries_test (void) -+{ -+ struct test_data data; -+ grub_gpt_t gpt; -+ -+ open_disk (&data); -+ -+ /* Corrupt the first entry in both tables. */ -+ memset (&data.raw->primary_entries[0], 0x55, -+ sizeof (data.raw->primary_entries[0])); -+ memset (&data.raw->backup_entries[0], 0x55, -+ sizeof (data.raw->backup_entries[0])); -+ sync_disk (&data); -+ -+ gpt = grub_gpt_read (data.dev->disk); -+ grub_test_assert (gpt == NULL, "no error reported for corrupt entries"); -+ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE, -+ "unexpected error: %s", grub_errmsg); -+ grub_errno = GRUB_ERR_NONE; -+ -+ close_disk (&data); -+} -+ -+static void -+read_fallback_test (void) -+{ -+ struct test_data data; -+ grub_gpt_t gpt; -+ -+ open_disk (&data); -+ -+ /* Corrupt the primary header. */ -+ memset (&data.raw->primary_header.guid, 0x55, -+ sizeof (data.raw->primary_header.guid)); -+ sync_disk (&data); -+ gpt = read_disk (&data); -+ grub_test_assert ((gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID) == 0, -+ "unreported corrupt primary header"); -+ grub_gpt_free (gpt); -+ reset_disk (&data); -+ -+ /* Corrupt the backup header. */ -+ memset (&data.raw->backup_header.guid, 0x55, -+ sizeof (data.raw->backup_header.guid)); -+ sync_disk (&data); -+ gpt = read_disk (&data); -+ grub_test_assert ((gpt->status & GRUB_GPT_BACKUP_HEADER_VALID) == 0, -+ "unreported corrupt backup header"); -+ grub_gpt_free (gpt); -+ reset_disk (&data); -+ -+ /* Corrupt the primary entry table. */ -+ memset (&data.raw->primary_entries[0], 0x55, -+ sizeof (data.raw->primary_entries[0])); -+ sync_disk (&data); -+ gpt = read_disk (&data); -+ grub_test_assert ((gpt->status & GRUB_GPT_PRIMARY_ENTRIES_VALID) == 0, -+ "unreported corrupt primary entries table"); -+ grub_gpt_free (gpt); -+ reset_disk (&data); -+ -+ /* Corrupt the backup entry table. */ -+ memset (&data.raw->backup_entries[0], 0x55, -+ sizeof (data.raw->backup_entries[0])); -+ sync_disk (&data); -+ gpt = read_disk (&data); -+ grub_test_assert ((gpt->status & GRUB_GPT_BACKUP_ENTRIES_VALID) == 0, -+ "unreported corrupt backup entries table"); -+ grub_gpt_free (gpt); -+ reset_disk (&data); -+ -+ /* If primary is corrupt and disk size is unknown fallback fails. */ -+ memset (&data.raw->primary_header.guid, 0x55, -+ sizeof (data.raw->primary_header.guid)); -+ sync_disk (&data); -+ data.dev->disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN; -+ gpt = grub_gpt_read (data.dev->disk); -+ grub_test_assert (gpt == NULL, "no error reported"); -+ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE, -+ "unexpected error: %s", grub_errmsg); -+ grub_errno = GRUB_ERR_NONE; -+ -+ close_disk (&data); -+} -+ -+static void -+repair_test (void) -+{ -+ struct test_data data; -+ grub_gpt_t gpt; -+ -+ open_disk (&data); -+ -+ /* Erase/Repair primary. */ -+ memset (&data.raw->primary_header, 0, sizeof (data.raw->primary_header)); -+ sync_disk (&data); -+ gpt = read_disk (&data); -+ grub_gpt_repair (data.dev->disk, gpt); -+ grub_test_assert (grub_errno == GRUB_ERR_NONE, -+ "repair failed: %s", grub_errmsg); -+ if (memcmp (&gpt->primary, &example_primary, sizeof (gpt->primary))) -+ { -+ printf ("Invalid restored primary header:\n"); -+ hexdump (16, (char*)&gpt->primary, sizeof (gpt->primary)); -+ printf ("Expected primary header:\n"); -+ hexdump (16, (char*)&example_primary, sizeof (example_primary)); -+ grub_test_assert (0, "repair did not restore primary header"); -+ } -+ grub_gpt_free (gpt); -+ reset_disk (&data); -+ -+ /* Erase/Repair backup. */ -+ memset (&data.raw->backup_header, 0, sizeof (data.raw->backup_header)); -+ sync_disk (&data); -+ gpt = read_disk (&data); -+ grub_gpt_repair (data.dev->disk, gpt); -+ grub_test_assert (grub_errno == GRUB_ERR_NONE, -+ "repair failed: %s", grub_errmsg); -+ if (memcmp (&gpt->backup, &example_backup, sizeof (gpt->backup))) -+ { -+ printf ("Invalid restored backup header:\n"); -+ hexdump (16, (char*)&gpt->backup, sizeof (gpt->backup)); -+ printf ("Expected backup header:\n"); -+ hexdump (16, (char*)&example_backup, sizeof (example_backup)); -+ grub_test_assert (0, "repair did not restore backup header"); -+ } -+ grub_gpt_free (gpt); -+ reset_disk (&data); -+ -+ close_disk (&data); -+} -+ -+/* Finding/reading/writing the backup GPT may be difficult if the OS and -+ * BIOS report different sizes for the same disk. We need to gracefully -+ * recognize this and avoid causing trouble for the OS. */ -+static void -+weird_disk_size_test (void) -+{ -+ struct test_data data; -+ grub_gpt_t gpt; -+ -+ open_disk (&data); -+ -+ /* Chop off 65536 bytes (128 512B sectors) which may happen when the -+ * BIOS thinks you are using a software RAID system that reserves that -+ * area for metadata when in fact you are not and using the bare disk. */ -+ grub_test_assert(data.dev->disk->total_sectors == DISK_SECTORS, -+ "unexpected disk size: 0x%llx", -+ (unsigned long long) data.dev->disk->total_sectors); -+ data.dev->disk->total_sectors -= 128; -+ -+ gpt = read_disk (&data); -+ assert_error_stack_empty (); -+ /* Reading the alternate_lba should have been blocked and reading -+ * the (new) end of disk should have found no useful data. */ -+ grub_test_assert ((gpt->status & GRUB_GPT_BACKUP_HEADER_VALID) == 0, -+ "unreported missing backup header"); -+ -+ /* We should be able to reconstruct the backup header and the location -+ * of the backup should remain unchanged, trusting the GPT data over -+ * what the BIOS is telling us. Further changes are left to the OS. */ -+ grub_gpt_repair (data.dev->disk, gpt); -+ grub_test_assert (grub_errno == GRUB_ERR_NONE, -+ "repair failed: %s", grub_errmsg); -+ grub_test_assert (memcmp (&gpt->primary, &example_primary, -+ sizeof (gpt->primary)) == 0, -+ "repair corrupted primary header"); -+ -+ grub_gpt_free (gpt); -+ close_disk (&data); -+} -+ -+static void -+iterate_partitions_test (void) -+{ -+ struct test_data data; -+ struct grub_gpt_partentry *p; -+ grub_gpt_t gpt; -+ grub_uint32_t n; -+ -+ open_disk (&data); -+ gpt = read_disk (&data); -+ -+ for (n = 0; (p = grub_gpt_get_partentry (gpt, n)) != NULL; n++) -+ grub_test_assert (memcmp (p, &example_entries[n], sizeof (*p)) == 0, -+ "unexpected partition %d data", n); -+ -+ grub_test_assert (n == TABLE_ENTRIES, "unexpected partition limit: %d", n); -+ -+ grub_gpt_free (gpt); -+ close_disk (&data); -+} -+ -+static void -+large_partitions_test (void) -+{ -+ struct test_data data; -+ struct grub_gpt_partentry *p; -+ grub_gpt_t gpt; -+ grub_uint32_t n; -+ -+ open_disk (&data); -+ -+ /* Double the entry size, cut the number of entries in half. */ -+ data.raw->primary_header.maxpart = -+ data.raw->backup_header.maxpart = -+ grub_cpu_to_le32_compile_time (TABLE_ENTRIES/2); -+ data.raw->primary_header.partentry_size = -+ data.raw->backup_header.partentry_size = -+ grub_cpu_to_le32_compile_time (ENTRY_SIZE*2); -+ data.raw->primary_header.partentry_crc32 = -+ data.raw->backup_header.partentry_crc32 = -+ grub_cpu_to_le32_compile_time (0xf2c45af8); -+ data.raw->primary_header.crc32 = grub_cpu_to_le32_compile_time (0xde00cc8f); -+ data.raw->backup_header.crc32 = grub_cpu_to_le32_compile_time (0x6d72e284); -+ -+ memset (&data.raw->primary_entries, 0, -+ sizeof (data.raw->primary_entries)); -+ for (n = 0; n < TABLE_ENTRIES/2; n++) -+ memcpy (&data.raw->primary_entries[n*2], &example_entries[n], -+ sizeof (data.raw->primary_entries[0])); -+ memcpy (&data.raw->backup_entries, &data.raw->primary_entries, -+ sizeof (data.raw->backup_entries)); -+ -+ sync_disk(&data); -+ gpt = read_disk (&data); -+ -+ for (n = 0; (p = grub_gpt_get_partentry (gpt, n)) != NULL; n++) -+ grub_test_assert (memcmp (p, &example_entries[n], sizeof (*p)) == 0, -+ "unexpected partition %d data", n); -+ -+ grub_test_assert (n == TABLE_ENTRIES/2, "unexpected partition limit: %d", n); -+ -+ grub_gpt_free (gpt); -+ -+ /* Editing memory beyond the entry structure should still change the crc. */ -+ data.raw->primary_entries[1].attrib = 0xff; -+ -+ sync_disk(&data); -+ gpt = read_disk (&data); -+ grub_test_assert (gpt->status == (GRUB_GPT_PROTECTIVE_MBR | -+ GRUB_GPT_PRIMARY_HEADER_VALID | -+ GRUB_GPT_BACKUP_HEADER_VALID | -+ GRUB_GPT_BACKUP_ENTRIES_VALID), -+ "unexpected status: 0x%02x", gpt->status); -+ grub_gpt_free (gpt); -+ -+ close_disk (&data); -+} -+ -+static void -+invalid_partsize_test (void) -+{ -+ struct grub_gpt_header header = { -+ .magic = GRUB_GPT_HEADER_MAGIC, -+ .version = GRUB_GPT_HEADER_VERSION, -+ .headersize = sizeof (struct grub_gpt_header), -+ .crc32 = grub_cpu_to_le32_compile_time (0x1ff2a054), -+ .header_lba = grub_cpu_to_le64_compile_time (PRIMARY_HEADER_SECTOR), -+ .alternate_lba = grub_cpu_to_le64_compile_time (BACKUP_HEADER_SECTOR), -+ .start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR), -+ .end = grub_cpu_to_le64_compile_time (DATA_END_SECTOR), -+ .guid = GRUB_GPT_GUID_INIT(0x69c131ad, 0x67d6, 0x46c6, -+ 0x93, 0xc4, 0x12, 0x4c, 0x75, 0x52, 0x56, 0xac), -+ .partitions = grub_cpu_to_le64_compile_time (PRIMARY_TABLE_SECTOR), -+ .maxpart = grub_cpu_to_le32_compile_time (TABLE_ENTRIES), -+ /* Triple the entry size, which is not valid. */ -+ .partentry_size = grub_cpu_to_le32_compile_time (ENTRY_SIZE*3), -+ .partentry_crc32 = grub_cpu_to_le32_compile_time (0x074e052c), -+ }; -+ -+ grub_gpt_header_check(&header, GRUB_DISK_SECTOR_BITS); -+ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE, -+ "unexpected error: %s", grub_errmsg); -+ grub_test_assert (strcmp(grub_errmsg, "invalid GPT entry size") == 0, -+ "unexpected error: %s", grub_errmsg); -+ grub_errno = GRUB_ERR_NONE; -+} -+ -+static void -+search_part_label_test (void) -+{ -+ struct test_data data; -+ const char *test_result; -+ char *expected_result; -+ -+ open_disk (&data); -+ -+ expected_result = grub_xasprintf ("%s,gpt1", data.dev->disk->name); -+ grub_env_unset ("test_result"); -+ grub_search_part_label ("EFI SYSTEM", "test_result", 0, NULL, 0); -+ test_result = grub_env_get ("test_result"); -+ grub_test_assert (test_result && strcmp (test_result, expected_result) == 0, -+ "wrong device: %s (%s)", test_result, expected_result); -+ grub_free (expected_result); -+ -+ expected_result = grub_xasprintf ("%s,gpt2", data.dev->disk->name); -+ grub_env_unset ("test_result"); -+ grub_search_part_label ("BIOS BOOT", "test_result", 0, NULL, 0); -+ test_result = grub_env_get ("test_result"); -+ grub_test_assert (test_result && strcmp (test_result, expected_result) == 0, -+ "wrong device: %s (%s)", test_result, expected_result); -+ grub_free (expected_result); -+ -+ grub_env_unset ("test_result"); -+ grub_search_part_label ("bogus name", "test_result", 0, NULL, 0); -+ test_result = grub_env_get ("test_result"); -+ grub_test_assert (test_result == NULL, -+ "unexpected device: %s", test_result); -+ grub_test_assert (grub_errno == GRUB_ERR_FILE_NOT_FOUND, -+ "unexpected error: %s", grub_errmsg); -+ grub_errno = GRUB_ERR_NONE; -+ -+ close_disk (&data); -+} -+ -+static void -+search_part_uuid_test (void) -+{ -+ struct test_data data; -+ const char gpt1_uuid[] = "A0F1792E-B4CE-4136-BCF2-1AFC133C2828"; -+ const char gpt2_uuid[] = "876c898d-1b40-4727-a161-edf9b5486674"; -+ const char bogus_uuid[] = "1534c928-c50e-4866-9daf-6a9fd7918a76"; -+ const char *test_result; -+ char *expected_result; -+ -+ open_disk (&data); -+ -+ expected_result = grub_xasprintf ("%s,gpt1", data.dev->disk->name); -+ grub_env_unset ("test_result"); -+ grub_search_part_uuid (gpt1_uuid, "test_result", 0, NULL, 0); -+ test_result = grub_env_get ("test_result"); -+ grub_test_assert (test_result && strcmp (test_result, expected_result) == 0, -+ "wrong device: %s (%s)", test_result, expected_result); -+ grub_free (expected_result); -+ -+ expected_result = grub_xasprintf ("%s,gpt2", data.dev->disk->name); -+ grub_env_unset ("test_result"); -+ grub_search_part_uuid (gpt2_uuid, "test_result", 0, NULL, 0); -+ test_result = grub_env_get ("test_result"); -+ grub_test_assert (test_result && strcmp (test_result, expected_result) == 0, -+ "wrong device: %s (%s)", test_result, expected_result); -+ grub_free (expected_result); -+ -+ grub_env_unset ("test_result"); -+ grub_search_part_uuid (bogus_uuid, "test_result", 0, NULL, 0); -+ test_result = grub_env_get ("test_result"); -+ grub_test_assert (test_result == NULL, -+ "unexpected device: %s", test_result); -+ grub_test_assert (grub_errno == GRUB_ERR_FILE_NOT_FOUND, -+ "unexpected error: %s", grub_errmsg); -+ grub_errno = GRUB_ERR_NONE; -+ -+ close_disk (&data); -+} -+ -+void -+grub_unit_test_init (void) -+{ -+ grub_init_all (); -+ grub_hostfs_init (); -+ grub_host_init (); -+ grub_test_register ("gpt_pmbr_test", pmbr_test); -+ grub_test_register ("gpt_header_test", header_test); -+ grub_test_register ("gpt_read_valid_test", read_valid_test); -+ grub_test_register ("gpt_read_invalid_test", read_invalid_entries_test); -+ grub_test_register ("gpt_read_fallback_test", read_fallback_test); -+ grub_test_register ("gpt_repair_test", repair_test); -+ grub_test_register ("gpt_iterate_partitions_test", iterate_partitions_test); -+ grub_test_register ("gpt_large_partitions_test", large_partitions_test); -+ grub_test_register ("gpt_invalid_partsize_test", invalid_partsize_test); -+ grub_test_register ("gpt_weird_disk_size_test", weird_disk_size_test); -+ grub_test_register ("gpt_search_part_label_test", search_part_label_test); -+ grub_test_register ("gpt_search_uuid_test", search_part_uuid_test); -+} -+ -+void -+grub_unit_test_fini (void) -+{ -+ grub_test_unregister ("gpt_pmbr_test"); -+ grub_test_unregister ("gpt_header_test"); -+ grub_test_unregister ("gpt_read_valid_test"); -+ grub_test_unregister ("gpt_read_invalid_test"); -+ grub_test_unregister ("gpt_read_fallback_test"); -+ grub_test_unregister ("gpt_repair_test"); -+ grub_test_unregister ("gpt_iterate_partitions_test"); -+ grub_test_unregister ("gpt_large_partitions_test"); -+ grub_test_unregister ("gpt_invalid_partsize_test"); -+ grub_test_unregister ("gpt_weird_disk_size_test"); -+ grub_test_unregister ("gpt_search_part_label_test"); -+ grub_test_unregister ("gpt_search_part_uuid_test"); -+ grub_fini_all (); -+} -diff --git a/tests/gptprio_test.in b/tests/gptprio_test.in -new file mode 100644 -index 000000000..c5cf0f3b7 ---- /dev/null -+++ b/tests/gptprio_test.in -@@ -0,0 +1,207 @@ -+#! /bin/bash -+set -e -+ -+# Copyright (C) 2010 Free Software Foundation, Inc. -+# Copyright (C) 2014 CoreOS, Inc. -+# -+# GRUB is free software: you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation, either version 3 of the License, or -+# (at your option) any later version. -+# -+# GRUB is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with GRUB. If not, see . -+ -+sgdisk=sgdisk -+grubshell=@builddir@/grub-shell -+ -+if ! which "${sgdisk}" >/dev/null 2>&1; then -+ echo "sgdisk not installed; cannot test gptprio." -+ exit 77 -+fi -+ -+. "@builddir@/grub-core/modinfo.sh" -+ -+case "${grub_modinfo_target_cpu}-${grub_modinfo_platform}" in -+ mips-qemu_mips | mipsel-qemu_mips | i386-qemu | i386-multiboot | i386-coreboot | mipsel-loongson) -+ disk=ata0 -+ ;; -+ powerpc-ieee1275) -+ disk=ieee1275//pci@80000000/mac-io@4/ata-3@20000/disk@0 -+ # FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label. -+ exit 0 -+ ;; -+ sparc64-ieee1275) -+ disk=ieee1275//pci@1fe\,0/pci-ata@5/ide0@500/disk@0 -+ # FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label. -+ exit 0 -+ ;; -+ i386-ieee1275) -+ disk=ieee1275/d -+ # FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label. -+ exit 0 -+ ;; -+ mips-arc) -+ # FIXME: ARC firmware has bugs which prevent it from accessing hard disk w/o dvh disklabel. -+ exit 0 ;; -+ mipsel-arc) -+ disk=arc/scsi0/disk0/rdisk0 -+ ;; -+ *) -+ disk=hd0 -+ ;; -+esac -+img1="`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"`" || exit 1 -+trap "rm -f '${img1}'" EXIT -+ -+prio_type="5dfbf5f4-2848-4bac-aa5e-0d9a20b745a6" -+declare -a prio_uuid -+prio_uuid[2]="9b003904-d006-4ab3-97f1-73f547b7af1a" -+prio_uuid[3]="1aa5a658-5b02-414d-9b71-f7e6c151f0cd" -+prio_uuid[4]="8aa0240d-98af-42b0-b32a-ccbe0572d62b" -+ -+create_disk_image () { -+ size=$1 -+ rm -f "${img1}" -+ dd if=/dev/zero of="${img1}" bs=512 count=1 seek=$((size - 1)) status=none -+ ${sgdisk} \ -+ -n 1:0:+1 -c 1:ESP -t 1:ef00 \ -+ -n 2:0:+1 -c 2:A -t 2:"${prio_type}" -u 2:"${prio_uuid[2]}" \ -+ -n 3:0:+1 -c 3:B -t 3:"${prio_type}" -u 3:"${prio_uuid[3]}" \ -+ -n 4:0:+1 -c 4:C -t 4:"${prio_type}" -u 4:"${prio_uuid[4]}" \ -+ "${img1}" >/dev/null -+} -+ -+wipe_disk_area () { -+ sector=$1 -+ size=$2 -+ dd if=/dev/zero of="${img1}" bs=512 count=${size} seek=${sector} conv=notrunc status=none -+} -+ -+is_zero () { -+ sector=$1 -+ size=$2 -+ cmp -s -i $((sector * 512)) -n $((size * 512)) /dev/zero "${img1}" -+} -+ -+check_is_zero () { -+ sector=$1 -+ size=$2 -+ if ! is_zero "$@"; then -+ echo "$size sector(s) starting at $sector should be all zero" -+ exit 1 -+ fi -+} -+ -+check_not_zero () { -+ sector=$1 -+ size=$2 -+ if is_zero "$@"; then -+ echo "$size sector(s) starting at $sector should not be all zero" -+ exit 1 -+ fi -+} -+ -+fmt_prio () { -+ priority=$(( ( $1 & 15 ) << 48 )) -+ tries=$(( ( $2 & 15 ) << 52 )) -+ success=$(( ( $3 & 1 ) << 56 )) -+ printf %016x $(( priority | tries | success )) -+} -+ -+set_prio () { -+ part="$1" -+ attr=$(fmt_prio $2 $3 $4) -+ ${sgdisk} -A "${part}:=:${attr}" "${img1}" >/dev/null -+} -+ -+check_prio () { -+ part="$1" -+ expect=$(fmt_prio $2 $3 $4) -+ result=$(LANG=C ${sgdisk} -i "${part}" "${img1}" 2>&1 \ -+ | awk '/^Attribute flags: / {print $3}') -+ if [[ "${expect}" != "${result}" ]]; then -+ echo "Partition ${part} has attributes ${result:-??}, not ${expect}" -+ exit 1 -+ fi -+} -+ -+run_next() { -+ "${grubshell}" --disk="${img1}" --modules=gptprio <. -+ -+parted=parted -+grubshell=@builddir@/grub-shell -+ -+. "@builddir@/grub-core/modinfo.sh" -+ -+case "${grub_modinfo_target_cpu}-${grub_modinfo_platform}" in -+ mips-qemu_mips | mipsel-qemu_mips | i386-qemu | i386-multiboot | i386-coreboot | mipsel-loongson) -+ disk=ata0 -+ ;; -+ powerpc-ieee1275) -+ disk=ieee1275//pci@80000000/mac-io@4/ata-3@20000/disk@0 -+ # FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label. -+ exit 0 -+ ;; -+ sparc64-ieee1275) -+ disk=ieee1275//pci@1fe\,0/pci-ata@5/ide0@500/disk@0 -+ # FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label. -+ exit 0 -+ ;; -+ i386-ieee1275) -+ disk=ieee1275/d -+ # FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label. -+ exit 0 -+ ;; -+ mips-arc) -+ # FIXME: ARC firmware has bugs which prevent it from accessing hard disk w/o dvh disklabel. -+ exit 0 ;; -+ mipsel-arc) -+ disk=arc/scsi0/disk0/rdisk0 -+ ;; -+ *) -+ disk=hd0 -+ ;; -+esac -+img1="`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"`" || exit 1 -+img2="`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"`" || exit 1 -+trap "rm -f '${img1}' '${img2}'" EXIT -+ -+create_disk_image () { -+ size=$1 -+ rm -f "${img1}" -+ dd if=/dev/zero of="${img1}" bs=512 count=1 seek=$((size - 1)) status=none -+ ${parted} -a none -s "${img1}" mklabel gpt -+ cp "${img1}" "${img2}" -+} -+ -+wipe_disk_area () { -+ sector=$1 -+ size=$2 -+ dd if=/dev/zero of="${img2}" bs=512 count=${size} seek=${sector} conv=notrunc status=none -+} -+ -+do_repair () { -+ output="`echo "gptrepair ($disk)" | "${grubshell}" --disk="${img2}"`" -+ if echo "${output}" | grep ^error; then -+ return 1 -+ fi -+ if echo "${output}" | grep -v GPT; then -+ echo "Unexpected output ${output}" -+ return 1 -+ fi -+ echo "${output}" -+} -+ -+echo "Nothing to repair:" -+create_disk_image 100 -+do_repair -+cmp "${img1}" "${img2}" -+echo -+ -+echo "Repair primary (MBR left intact)" -+create_disk_image 100 -+wipe_disk_area 1 1 -+do_repair -+cmp "${img1}" "${img2}" -+echo -+ -+echo "Repair backup" -+create_disk_image 100 -+wipe_disk_area 99 1 -+do_repair -+cmp "${img1}" "${img2}" -+echo --- -2.34.1 - diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-verity-hash.patch b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-verity-hash.patch deleted file mode 100644 index ed892d90dd2..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-verity-hash.patch +++ /dev/null @@ -1,134 +0,0 @@ -From 14d4760aacb8896f99422c06d100e5231e09e797 Mon Sep 17 00:00:00 2001 -From: Sayan Chowdhury -Date: Thu, 24 Aug 2023 00:00:00 +0530 -Subject: Add verity hash passthrough - -Read the verity hash from the kernel binary and pass it to the running -system via the kernel command line - -The patch is prepared using the coreos/grub PRs, picking the only -required ones, and dropping the others. The README.md file in the -coreos-overlay/sys-boot/grub/ contains more contexual information -along with the commits used to create the patch. - -Authored-by: Matthew Garrett -Signed-off-by: Sayan Chowdhury ---- - grub-core/loader/arm64/linux.c | 6 +++- - grub-core/loader/i386/linux.c | 3 ++ - include/grub/verity-hash.h | 51 ++++++++++++++++++++++++++++++++++ - 3 files changed, 59 insertions(+), 1 deletion(-) - create mode 100644 include/grub/verity-hash.h - -diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c -index ef3e9f944..17bed4e15 100644 ---- a/grub-core/loader/arm64/linux.c -+++ b/grub-core/loader/arm64/linux.c -@@ -34,6 +34,8 @@ - #include - #include - -+#include -+ - GRUB_MOD_LICENSE ("GPLv3+"); - - static grub_dl_t my_mod; -@@ -333,7 +335,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - - grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); - -- cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE); -+ cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE) -+ + VERITY_CMDLINE_LENGTH; - linux_args = grub_malloc (cmdline_size); - if (!linux_args) - { -@@ -350,6 +353,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - - if (grub_errno == GRUB_ERR_NONE) - { -+ grub_pass_verity_hash (kernel_addr, linux_args, cmdline_size); - grub_loader_set (grub_linux_boot, grub_linux_unload, 0); - loaded = 1; - } -diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c -index 9f74a96b1..1c76ac5bf 100644 ---- a/grub-core/loader/i386/linux.c -+++ b/grub-core/loader/i386/linux.c -@@ -38,6 +38,8 @@ - #include - #include - -+#include -+ - GRUB_MOD_LICENSE ("GPLv3+"); - - #ifdef GRUB_MACHINE_PCBIOS -@@ -1006,6 +1008,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), - goto fail; - } - -+ grub_pass_verity_hash(&lh, linux_cmdline, maximal_cmdline_size); - len = prot_file_size; - if (grub_file_read (file, prot_mode_mem, len) != len && !grub_errno) - grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), -diff --git a/include/grub/verity-hash.h b/include/grub/verity-hash.h -new file mode 100644 -index 000000000..448d9aff0 ---- /dev/null -+++ b/include/grub/verity-hash.h -@@ -0,0 +1,51 @@ -+/* CoreOS verity hash */ -+ -+#define VERITY_ARG " verity.usrhash=" -+#define VERITY_ARG_LENGTH (sizeof (VERITY_ARG) - 1) -+#define VERITY_HASH_LENGTH 64 -+#define VERITY_CMDLINE_LENGTH ((VERITY_ARG_LENGTH)+(VERITY_HASH_LENGTH)) -+ -+#if defined(__aarch64__) -+# define VERITY_HASH_OFFSET 512 -+#elif defined(__i386__) || defined(__amd64__) -+# define VERITY_HASH_OFFSET 0x40 -+#else -+# error Unsupported arch -+#endif -+ -+ -+/** -+ * grub_pass_verity_hash - Reads the CoreOS verity hash value from a well known -+ * kernel image offset and adds a kernel command line argument for it. -+ * -+ * @pImage: Kernel image buffer. -+ * @cmdline: Kernel command line buffer. -+ * @cmdline_max_len: Kernel command line buffer length. -+ */ -+ -+static inline void grub_pass_verity_hash(const void *pImage, -+ char *cmdline, -+ grub_size_t cmdline_max_len) -+{ -+ const char *buf = pImage; -+ grub_size_t cmdline_len; -+ int i; -+ -+ for (i=VERITY_HASH_OFFSET; i '9') // Not a number -+ if (buf[i] < 'a' || buf[i] > 'f') // Not a hex letter -+ return; -+ } -+ -+ cmdline_len = grub_strlen(cmdline); -+ if (cmdline_len + VERITY_CMDLINE_LENGTH > cmdline_max_len) -+ return; -+ -+ grub_memcpy (cmdline + cmdline_len, VERITY_ARG, VERITY_ARG_LENGTH); -+ cmdline_len += VERITY_ARG_LENGTH; -+ grub_memcpy (cmdline + cmdline_len, buf + VERITY_HASH_OFFSET, -+ VERITY_HASH_LENGTH); -+ cmdline_len += VERITY_HASH_LENGTH; -+ cmdline[cmdline_len] = '\0'; -+} --- -2.34.1 - diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-fs-ext2-ignore-checksum-seed.patch b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-fs-ext2-ignore-checksum-seed.patch deleted file mode 100644 index 9024b479a87..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-fs-ext2-ignore-checksum-seed.patch +++ /dev/null @@ -1,62 +0,0 @@ -https://bugs.gentoo.org/894200 -https://git.savannah.gnu.org/cgit/grub.git/patch/?id=7fd5feff97c4b1f446f8fcf6d37aca0c64e7c763 - -From 7fd5feff97c4b1f446f8fcf6d37aca0c64e7c763 Mon Sep 17 00:00:00 2001 -From: Javier Martinez Canillas -Date: Fri, 11 Jun 2021 21:36:16 +0200 -Subject: fs/ext2: Ignore checksum seed incompat feature - -This incompat feature is used to denote that the filesystem stored its -metadata checksum seed in the superblock. This is used to allow tune2fs -changing the UUID on a mounted metdata_csum filesystem without having -to rewrite all the disk metadata. However, the GRUB doesn't use the -metadata checksum at all. So, it can just ignore this feature if it -is enabled. This is consistent with the GRUB filesystem code in general -which just does a best effort to access the filesystem's data. - -The checksum seed incompat feature has to be removed from the ignore -list if the support for metadata checksum verification is added to the -GRUB ext2 driver later. - -Suggested-by: Eric Sandeen -Suggested-by: Lukas Czerner -Signed-off-by: Javier Martinez Canillas -Reviewed-by: Lukas Czerner -Reviewed-by: Daniel Kiper ---- - grub-core/fs/ext2.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/grub-core/fs/ext2.c b/grub-core/fs/ext2.c -index e7dd78e..4953a15 100644 ---- a/grub-core/fs/ext2.c -+++ b/grub-core/fs/ext2.c -@@ -103,6 +103,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); - #define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 - #define EXT4_FEATURE_INCOMPAT_MMP 0x0100 - #define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 -+#define EXT4_FEATURE_INCOMPAT_CSUM_SEED 0x2000 - #define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000 - - /* The set of back-incompatible features this driver DOES support. Add (OR) -@@ -123,10 +124,15 @@ GRUB_MOD_LICENSE ("GPLv3+"); - * mmp: Not really back-incompatible - was added as such to - * avoid multiple read-write mounts. Safe to ignore for this - * RO driver. -+ * checksum seed: Not really back-incompatible - was added to allow tools -+ * such as tune2fs to change the UUID on a mounted metadata -+ * checksummed filesystem. Safe to ignore for now since the -+ * driver doesn't support checksum verification. However, it -+ * has to be removed from this list if the support is added later. - */ - #define EXT2_DRIVER_IGNORED_INCOMPAT ( EXT3_FEATURE_INCOMPAT_RECOVER \ -- | EXT4_FEATURE_INCOMPAT_MMP) -- -+ | EXT4_FEATURE_INCOMPAT_MMP \ -+ | EXT4_FEATURE_INCOMPAT_CSUM_SEED) - - #define EXT3_JOURNAL_MAGIC_NUMBER 0xc03b3998U - --- -cgit v1.1 - diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-gentpl.py-Remove-.interp-section-from-.img-files.patch b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-gentpl.py-Remove-.interp-section-from-.img-files.patch deleted file mode 100644 index 8d543d4ea9b..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-gentpl.py-Remove-.interp-section-from-.img-files.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 28ad1f9b95799afc94fa178ec935e297da94cced Mon Sep 17 00:00:00 2001 -From: Nicholas Vinson -Date: Fri, 13 Jan 2023 02:56:35 -0500 -Subject: [PATCH] gentpl.py: Remove .interp section from .img files. - -Whn building .img files, a .interp section from the .image files will -sometimes be copied into the .img file. This additional section pushes -the .img file beyond the 512-byte limit and causes grub-install to fail -to run for i386-pc platforms. - -Signed-off-by: Nicholas Vinson ---- - gentpl.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/gentpl.py b/gentpl.py -index c86550d4f..823a8b5f8 100644 ---- a/gentpl.py -+++ b/gentpl.py -@@ -766,7 +766,7 @@ def image(defn, platform): - if test x$(TARGET_APPLE_LINKER) = x1; then \ - $(MACHO2IMG) $< $@; \ - else \ -- $(TARGET_OBJCOPY) $(""" + cname(defn) + """_OBJCOPYFLAGS) --strip-unneeded -R .note -R .comment -R .note.gnu.build-id -R .MIPS.abiflags -R .reginfo -R .rel.dyn -R .note.gnu.gold-version -R .note.gnu.property -R .ARM.exidx $< $@; \ -+ $(TARGET_OBJCOPY) $(""" + cname(defn) + """_OBJCOPYFLAGS) --strip-unneeded -R .note -R .comment -R .note.gnu.build-id -R .MIPS.abiflags -R .reginfo -R .rel.dyn -R .note.gnu.gold-version -R .note.gnu.property -R .ARM.exidx -R .interp $< $@; \ - fi - """) - --- -2.39.0 - diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-grub-mkconfig-restore-umask.patch b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-grub-mkconfig-restore-umask.patch deleted file mode 100644 index e2a6414ef05..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-grub-mkconfig-restore-umask.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0adec29674561034771c13e446069b41ef41e4d4 Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Fri, 3 Dec 2021 16:13:28 +0800 -Subject: grub-mkconfig: Restore umask for the grub.cfg - -The commit ab2e53c8a (grub-mkconfig: Honor a symlink when generating -configuration by grub-mkconfig) has inadvertently discarded umask for -creating grub.cfg in the process of running grub-mkconfig. The resulting -wrong permission (0644) would allow unprivileged users to read GRUB -configuration file content. This presents a low confidentiality risk -as grub.cfg may contain non-secured plain-text passwords. - -This patch restores the missing umask and sets the creation file mode -to 0600 preventing unprivileged access. - -Fixes: CVE-2021-3981 - -Signed-off-by: Michael Chang -Reviewed-by: Daniel Kiper ---- - util/grub-mkconfig.in | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/util/grub-mkconfig.in b/util/grub-mkconfig.in -index c3ea761..62335d0 100644 ---- a/util/grub-mkconfig.in -+++ b/util/grub-mkconfig.in -@@ -301,7 +301,10 @@ and /etc/grub.d/* files or please file a bug report with - exit 1 - else - # none of the children aborted with error, install the new grub.cfg -+ oldumask=$(umask) -+ umask 077 - cat ${grub_cfg}.new > ${grub_cfg} -+ umask $oldumask - rm -f ${grub_cfg}.new - fi - fi --- -cgit v1.1 - diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-locale.patch b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-locale.patch deleted file mode 100644 index 14706cbca3a..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-locale.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 5983c2c6adf1c1bbb3ecd751253d1e898bdfd8a3 Mon Sep 17 00:00:00 2001 -From: Michael Chang -Date: Tue, 26 Oct 2021 15:11:00 +0800 -Subject: templates: Filter out POSIX locale for translation - -The POSIX locale is default or native operating system's locale -identical to the C locale, so no translation to human speaking languages -are provided. For this reason we should filter out LANG=POSIX as well as -LANG=C upon generating grub.cfg to avoid looking up for it's gettext's -message catalogs that will consequently result in an unpleasant message: - - error: file `/boot/grub/locale/POSIX.gmo' not found - -Signed-off-by: Michael Chang -Reviewed-by: Daniel Kiper ---- - util/grub.d/00_header.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in -index 93a9023..f74c2a4 100644 ---- a/util/grub.d/00_header.in -+++ b/util/grub.d/00_header.in -@@ -191,7 +191,7 @@ EOF - EOF - - # Gettext variables and module --if [ "x${LANG}" != "xC" ] && [ "x${LANG}" != "x" ]; then -+if [ "x${LANG}" != "xC" ] && [ "x${LANG}" != "xPOSIX" ] && [ "x${LANG}" != "x" ]; then - cat << EOF - set locale_dir=\$prefix/locale - set lang=${grub_lang} --- -cgit v1.1 - -From f42266a8a2a4215e4ffe419b8092bdf9ced33e8e Mon Sep 17 00:00:00 2001 -From: Christian Hesse -Date: Mon, 19 Sep 2022 15:31:28 +0200 -Subject: templates: Filter C.UTF-8 locale for translation - -In addition to C locale there is also C.UTF-8 locale now. Filter that as -well, by using ${grub_lang}, which contains a stripped value. -This fixes the following message and resulting boot failure: - - error: file `/boot/grub/locale/C.gmo' not found. - -Signed-off-by: Christian Hesse -Reviewed-by: Daniel Kiper ---- - util/grub.d/00_header.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in -index f74c2a4..6a316a5 100644 ---- a/util/grub.d/00_header.in -+++ b/util/grub.d/00_header.in -@@ -191,7 +191,7 @@ EOF - EOF - - # Gettext variables and module --if [ "x${LANG}" != "xC" ] && [ "x${LANG}" != "xPOSIX" ] && [ "x${LANG}" != "x" ]; then -+if [ "x${grub_lang}" != "xC" ] && [ "x${LANG}" != "xPOSIX" ] && [ "x${LANG}" != "x" ]; then - cat << EOF - set locale_dir=\$prefix/locale - set lang=${grub_lang} --- -cgit v1.1 - diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-riscv.patch b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-riscv.patch deleted file mode 100644 index 83c54375704..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-riscv.patch +++ /dev/null @@ -1,49 +0,0 @@ -https://bugs.gentoo.org/905785 - -From 049efdd72eb7baa7b2bf8884391ee7fe650da5a0 Mon Sep 17 00:00:00 2001 -From: Heinrich Schuchardt -Date: Sat, 29 Jan 2022 13:36:55 +0100 -Subject: RISC-V: Adjust -march flags for binutils 2.38 - -As of version 2.38 binutils defaults to ISA specification version -2019-12-13. This version of the specification has has separated the -the csr read/write (csrr*/csrw*) instructions and the fence.i from -the I extension and put them into separate Zicsr and Zifencei -extensions. - -This implies that we have to adjust the -march flag passed to the -compiler accordingly. - -Signed-off-by: Heinrich Schuchardt -Reviewed-by: Daniel Kiper ---- - configure.ac | 8 ++++++++ - 1 file changed, 8 insertions(+) - -diff --git a/configure.ac b/configure.ac -index 4f649ed..5c01af0 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -870,11 +870,19 @@ if test x"$platform" != xemu ; then - CFLAGS="$TARGET_CFLAGS -march=rv32imac -mabi=ilp32 -Werror" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], - [grub_cv_target_cc_soft_float="-march=rv32imac -mabi=ilp32"], []) -+ # ISA spec version 20191213 factored out extensions Zicsr and Zifencei -+ CFLAGS="$TARGET_CFLAGS -march=rv32imac_zicsr_zifencei -mabi=ilp32 -Werror" -+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], -+ [grub_cv_target_cc_soft_float="-march=rv32imac_zicsr_zifencei -mabi=ilp32"], []) - fi - if test "x$target_cpu" = xriscv64; then - CFLAGS="$TARGET_CFLAGS -march=rv64imac -mabi=lp64 -Werror" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], - [grub_cv_target_cc_soft_float="-march=rv64imac -mabi=lp64"], []) -+ # ISA spec version 20191213 factored out extensions Zicsr and Zifencei -+ CFLAGS="$TARGET_CFLAGS -march=rv64imac_zicsr_zifencei -mabi=lp64 -Werror" -+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], -+ [grub_cv_target_cc_soft_float="-march=rv64imac_zicsr_zifencei -mabi=lp64"], []) - fi - if test "x$target_cpu" = xia64; then - CFLAGS="$TARGET_CFLAGS -mno-inline-float-divide -mno-inline-sqrt -Werror" --- -cgit v1.1 - diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.12_rc1-util-grub.d-25_bli.in-fix-shebang-on-unmerged-usr.patch b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.12_rc1-util-grub.d-25_bli.in-fix-shebang-on-unmerged-usr.patch deleted file mode 100644 index 6c5096d35e7..00000000000 --- a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.12_rc1-util-grub.d-25_bli.in-fix-shebang-on-unmerged-usr.patch +++ /dev/null @@ -1,31 +0,0 @@ -From f827aac60d760a026db642b9d5c1ecbf587cfefc Mon Sep 17 00:00:00 2001 -From: Oskari Pirhonen -Date: Mon, 10 Jul 2023 23:55:43 -0500 -Subject: [PATCH] util/grub.d/25_bli.in: fix shebang on unmerged-usr - -On an unmerged-usr system, grub-mkconfig errors out with the following -error due to /usr/bin/sh not existing: - -/usr/sbin/grub-mkconfig: /etc/grub.d/25_bli: /usr/bin/sh: bad interpreter: No such file or directory - -Use a /bin/sh shebang to fix the error as well as match the other -existing files. - -Signed-off-by: Oskari Pirhonen ---- - util/grub.d/25_bli.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/util/grub.d/25_bli.in b/util/grub.d/25_bli.in -index 6e4538716..26e27a019 100644 ---- a/util/grub.d/25_bli.in -+++ b/util/grub.d/25_bli.in -@@ -1,4 +1,4 @@ --#!/usr/bin/sh -+#! /bin/sh - set -e - - # grub-mkconfig helper script. --- -2.41.0 - diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-2.06-r7.ebuild b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-2.06-r9.ebuild similarity index 93% rename from sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-2.06-r7.ebuild rename to sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-2.06-r9.ebuild index df7a8afb622..f372a2ec6a0 100644 --- a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-2.06-r7.ebuild +++ b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-2.06-r9.ebuild @@ -54,26 +54,19 @@ if [[ ${PV} != 9999 ]]; then " S=${WORKDIR}/${P%_*} fi - KEYWORDS="amd64 arm arm64 ~ia64 ppc ppc64 ~riscv sparc x86" + KEYWORDS="amd64 ~arm ~arm64 ~ia64 ~ppc ~ppc64 ~riscv ~sparc x86" else inherit git-r3 EGIT_REPO_URI="https://git.savannah.gnu.org/git/grub.git" fi -SRC_URI+=" https://dev.gentoo.org/~floppym/dist/${P}-backports-r2.tar.xz" +SRC_URI+=" https://dev.gentoo.org/~floppym/dist/${P}-backports-r3.tar.xz" PATCHES=( "${WORKDIR}/${P}-backports" "${FILESDIR}"/gfxpayload.patch "${FILESDIR}"/grub-2.02_beta2-KERNEL_GLOBS.patch "${FILESDIR}"/grub-2.06-test-words.patch - "${FILESDIR}"/grub-2.06-grub-mkconfig-restore-umask.patch - "${FILESDIR}"/grub-2.06-gentpl.py-Remove-.interp-section-from-.img-files.patch - "${FILESDIR}"/grub-2.06-fs-ext2-ignore-checksum-seed.patch - "${FILESDIR}"/grub-2.06-riscv.patch - "${FILESDIR}"/grub-2.06-locale.patch - "${FILESDIR}"/grub-2.06-add-verity-hash.patch - "${FILESDIR}"/grub-2.06-add-gpt-partition-scheme.patch ) DEJAVU=dejavu-sans-ttf-2.37 @@ -91,9 +84,6 @@ IUSE="device-mapper doc efiemu +fonts mount nls sdl test +themes truetype libzfs GRUB_ALL_PLATFORMS=( coreboot efi-32 efi-64 emu ieee1275 loongson multiboot qemu qemu-mips pc uboot xen xen-32 xen-pvh ) - -# Flatcar: Add arm64 to the list of platforms -GRUB_ALL_PLATFORMS+=( arm64 ) IUSE+=" ${GRUB_ALL_PLATFORMS[@]/#/grub_platforms_}" REQUIRED_USE=" @@ -109,7 +99,6 @@ BDEPEND=" sys-devel/bison sys-apps/help2man sys-apps/texinfo - grub_platforms_arm64? ( cross-aarch64-cros-linux-gnu/gcc ) fonts? ( media-libs/freetype:2 virtual/pkgconfig @@ -216,7 +205,6 @@ grub_configure() { efi*) platform=efi ;; xen-pvh) platform=xen_pvh ;; xen*) platform=xen ;; - arm64*) platform=efi ;; guessed) ;; *) platform=${MULTIBUILD_VARIANT} ;; esac From edd42f8e95bc65040e01ae0e19740114d86dc26d Mon Sep 17 00:00:00 2001 From: Sayan Chowdhury Date: Wed, 2 Aug 2023 20:01:52 +0530 Subject: [PATCH 2/3] sys-boot/grub: Apply Flatcar patches Co-authored-by: Krzesimir Nowak Signed-off-by: Sayan Chowdhury --- .../coreos-overlay/sys-boot/grub/README.md | 460 +++ .../grub-2.06-add-gpt-partition-scheme.patch | 2792 +++++++++++++++++ .../files/grub-2.06-add-verity-hash.patch | 134 + .../sys-boot/grub/grub-2.06-r9.ebuild | 13 +- 4 files changed, 3398 insertions(+), 1 deletion(-) create mode 100644 sdk_container/src/third_party/coreos-overlay/sys-boot/grub/README.md create mode 100644 sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-gpt-partition-scheme.patch create mode 100644 sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-verity-hash.patch diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/README.md b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/README.md new file mode 100644 index 00000000000..c41786a2bc4 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/README.md @@ -0,0 +1,460 @@ +Flatcar uses a patched version of the GRUB, which implements the functionality to +read the [Flatcar Container Linux partition table](https://www.flatcar.org/docs/latest/reference/developer-guides/sdk-disk-partitions/#partition-table) + +## History + +CoreOS Container Linux maintained a fork of the [grub](https://github.com/coreos/grub) and then was referenced +in the coreos-overlay. Any changes were made through [PRs](https://github.com/coreos/grub/pulls?q=is%3Apr+is%3Aclosed) to the grub repository. + +When Flatcar was born, a `grub` repo under the flatcar-linux org was created +and referenced in the Flatcar's coreos-overlay. Except for a few, now many changes +where brought into the system. + +The repo was maintained at 2.02 version. During the 2.06 migration, the philosophy +to use a separate repo was scraped, and a single patch file was created. The patch +files migrated only the essential commits, and dropped all the other commits, which +were either half-baked, or redundant at the point of migration. The two patches are applied +on top of the grub sources, and emerge is done. + +Given below are the list of commits that were referenced to create the two patches. + +## Summary of the patches + +The patch starts with adding a new implementation of reading the GPT instead +of using the traditional module. It provides essential functionality to interact +with GPT structures on disk, and checking/validating data integrity & GPT specification. + +The commits goes on to add the following modules gptprio, gptrepair, and search +commands by label and partition. + +The `gptprio` command which provides a mechanism to prioritize and select the +next bootable partition based on the GPT attributes and results in flexible +partition booting. The `gptrepair` command implements the repair functions for +GPT information on a specified device. Few other functions include searching +devices by partition label or partition UUID. + +## Commits + +Below are the commits that are picked to create the two patches for the grub. One is +descriptive, and other is comprehensive. + +
+ (click to expand) The descriptive log for all the commits picked + +``` +commit f69a9e0fdcf63ac33906e2753e14152bab2fcd05 +Author: Michael Marineau +Date: Sun Sep 28 21:26:21 2014 -0700 + + gpt: start new GPT module + + This module is a new implementation for reading GUID Partition Tables + which is much stricter than the existing part_gpt module and exports GPT + data directly instead of the generic grub_partition structure. It will + be the basis for modules that need to read/write/update GPT data. + + The current code does nothing more than read and verify the table. + +commit c26743a145c918958b862d580c4261735d1c1a6e +Author: Michael Marineau +Date: Sat Oct 18 15:39:13 2014 -0700 + + gpt: rename misnamed header location fields + + The header location fields refer to 'this header' and 'alternate header' + respectively, not 'primary header' and 'backup header'. The previous + field names are backwards for the backup header. + +commit 94f04a532d2b0e2b81e47a92488ebb1613bda1a0 +Author: Michael Marineau +Date: Sat Oct 18 16:46:17 2014 -0700 + + gpt: record size of of the entries table + + The size of the entries table will be needed later when writing it back + to disk. Restructure the entries reading code to flow a little better. + +commit 3d066264ac13198e45dc151b863a9aac4c095225 +Author: Michael Marineau +Date: Sat Oct 18 18:18:17 2014 -0700 + + gpt: consolidate crc32 computation code + + The gcrypt API is overly verbose, wrap it up in a helper function to + keep this rather common operation easy to use. + +commit dab6fac705bdad7e6ec130b24085189bcb15a5c9 +Author: Michael Marineau +Date: Sat Oct 18 18:21:07 2014 -0700 + + gpt: add new repair function to sync up primary and backup tables. + +commit 5e1829d4141343617b5e13e84298d118eac15bdf +Author: Michael Marineau +Date: Sun Oct 19 14:21:29 2014 -0700 + + gpt: add write function and gptrepair command + + The first hint of something practical, a command that can restore any of + the GPT structures from the alternate location. New test case must run + under QEMU because the loopback device used by the other unit tests does + not support writing. + +commit 2cd009dffe98c19672394608661767e4c3c84764 +Author: Michael Marineau +Date: Thu Oct 30 20:55:21 2014 -0700 + + gpt: add a new generic GUID type + + In order to do anything with partition GUIDs they need to be stored in a + proper structure like the partition type GUIDs. Additionally add an + initializer macro to simplify defining both GUID types. + +commit 508b02fc8a1fe58413ec8938ed1a7b149b5855fe +Author: Michael Marineau +Date: Mon Nov 3 17:14:37 2014 -0800 + + gpt: new gptprio.next command for selecting priority based partitions + + Basic usage would look something like this: + + gptprio.next -d usr_dev -u usr_uuid + linuxefi ($usr_dev)/boot/vmlinuz mount.usr=PARTUUID=$usr_uuid + + After booting the system should set the 'successful' bit on the + partition that was used. + +commit f8f6f790aa7448a35c2e3aae2d1a35d9d323a1b2 +Author: Michael Marineau +Date: Sat Nov 15 13:27:13 2014 -0800 + + gpt: split out checksum recomputation + + For basic data modifications the full repair function is overkill. + +commit d9bdbc10485a5c6f610569077631294683da4e34 +Author: Michael Marineau +Date: Thu Nov 27 12:55:53 2014 -0800 + + gpt: move gpt guid printing function to common library + +commit ffb13159f1e88d8c66954c3dfbeb027f943b3b1d +Author: Michael Marineau +Date: Thu Nov 27 14:54:27 2014 -0800 + + gpt: switch partition names to a 16 bit type + + In UEFI/GPT strings are UTF-16 so use a uint16 to make dealing with the + string practical. + +commit febf4666fbabc3ab4eaab32f4972b45b5c64c06d +Author: Michael Marineau +Date: Thu Nov 27 15:49:57 2014 -0800 + + tests: add some partitions to the gpt unit test data + +commit 67475f53e0ac4a844f793296ba2e4af707d5b20e +Author: Michael Marineau +Date: Thu Nov 27 16:34:21 2014 -0800 + + gpt: add search by partition label and uuid commands + + Builds on the existing filesystem search code. Only for GPT right now. + +commit d1270a2ba31cc3dd747d410a907f272ff03a6d68 +Author: Michael Marineau +Date: Fri Jul 31 15:03:11 2015 -0700 + + gpt: clean up little-endian crc32 computation + + - Remove problematic cast from *uint8_t to *uint32_t (alignment issue). + - Remove dynamic allocation and associated error handling paths. + - Match parameter ordering to existing grub_crypto_hash function. + +commit bacbed2c07f4b4e21c70310814a75fa9a1c3a155 +Author: Alex Crawford +Date: Mon Aug 31 15:23:39 2015 -0700 + + gpt: minor cleanup + +commit 1545295ad49d2aff2b75c6c0e7db58214351768e +Author: Alex Crawford +Date: Mon Aug 31 15:15:48 2015 -0700 + + gpt: add search by disk uuid command + +commit 6d4ea47541db4e0a1eab81de8843a491973e6b40 +Author: Michael Marineau +Date: Mon Jul 25 14:59:29 2016 -0700 + + gpt: do not use disk sizes GRUB will reject as invalid later on + + GRUB assumes that no disk is ever larger than 1EiB and rejects + reads/writes to such locations. Unfortunately this is not conveyed in + the usual way with the special GRUB_DISK_SIZE_UNKNOWN value. + +commit 99959fa2fb8bfafadc1fa5aec773a8d605a1df4e +Author: Michael Marineau +Date: Wed Aug 10 18:26:03 2016 -0700 + + gpt: add verbose debug logging + +commit f6b89ec3156a549999a13b3d15e9a67b4a9bf824 +Author: Michael Marineau +Date: Wed Aug 10 18:26:03 2016 -0700 + + gpt: improve validation of GPT headers + + Adds basic validation of all the disk locations in the headers, reducing + the chance of corrupting weird locations on disk. + +commit fa18d3a292bdcd61012d549c61e25d557481a05e +Author: Michael Marineau +Date: Thu Aug 11 15:02:21 2016 -0700 + + gpt: refuse to write to sector 0 + +commit b1ef48849c8dc12756793567520dfd3654539a27 +Author: Michael Marineau +Date: Sat Aug 20 17:42:12 2016 -0700 + + gpt: properly detect and repair invalid tables + + GPT_BOTH_VALID is 4 bits so simple a boolean check is not sufficient. + This broken condition allowed gptprio to trust bogus disk locations in + headers that were marked invalid causing arbitrary disk corruption. + +commit 9af98c2bfd31a73b899268e67f01bca785681d52 +Author: Michael Marineau +Date: Mon Aug 22 16:44:30 2016 -0700 + + gptrepair_test: fix typo in cleanup trap + +commit d457364d1d811ad262519cf6dde3d098caf7c778 +Author: Michael Marineau +Date: Mon Aug 22 16:45:10 2016 -0700 + + gptprio_test: check GPT is repaired when appropriate + +commit 3a3e45823dd677b428ceb40d8963676aff63f8d2 +Author: Michael Marineau +Date: Mon Aug 22 18:30:56 2016 -0700 + + fix checking alternate_lba + +commit 72b178950d313d567dfdf11f403199370d81a9f3 +Author: Michael Marineau +Date: Wed Aug 24 16:14:20 2016 -0700 + + gpt: fix partition table indexing and validation + + Portions of the code attempted to handle the fact that GPT entries on + disk may be larger than the currently defined struct while others + assumed the data could be indexed by the struct size directly. This + never came up because no utility uses a size larger than 128 bytes but + for the sake of safety we need to do this by the spec. + +commit 1d358a2061f40ad89567754f4787d0c76001d48a +Author: Michael Marineau +Date: Tue Aug 23 13:09:14 2016 -0700 + + gpt: prefer disk size from header over firmware + + The firmware and the OS may disagree on the disk configuration and size. + Although such a setup should be avoided users are unlikely to know about + the problem, assuming everything behaves like the OS. Tolerate this as + best we can and trust the reported on-disk location over the firmware + when looking for the backup GPT. If the location is inaccessible report + the error as best we can and move on. + +commit 2ed905dc03c757c92064486b380f59166cc704e8 +Author: Vito Caputo +Date: Thu Aug 25 17:21:18 2016 -0700 + + gpt: add helper for picking a valid header + + Eliminate some repetition in primary vs. backup header acquisition. + +commit 4af1d7a8b7d0cefa41a1ea4df050b161ea6cdf50 +Author: Michael Marineau +Date: Tue Sep 20 13:06:05 2016 -0700 + + gptrepair: fix status checking + + None of these status bit checks were correct. Fix and simplify. + +commit a794435ae9f5b1a2e0281d36b10545c6e643fd8d +Author: Michael Marineau +Date: Tue Sep 20 12:43:01 2016 -0700 + + gpt: use inline functions for checking status bits + + This should prevent bugs like 6078f836 and 4268f3da. + +commit 38cc185319b74d7d33ad380fe4d519fb0b0c85a6 +Author: Michael Marineau +Date: Tue Sep 20 13:40:11 2016 -0700 + + gpt: allow repair function to noop + + Simplifies usage a little. + +commit 2aeadda52929bb47089ef99c2bad0f928eadeffa +Author: Michael Marineau +Date: Wed Sep 21 13:22:06 2016 -0700 + + gpt: do not use an enum for status bit values + +commit 34652e500d64dc747ca17091b4490f9adf93ff82 +Author: Michael Marineau +Date: Wed Sep 21 13:44:11 2016 -0700 + + gpt: check header and entries status bits together + + Use the new status function which checks *_HEADER_VALID and + *_ENTRIES_VALID bits together. It doesn't make sense for the header and + entries bits to mismatch so don't allow for it. + +commit 753dd9201306e8cd7092a1231ceb194524397b04 +Author: Michael Marineau +Date: Wed Sep 21 13:52:52 2016 -0700 + + gpt: be more careful about relocating backup header + + The header was being relocated without checking the new location is + actually safe. If the BIOS thinks the disk is smaller than the OS then + repair may relocate the header into allocated space, failing the final + validation check. So only move it if the disk has grown. + + Additionally, if the backup is valid then we can assume its current + location is good enough and leave it as-is. + +commit f1f618740d1379000b04130a632f4d53bc2392b8 +Author: Michael Marineau +Date: Wed Sep 21 14:33:48 2016 -0700 + + gpt: selectively update fields during repair + + Just a little cleanup/refactor to skip touching data we don't need to. + +commit 285368e3753b1dbd631c1f5a4a127b7321a6941f +Author: Michael Marineau +Date: Wed Sep 21 14:55:19 2016 -0700 + + gpt: always revalidate when recomputing checksums + + This ensures all code modifying GPT data include the same sanity check + that repair does. If revalidation fails the status flags are left in the + appropriate state. + +commit f19f5cc49dc00752f6b267c2d580a25c31697afb +Author: Michael Marineau +Date: Wed Sep 21 15:01:09 2016 -0700 + + gpt: include backup-in-sync check in revalidation + +commit 7b25acebc343895adf942975bba5a52ef3408437 +Author: Michael Marineau +Date: Wed Sep 21 15:29:55 2016 -0700 + + gpt: read entries table at the same time as the header + + I personally think this reads easier. Also has the side effect of + directly comparing the primary and backup tables instead of presuming + they are equal if the crc32 matches. + +commit edd01f055a8a8f922491ba7077bf26fcaf015516 +Author: Michael Marineau +Date: Wed Sep 21 16:02:53 2016 -0700 + + gpt: report all revalidation errors + + Before returning an error that the primary or backup GPT is invalid push + the existing error onto the stack so the user will be told what is bad. + +commit 176fe49cf03ffdd72b8bd174a149032c3867ddde +Author: Michael Marineau +Date: Thu Sep 22 10:00:27 2016 -0700 + + gpt: rename and update documentation for grub_gpt_update + + The function now does more than just recompute checksums so give it a + more general name to reflect that. + +commit eb28d32081be2d224874c430345e7ef97bfbba07 +Author: Michael Marineau +Date: Thu Sep 22 11:18:42 2016 -0700 + + gpt: write backup GPT first, skip if inaccessible. + + Writing the primary GPT before the backup may lead to a confusing + situation: booting a freshly updated system could consistently fail and + next boot will fall back to the old system if writing the primary works + but writing the backup fails. If the backup is written first and fails + the primary is left in the old state so the next boot will re-try and + possibly fail in the exact same way. Making that repeatable should make + it easier for users to identify the error. + + Additionally if the firmware and OS disagree on the disk size, making + the backup inaccessible to GRUB, then just skip writing the backup. + When this happens the automatic call to `coreos-setgoodroot` after boot + will take care of repairing the backup. + +commit 03b547c21ec3475980a54b71e909034ed5ed5254 +Author: Matthew Garrett +Date: Thu May 28 11:15:30 2015 -0700 + + Add verity hash passthrough + + Read the verity hash from the kernel binary and pass it to the running + system via the kernel command line +``` +
+ +
+ (click to expand) Comprehensive log of the commits + +``` +f69a9e0fd gpt: start new GPT module +c26743a14 gpt: rename misnamed header location fields +94f04a532 gpt: record size of of the entries table +3d066264a gpt: consolidate crc32 computation code +dab6fac70 gpt: add new repair function to sync up primary and backup tables. +5e1829d41 gpt: add write function and gptrepair command +2cd009dff gpt: add a new generic GUID type +508b02fc8 gpt: new gptprio.next command for selecting priority based partitions +f8f6f790a gpt: split out checksum recomputation +d9bdbc104 gpt: move gpt guid printing function to common library +ffb13159f gpt: switch partition names to a 16 bit type +febf4666f tests: add some partitions to the gpt unit test data +67475f53e gpt: add search by partition label and uuid commands +d1270a2ba gpt: clean up little-endian crc32 computation +bacbed2c0 gpt: minor cleanup +1545295ad gpt: add search by disk uuid command +6d4ea4754 gpt: do not use disk sizes GRUB will reject as invalid later on +99959fa2f gpt: add verbose debug logging +f6b89ec31 gpt: improve validation of GPT headers +fa18d3a29 gpt: refuse to write to sector 0 +b1ef48849 gpt: properly detect and repair invalid tables +9af98c2bf gptrepair_test: fix typo in cleanup trap +d457364d1 gptprio_test: check GPT is repaired when appropriate +3a3e45823 fix checking alternate_lba +72b178950 gpt: fix partition table indexing and validation +1d358a206 gpt: prefer disk size from header over firmware +2ed905dc0 gpt: add helper for picking a valid header +4af1d7a8b gptrepair: fix status checking +a794435ae gpt: use inline functions for checking status bits +38cc18531 gpt: allow repair function to noop +2aeadda52 gpt: do not use an enum for status bit values +34652e500 gpt: check header and entries status bits together +753dd9201 gpt: be more careful about relocating backup header +f1f618740 gpt: selectively update fields during repair +285368e37 gpt: always revalidate when recomputing checksums +f19f5cc49 gpt: include backup-in-sync check in revalidation +7b25acebc gpt: read entries table at the same time as the header +edd01f055 gpt: report all revalidation errors +176fe49cf gpt: rename and update documentation for grub_gpt_update +eb28d3208 gpt: write backup GPT first, skip if inaccessible. +03b547c21 Add verity hash passthrough +``` +
diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-gpt-partition-scheme.patch b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-gpt-partition-scheme.patch new file mode 100644 index 00000000000..cef57e856a9 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-gpt-partition-scheme.patch @@ -0,0 +1,2792 @@ +From 026cab86883e256607f6df30375bfda4468ae71e Mon Sep 17 00:00:00 2001 +From: Sayan Chowdhury +Date: Thu, 24 Aug 2023 00:00:00 +0530 +Subject: [PATCH] gpt: Add patch to implement the custom GPT module + +This module is a new implementation for reading GUID Partition Tables +which is much stricter than the existing part_gpt module and exports GPT +data directly instead of the generic grub_partition structure. It will +be the basis for modules that need to read/write/update GPT data. + +This patch also includes the supporting functions like gptprio, +gptrepair, search commands. + +The patch is prepared using the coreos/grub PRs, picking the only +required ones, and dropping the others. The README.md file in the +coreos-overlay/sys-boot/grub/ contains more contexual information +along with the commits used to create the patch. + +Authored-by: Michael Marineau +Signed-off-by: Sayan Chowdhury +--- + Makefile.util.def | 30 + + grub-core/Makefile.core.def | 25 + + grub-core/commands/gptprio.c | 223 +++++++ + grub-core/commands/gptrepair.c | 110 ++++ + grub-core/commands/search.c | 49 ++ + grub-core/commands/search_part_label.c | 5 + + grub-core/commands/search_part_uuid.c | 5 + + grub-core/commands/search_wrap.c | 12 + + grub-core/lib/gpt.c | 757 +++++++++++++++++++++++ + include/grub/gpt_partition.h | 211 ++++++- + include/grub/search.h | 4 + + tests/gpt_unit_test.c | 807 +++++++++++++++++++++++++ + tests/gptprio_test.in | 207 +++++++ + tests/gptrepair_test.in | 102 ++++ + 14 files changed, 2530 insertions(+), 17 deletions(-) + create mode 100644 grub-core/commands/gptprio.c + create mode 100644 grub-core/commands/gptrepair.c + create mode 100644 grub-core/commands/search_part_label.c + create mode 100644 grub-core/commands/search_part_uuid.c + create mode 100644 grub-core/lib/gpt.c + create mode 100644 tests/gpt_unit_test.c + create mode 100644 tests/gptprio_test.in + create mode 100644 tests/gptrepair_test.in + +diff --git a/Makefile.util.def b/Makefile.util.def +index f8b356cc1..07df521ec 100644 +--- a/Makefile.util.def ++++ b/Makefile.util.def +@@ -1211,6 +1211,18 @@ script = { + common = tests/syslinux_test.in; + }; + ++script = { ++ testcase; ++ name = gptrepair_test; ++ common = tests/gptrepair_test.in; ++}; ++ ++script = { ++ testcase; ++ name = gptprio_test; ++ common = tests/gptprio_test.in; ++}; ++ + program = { + testcase; + name = example_unit_test; +@@ -1288,6 +1300,24 @@ program = { + ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + }; + ++program = { ++ testcase; ++ name = gpt_unit_test; ++ common = tests/gpt_unit_test.c; ++ common = tests/lib/unit_test.c; ++ common = grub-core/commands/search_part_label.c; ++ common = grub-core/commands/search_part_uuid.c; ++ common = grub-core/disk/host.c; ++ common = grub-core/kern/emu/hostfs.c; ++ common = grub-core/lib/gpt.c; ++ common = grub-core/tests/lib/test.c; ++ ldadd = libgrubmods.a; ++ ldadd = libgrubgcry.a; ++ ldadd = libgrubkern.a; ++ ldadd = grub-core/gnulib/libgnu.a; ++ ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; ++}; ++ + program = { + name = grub-menulst2cfg; + mansection = 1; +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index 8022e1c0a..e9baa2144 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -897,6 +897,21 @@ module = { + common = commands/gptsync.c; + }; + ++module = { ++ name = gptrepair; ++ common = commands/gptrepair.c; ++}; ++ ++module = { ++ name = gptprio; ++ common = commands/gptprio.c; ++}; ++ ++module = { ++ name = gpt; ++ common = lib/gpt.c; ++}; ++ + module = { + name = halt; + nopc = commands/halt.c; +@@ -1073,6 +1088,16 @@ module = { + common = commands/search_label.c; + }; + ++module = { ++ name = search_part_uuid; ++ common = commands/search_part_uuid.c; ++}; ++ ++module = { ++ name = search_part_label; ++ common = commands/search_part_label.c; ++}; ++ + module = { + name = setpci; + common = commands/setpci.c; +diff --git a/grub-core/commands/gptprio.c b/grub-core/commands/gptprio.c +new file mode 100644 +index 000000000..4a24fa62d +--- /dev/null ++++ b/grub-core/commands/gptprio.c +@@ -0,0 +1,223 @@ ++/* gptprio.c - manage priority based partition selection. */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2009 Free Software Foundation, Inc. ++ * Copyright (C) 2014 CoreOS, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static const struct grub_arg_option options_next[] = { ++ {"set-device", 'd', 0, ++ N_("Set a variable to the name of selected partition."), ++ N_("VARNAME"), ARG_TYPE_STRING}, ++ {"set-uuid", 'u', 0, ++ N_("Set a variable to the GPT UUID of selected partition."), ++ N_("VARNAME"), ARG_TYPE_STRING}, ++ {0, 0, 0, 0, 0, 0} ++}; ++ ++enum options_next ++{ ++ NEXT_SET_DEVICE, ++ NEXT_SET_UUID, ++}; ++ ++static unsigned int ++grub_gptprio_priority (struct grub_gpt_partentry *entry) ++{ ++ return (unsigned int) grub_gpt_entry_attribute ++ (entry, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_PRIORITY, 4); ++} ++ ++static unsigned int ++grub_gptprio_tries_left (struct grub_gpt_partentry *entry) ++{ ++ return (unsigned int) grub_gpt_entry_attribute ++ (entry, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_TRIES_LEFT, 4); ++} ++ ++static void ++grub_gptprio_set_tries_left (struct grub_gpt_partentry *entry, ++ unsigned int tries_left) ++{ ++ grub_gpt_entry_set_attribute ++ (entry, tries_left, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_TRIES_LEFT, 4); ++} ++ ++static unsigned int ++grub_gptprio_successful (struct grub_gpt_partentry *entry) ++{ ++ return (unsigned int) grub_gpt_entry_attribute ++ (entry, GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_SUCCESSFUL, 1); ++} ++ ++static grub_err_t ++grub_find_next (const char *disk_name, ++ const grub_gpt_part_type_t *part_type, ++ char **part_name, char **part_guid) ++{ ++ struct grub_gpt_partentry *part, *part_found = NULL; ++ grub_device_t dev = NULL; ++ grub_gpt_t gpt = NULL; ++ grub_uint32_t i, part_index; ++ ++ dev = grub_device_open (disk_name); ++ if (!dev) ++ goto done; ++ ++ gpt = grub_gpt_read (dev->disk); ++ if (!gpt) ++ goto done; ++ ++ if (grub_gpt_repair (dev->disk, gpt)) ++ goto done; ++ ++ for (i = 0; (part = grub_gpt_get_partentry (gpt, i)) != NULL; i++) ++ { ++ if (grub_memcmp (part_type, &part->type, sizeof (*part_type)) == 0) ++ { ++ unsigned int priority, tries_left, successful, old_priority = 0; ++ ++ priority = grub_gptprio_priority (part); ++ tries_left = grub_gptprio_tries_left (part); ++ successful = grub_gptprio_successful (part); ++ ++ if (part_found) ++ old_priority = grub_gptprio_priority (part_found); ++ ++ if ((tries_left || successful) && priority > old_priority) ++ { ++ part_index = i; ++ part_found = part; ++ } ++ } ++ } ++ ++ if (!part_found) ++ { ++ grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("no such partition")); ++ goto done; ++ } ++ ++ if (grub_gptprio_tries_left (part_found)) ++ { ++ unsigned int tries_left = grub_gptprio_tries_left (part_found); ++ ++ grub_gptprio_set_tries_left (part_found, tries_left - 1); ++ ++ if (grub_gpt_update (gpt)) ++ goto done; ++ ++ if (grub_gpt_write (dev->disk, gpt)) ++ goto done; ++ } ++ ++ *part_name = grub_xasprintf ("%s,gpt%u", disk_name, part_index + 1); ++ if (!*part_name) ++ goto done; ++ ++ *part_guid = grub_gpt_guid_to_str (&part_found->guid); ++ if (!*part_guid) ++ goto done; ++ ++ grub_errno = GRUB_ERR_NONE; ++ ++done: ++ grub_gpt_free (gpt); ++ ++ if (dev) ++ grub_device_close (dev); ++ ++ return grub_errno; ++} ++ ++ ++ ++static grub_err_t ++grub_cmd_next (grub_extcmd_context_t ctxt, int argc, char **args) ++{ ++ struct grub_arg_list *state = ctxt->state; ++ char *p, *root = NULL, *part_name = NULL, *part_guid = NULL; ++ ++ /* TODO: Add a uuid parser and a command line flag for providing type. */ ++ grub_gpt_part_type_t part_type = GRUB_GPT_PARTITION_TYPE_USR_X86_64; ++ ++ if (!state[NEXT_SET_DEVICE].set || !state[NEXT_SET_UUID].set) ++ { ++ grub_error (GRUB_ERR_INVALID_COMMAND, N_("-d and -u are required")); ++ goto done; ++ } ++ ++ if (argc == 0) ++ root = grub_strdup (grub_env_get ("root")); ++ else if (argc == 1) ++ root = grub_strdup (args[0]); ++ else ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unexpected arguments")); ++ goto done; ++ } ++ ++ if (!root) ++ goto done; ++ ++ /* To make using $root practical strip off the partition name. */ ++ p = grub_strchr (root, ','); ++ if (p) ++ *p = '\0'; ++ ++ if (grub_find_next (root, &part_type, &part_name, &part_guid)) ++ goto done; ++ ++ if (grub_env_set (state[NEXT_SET_DEVICE].arg, part_name)) ++ goto done; ++ ++ if (grub_env_set (state[NEXT_SET_UUID].arg, part_guid)) ++ goto done; ++ ++ grub_errno = GRUB_ERR_NONE; ++ ++done: ++ grub_free (root); ++ grub_free (part_name); ++ grub_free (part_guid); ++ ++ return grub_errno; ++} ++ ++static grub_extcmd_t cmd_next; ++ ++GRUB_MOD_INIT(gptprio) ++{ ++ cmd_next = grub_register_extcmd ("gptprio.next", grub_cmd_next, 0, ++ N_("-d VARNAME -u VARNAME [DEVICE]"), ++ N_("Select next partition to boot."), ++ options_next); ++} ++ ++GRUB_MOD_FINI(gptprio) ++{ ++ grub_unregister_extcmd (cmd_next); ++} +diff --git a/grub-core/commands/gptrepair.c b/grub-core/commands/gptrepair.c +new file mode 100644 +index 000000000..c17c7346c +--- /dev/null ++++ b/grub-core/commands/gptrepair.c +@@ -0,0 +1,110 @@ ++/* gptrepair.c - verify and restore GPT info from alternate location. */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2009 Free Software Foundation, Inc. ++ * Copyright (C) 2014 CoreOS, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static char * ++trim_dev_name (char *name) ++{ ++ grub_size_t len = grub_strlen (name); ++ if (len && name[0] == '(' && name[len - 1] == ')') ++ { ++ name[len - 1] = '\0'; ++ name = name + 1; ++ } ++ return name; ++} ++ ++static grub_err_t ++grub_cmd_gptrepair (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char **args) ++{ ++ grub_device_t dev = NULL; ++ grub_gpt_t gpt = NULL; ++ char *dev_name; ++ ++ if (argc != 1 || !grub_strlen(args[0])) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required"); ++ ++ dev_name = trim_dev_name (args[0]); ++ dev = grub_device_open (dev_name); ++ if (!dev) ++ goto done; ++ ++ if (!dev->disk) ++ { ++ grub_error (GRUB_ERR_BAD_ARGUMENT, "not a disk"); ++ goto done; ++ } ++ ++ gpt = grub_gpt_read (dev->disk); ++ if (!gpt) ++ goto done; ++ ++ if (grub_gpt_both_valid (gpt)) ++ { ++ grub_printf_ (N_("GPT already valid, %s unmodified.\n"), dev_name); ++ goto done; ++ } ++ ++ if (!grub_gpt_primary_valid (gpt)) ++ grub_printf_ (N_("Found invalid primary GPT on %s\n"), dev_name); ++ ++ if (!grub_gpt_backup_valid (gpt)) ++ grub_printf_ (N_("Found invalid backup GPT on %s\n"), dev_name); ++ ++ if (grub_gpt_repair (dev->disk, gpt)) ++ goto done; ++ ++ if (grub_gpt_write (dev->disk, gpt)) ++ goto done; ++ ++ grub_printf_ (N_("Repaired GPT on %s\n"), dev_name); ++ ++done: ++ if (gpt) ++ grub_gpt_free (gpt); ++ ++ if (dev) ++ grub_device_close (dev); ++ ++ return grub_errno; ++} ++ ++static grub_command_t cmd; ++ ++GRUB_MOD_INIT(gptrepair) ++{ ++ cmd = grub_register_command ("gptrepair", grub_cmd_gptrepair, ++ N_("DEVICE"), ++ N_("Verify and repair GPT on drive DEVICE.")); ++} ++ ++GRUB_MOD_FINI(gptrepair) ++{ ++ grub_unregister_command (cmd); ++} +diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c +index ed090b3af..4ad72c5b4 100644 +--- a/grub-core/commands/search.c ++++ b/grub-core/commands/search.c +@@ -30,6 +30,9 @@ + #include + #include + #include ++#if defined(DO_SEARCH_PART_UUID) || defined(DO_SEARCH_PART_LABEL) ++#include ++#endif + + GRUB_MOD_LICENSE ("GPLv3+"); + +@@ -90,6 +93,44 @@ iterate_device (const char *name, void *data) + } + grub_free (buf); + } ++#elif defined(DO_SEARCH_PART_UUID) ++ { ++ grub_device_t dev; ++ char *quid; ++ ++ dev = grub_device_open (name); ++ if (dev) ++ { ++ if (grub_gpt_part_uuid (dev, &quid) == GRUB_ERR_NONE) ++ { ++ if (grub_strcasecmp (quid, ctx->key) == 0) ++ found = 1; ++ ++ grub_free (quid); ++ } ++ ++ grub_device_close (dev); ++ } ++ } ++#elif defined(DO_SEARCH_PART_LABEL) ++ { ++ grub_device_t dev; ++ char *quid; ++ ++ dev = grub_device_open (name); ++ if (dev) ++ { ++ if (grub_gpt_part_label (dev, &quid) == GRUB_ERR_NONE) ++ { ++ if (grub_strcmp (quid, ctx->key) == 0) ++ found = 1; ++ ++ grub_free (quid); ++ } ++ ++ grub_device_close (dev); ++ } ++ } + #else + { + /* SEARCH_FS_UUID or SEARCH_LABEL */ +@@ -313,6 +354,10 @@ static grub_command_t cmd; + + #ifdef DO_SEARCH_FILE + GRUB_MOD_INIT(search_fs_file) ++#elif defined(DO_SEARCH_PART_UUID) ++GRUB_MOD_INIT(search_part_uuid) ++#elif defined(DO_SEARCH_PART_LABEL) ++GRUB_MOD_INIT(search_part_label) + #elif defined (DO_SEARCH_FS_UUID) + GRUB_MOD_INIT(search_fs_uuid) + #else +@@ -327,6 +372,10 @@ GRUB_MOD_INIT(search_label) + + #ifdef DO_SEARCH_FILE + GRUB_MOD_FINI(search_fs_file) ++#elif defined(DO_SEARCH_PART_UUID) ++GRUB_MOD_FINI(search_part_uuid) ++#elif defined(DO_SEARCH_PART_LABEL) ++GRUB_MOD_FINI(search_part_label) + #elif defined (DO_SEARCH_FS_UUID) + GRUB_MOD_FINI(search_fs_uuid) + #else +diff --git a/grub-core/commands/search_part_label.c b/grub-core/commands/search_part_label.c +new file mode 100644 +index 000000000..ca906cbd9 +--- /dev/null ++++ b/grub-core/commands/search_part_label.c +@@ -0,0 +1,5 @@ ++#define DO_SEARCH_PART_LABEL 1 ++#define FUNC_NAME grub_search_part_label ++#define COMMAND_NAME "search.part_label" ++#define HELP_MESSAGE N_("Search devices by partition label. If VARIABLE is specified, the first device found is set to a variable.") ++#include "search.c" +diff --git a/grub-core/commands/search_part_uuid.c b/grub-core/commands/search_part_uuid.c +new file mode 100644 +index 000000000..2d1d3d0d7 +--- /dev/null ++++ b/grub-core/commands/search_part_uuid.c +@@ -0,0 +1,5 @@ ++#define DO_SEARCH_PART_UUID 1 ++#define FUNC_NAME grub_search_part_uuid ++#define COMMAND_NAME "search.part_uuid" ++#define HELP_MESSAGE N_("Search devices by partition UUID. If VARIABLE is specified, the first device found is set to a variable.") ++#include "search.c" +diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c +index 47fc8eb99..d357454a9 100644 +--- a/grub-core/commands/search_wrap.c ++++ b/grub-core/commands/search_wrap.c +@@ -36,6 +36,10 @@ static const struct grub_arg_option options[] = + 0, 0}, + {"fs-uuid", 'u', 0, N_("Search devices by a filesystem UUID."), + 0, 0}, ++ {"part-label", 'L', 0, N_("Search devices by a partition label."), ++ 0, 0}, ++ {"part-uuid", 'U', 0, N_("Search devices by a partition UUID."), ++ 0, 0}, + {"set", 's', GRUB_ARG_OPTION_OPTIONAL, + N_("Set a variable to the first device found."), N_("VARNAME"), + ARG_TYPE_STRING}, +@@ -71,6 +75,8 @@ enum options + SEARCH_FILE, + SEARCH_LABEL, + SEARCH_FS_UUID, ++ SEARCH_PART_LABEL, ++ SEARCH_PART_UUID, + SEARCH_SET, + SEARCH_NO_FLOPPY, + SEARCH_HINT, +@@ -186,6 +192,12 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args) + else if (state[SEARCH_FS_UUID].set) + grub_search_fs_uuid (id, var, state[SEARCH_NO_FLOPPY].set, + hints, nhints); ++ else if (state[SEARCH_PART_LABEL].set) ++ grub_search_part_label (id, var, state[SEARCH_NO_FLOPPY].set, ++ hints, nhints); ++ else if (state[SEARCH_PART_UUID].set) ++ grub_search_part_uuid (id, var, state[SEARCH_NO_FLOPPY].set, ++ hints, nhints); + else if (state[SEARCH_FILE].set) + grub_search_fs_file (id, var, state[SEARCH_NO_FLOPPY].set, + hints, nhints); +diff --git a/grub-core/lib/gpt.c b/grub-core/lib/gpt.c +new file mode 100644 +index 000000000..098fa65c4 +--- /dev/null ++++ b/grub-core/lib/gpt.c +@@ -0,0 +1,757 @@ ++/* gpt.c - Read/Verify/Write GUID Partition Tables (GPT). */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2005,2006,2007,2008 Free Software Foundation, Inc. ++ * Copyright (C) 2014 CoreOS, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++static grub_uint8_t grub_gpt_magic[] = GRUB_GPT_HEADER_MAGIC; ++ ++static grub_err_t ++grub_gpt_read_entries (grub_disk_t disk, grub_gpt_t gpt, ++ struct grub_gpt_header *header, ++ void **ret_entries, ++ grub_size_t *ret_entries_size); ++ ++char * ++grub_gpt_guid_to_str (grub_gpt_guid_t *guid) ++{ ++ return grub_xasprintf ("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", ++ grub_le_to_cpu32 (guid->data1), ++ grub_le_to_cpu16 (guid->data2), ++ grub_le_to_cpu16 (guid->data3), ++ guid->data4[0], guid->data4[1], ++ guid->data4[2], guid->data4[3], ++ guid->data4[4], guid->data4[5], ++ guid->data4[6], guid->data4[7]); ++} ++ ++static grub_err_t ++grub_gpt_device_partentry (grub_device_t device, ++ struct grub_gpt_partentry *entry) ++{ ++ grub_disk_t disk = device->disk; ++ grub_partition_t p; ++ grub_err_t err; ++ ++ if (!disk || !disk->partition) ++ return grub_error (GRUB_ERR_BUG, "not a partition"); ++ ++ if (grub_strcmp (disk->partition->partmap->name, "gpt")) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a GPT partition"); ++ ++ p = disk->partition; ++ disk->partition = p->parent; ++ err = grub_disk_read (disk, p->offset, p->index, sizeof (*entry), entry); ++ disk->partition = p; ++ ++ return err; ++} ++ ++grub_err_t ++grub_gpt_part_label (grub_device_t device, char **label) ++{ ++ struct grub_gpt_partentry entry; ++ const grub_size_t name_len = ARRAY_SIZE (entry.name); ++ const grub_size_t label_len = name_len * GRUB_MAX_UTF8_PER_UTF16 + 1; ++ grub_size_t i; ++ grub_uint8_t *end; ++ ++ if (grub_gpt_device_partentry (device, &entry)) ++ return grub_errno; ++ ++ *label = grub_malloc (label_len); ++ if (!*label) ++ return grub_errno; ++ ++ for (i = 0; i < name_len; i++) ++ entry.name[i] = grub_le_to_cpu16 (entry.name[i]); ++ ++ end = grub_utf16_to_utf8 ((grub_uint8_t *) *label, entry.name, name_len); ++ *end = '\0'; ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_gpt_part_uuid (grub_device_t device, char **uuid) ++{ ++ struct grub_gpt_partentry entry; ++ ++ if (grub_gpt_device_partentry (device, &entry)) ++ return grub_errno; ++ ++ *uuid = grub_gpt_guid_to_str (&entry.guid); ++ if (!*uuid) ++ return grub_errno; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static struct grub_gpt_header * ++grub_gpt_get_header (grub_gpt_t gpt) ++{ ++ if (gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID) ++ return &gpt->primary; ++ else if (gpt->status & GRUB_GPT_BACKUP_HEADER_VALID) ++ return &gpt->backup; ++ ++ grub_error (GRUB_ERR_BUG, "No valid GPT header"); ++ return NULL; ++} ++ ++static grub_uint64_t ++grub_gpt_size_to_sectors (grub_gpt_t gpt, grub_size_t size) ++{ ++ unsigned int sector_size; ++ grub_uint64_t sectors; ++ ++ sector_size = 1U << gpt->log_sector_size; ++ sectors = size / sector_size; ++ if (size % sector_size) ++ sectors++; ++ ++ return sectors; ++} ++ ++/* Copied from grub-core/kern/disk_common.c grub_disk_adjust_range so we can ++ * avoid attempting to use disk->total_sectors when GRUB won't let us. ++ * TODO: Why is disk->total_sectors not set to GRUB_DISK_SIZE_UNKNOWN? */ ++static int ++grub_gpt_disk_size_valid (grub_disk_t disk) ++{ ++ grub_disk_addr_t total_sectors; ++ ++ /* Transform total_sectors to number of 512B blocks. */ ++ total_sectors = disk->total_sectors << (disk->log_sector_size - GRUB_DISK_SECTOR_BITS); ++ ++ /* Some drivers have problems with disks above reasonable. ++ Treat unknown as 1EiB disk. While on it, clamp the size to 1EiB. ++ Just one condition is enough since GRUB_DISK_UNKNOWN_SIZE << ls is always ++ above 9EiB. ++ */ ++ if (total_sectors > (1ULL << 51)) ++ return 0; ++ ++ return 1; ++} ++ ++static void ++grub_gpt_lecrc32 (grub_uint32_t *crc, const void *data, grub_size_t len) ++{ ++ grub_uint32_t crc32_val; ++ ++ grub_crypto_hash (GRUB_MD_CRC32, &crc32_val, data, len); ++ ++ /* GRUB_MD_CRC32 always uses big endian, gpt is always little. */ ++ *crc = grub_swap_bytes32 (crc32_val); ++} ++ ++static void ++grub_gpt_header_lecrc32 (grub_uint32_t *crc, struct grub_gpt_header *header) ++{ ++ grub_uint32_t old, new; ++ ++ /* crc32 must be computed with the field cleared. */ ++ old = header->crc32; ++ header->crc32 = 0; ++ grub_gpt_lecrc32 (&new, header, sizeof (*header)); ++ header->crc32 = old; ++ ++ *crc = new; ++} ++ ++/* Make sure the MBR is a protective MBR and not a normal MBR. */ ++grub_err_t ++grub_gpt_pmbr_check (struct grub_msdos_partition_mbr *mbr) ++{ ++ unsigned int i; ++ ++ if (mbr->signature != ++ grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE)) ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid MBR signature"); ++ ++ for (i = 0; i < sizeof (mbr->entries); i++) ++ if (mbr->entries[i].type == GRUB_PC_PARTITION_TYPE_GPT_DISK) ++ return GRUB_ERR_NONE; ++ ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid protective MBR"); ++} ++ ++static grub_uint64_t ++grub_gpt_entries_size (struct grub_gpt_header *gpt) ++{ ++ return (grub_uint64_t) grub_le_to_cpu32 (gpt->maxpart) * ++ (grub_uint64_t) grub_le_to_cpu32 (gpt->partentry_size); ++} ++ ++static grub_uint64_t ++grub_gpt_entries_sectors (struct grub_gpt_header *gpt, ++ unsigned int log_sector_size) ++{ ++ grub_uint64_t sector_bytes, entries_bytes; ++ ++ sector_bytes = 1ULL << log_sector_size; ++ entries_bytes = grub_gpt_entries_size (gpt); ++ return grub_divmod64(entries_bytes + sector_bytes - 1, sector_bytes, NULL); ++} ++ ++static int ++is_pow2 (grub_uint32_t n) ++{ ++ return (n & (n - 1)) == 0; ++} ++ ++grub_err_t ++grub_gpt_header_check (struct grub_gpt_header *gpt, ++ unsigned int log_sector_size) ++{ ++ grub_uint32_t crc = 0, size; ++ grub_uint64_t start, end; ++ ++ if (grub_memcmp (gpt->magic, grub_gpt_magic, sizeof (grub_gpt_magic)) != 0) ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT signature"); ++ ++ if (gpt->version != GRUB_GPT_HEADER_VERSION) ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "unknown GPT version"); ++ ++ grub_gpt_header_lecrc32 (&crc, gpt); ++ if (gpt->crc32 != crc) ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT header crc32"); ++ ++ /* The header size "must be greater than or equal to 92 and must be less ++ * than or equal to the logical block size." */ ++ size = grub_le_to_cpu32 (gpt->headersize); ++ if (size < 92U || size > (1U << log_sector_size)) ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT header size"); ++ ++ /* The partition entry size must be "a value of 128*(2^n) where n is an ++ * integer greater than or equal to zero (e.g., 128, 256, 512, etc.)." */ ++ size = grub_le_to_cpu32 (gpt->partentry_size); ++ if (size < 128U || size % 128U || !is_pow2 (size / 128U)) ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT entry size"); ++ ++ /* The minimum entries table size is specified in terms of bytes, ++ * regardless of how large the individual entry size is. */ ++ if (grub_gpt_entries_size (gpt) < GRUB_GPT_DEFAULT_ENTRIES_SIZE) ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT entry table size"); ++ ++ /* And of course there better be some space for partitions! */ ++ start = grub_le_to_cpu64 (gpt->start); ++ end = grub_le_to_cpu64 (gpt->end); ++ if (start > end) ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid usable sectors"); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static int ++grub_gpt_headers_equal (grub_gpt_t gpt) ++{ ++ /* Assume headers passed grub_gpt_header_check so skip magic and version. ++ * Individual fields must be checked instead of just using memcmp because ++ * crc32, header, alternate, and partitions will all normally differ. */ ++ ++ if (gpt->primary.headersize != gpt->backup.headersize || ++ gpt->primary.header_lba != gpt->backup.alternate_lba || ++ gpt->primary.alternate_lba != gpt->backup.header_lba || ++ gpt->primary.start != gpt->backup.start || ++ gpt->primary.end != gpt->backup.end || ++ gpt->primary.maxpart != gpt->backup.maxpart || ++ gpt->primary.partentry_size != gpt->backup.partentry_size || ++ gpt->primary.partentry_crc32 != gpt->backup.partentry_crc32) ++ return 0; ++ ++ return grub_memcmp(&gpt->primary.guid, &gpt->backup.guid, ++ sizeof(grub_gpt_guid_t)) == 0; ++} ++ ++static grub_err_t ++grub_gpt_check_primary (grub_gpt_t gpt) ++{ ++ grub_uint64_t backup, primary, entries, entries_len, start, end; ++ ++ primary = grub_le_to_cpu64 (gpt->primary.header_lba); ++ backup = grub_le_to_cpu64 (gpt->primary.alternate_lba); ++ entries = grub_le_to_cpu64 (gpt->primary.partitions); ++ entries_len = grub_gpt_entries_sectors(&gpt->primary, gpt->log_sector_size); ++ start = grub_le_to_cpu64 (gpt->primary.start); ++ end = grub_le_to_cpu64 (gpt->primary.end); ++ ++ grub_dprintf ("gpt", "Primary GPT layout:\n" ++ "primary header = 0x%llx backup header = 0x%llx\n" ++ "entries location = 0x%llx length = 0x%llx\n" ++ "first usable = 0x%llx last usable = 0x%llx\n", ++ (unsigned long long) primary, ++ (unsigned long long) backup, ++ (unsigned long long) entries, ++ (unsigned long long) entries_len, ++ (unsigned long long) start, ++ (unsigned long long) end); ++ ++ if (grub_gpt_header_check (&gpt->primary, gpt->log_sector_size)) ++ return grub_errno; ++ if (primary != 1) ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid primary GPT LBA"); ++ if (entries <= 1 || entries+entries_len > start) ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid entries location"); ++ if (backup <= end) ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid backup GPT LBA"); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_gpt_check_backup (grub_gpt_t gpt) ++{ ++ grub_uint64_t backup, primary, entries, entries_len, start, end; ++ ++ backup = grub_le_to_cpu64 (gpt->backup.header_lba); ++ primary = grub_le_to_cpu64 (gpt->backup.alternate_lba); ++ entries = grub_le_to_cpu64 (gpt->backup.partitions); ++ entries_len = grub_gpt_entries_sectors(&gpt->backup, gpt->log_sector_size); ++ start = grub_le_to_cpu64 (gpt->backup.start); ++ end = grub_le_to_cpu64 (gpt->backup.end); ++ ++ grub_dprintf ("gpt", "Backup GPT layout:\n" ++ "primary header = 0x%llx backup header = 0x%llx\n" ++ "entries location = 0x%llx length = 0x%llx\n" ++ "first usable = 0x%llx last usable = 0x%llx\n", ++ (unsigned long long) primary, ++ (unsigned long long) backup, ++ (unsigned long long) entries, ++ (unsigned long long) entries_len, ++ (unsigned long long) start, ++ (unsigned long long) end); ++ ++ if (grub_gpt_header_check (&gpt->backup, gpt->log_sector_size)) ++ return grub_errno; ++ if (primary != 1) ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid primary GPT LBA"); ++ if (entries <= end || entries+entries_len > backup) ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid entries location"); ++ if (backup <= end) ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid backup GPT LBA"); ++ ++ /* If both primary and backup are valid but differ prefer the primary. */ ++ if ((gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID) && ++ !grub_gpt_headers_equal (gpt)) ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "backup GPT out of sync"); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_gpt_read_primary (grub_disk_t disk, grub_gpt_t gpt) ++{ ++ grub_disk_addr_t addr; ++ ++ /* TODO: The gpt partmap module searches for the primary header instead ++ * of relying on the disk's sector size. For now trust the disk driver ++ * but eventually this code should match the existing behavior. */ ++ gpt->log_sector_size = disk->log_sector_size; ++ ++ grub_dprintf ("gpt", "reading primary GPT from sector 0x1\n"); ++ ++ addr = grub_gpt_sector_to_addr (gpt, 1); ++ if (grub_disk_read (disk, addr, 0, sizeof (gpt->primary), &gpt->primary)) ++ return grub_errno; ++ ++ if (grub_gpt_check_primary (gpt)) ++ return grub_errno; ++ ++ gpt->status |= GRUB_GPT_PRIMARY_HEADER_VALID; ++ ++ if (grub_gpt_read_entries (disk, gpt, &gpt->primary, ++ &gpt->entries, &gpt->entries_size)) ++ return grub_errno; ++ ++ gpt->status |= GRUB_GPT_PRIMARY_ENTRIES_VALID; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_gpt_read_backup (grub_disk_t disk, grub_gpt_t gpt) ++{ ++ void *entries = NULL; ++ grub_size_t entries_size; ++ grub_uint64_t sector; ++ grub_disk_addr_t addr; ++ ++ /* Assumes gpt->log_sector_size == disk->log_sector_size */ ++ if (gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID) ++ { ++ sector = grub_le_to_cpu64 (gpt->primary.alternate_lba); ++ if (grub_gpt_disk_size_valid (disk) && sector >= disk->total_sectors) ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ "backup GPT located at 0x%llx, " ++ "beyond last disk sector at 0x%llx", ++ (unsigned long long) sector, ++ (unsigned long long) disk->total_sectors - 1); ++ } ++ else if (grub_gpt_disk_size_valid (disk)) ++ sector = disk->total_sectors - 1; ++ else ++ return grub_error (GRUB_ERR_OUT_OF_RANGE, ++ "size of disk unknown, cannot locate backup GPT"); ++ ++ grub_dprintf ("gpt", "reading backup GPT from sector 0x%llx\n", ++ (unsigned long long) sector); ++ ++ addr = grub_gpt_sector_to_addr (gpt, sector); ++ if (grub_disk_read (disk, addr, 0, sizeof (gpt->backup), &gpt->backup)) ++ return grub_errno; ++ ++ if (grub_gpt_check_backup (gpt)) ++ return grub_errno; ++ ++ /* Ensure the backup header thinks it is located where we found it. */ ++ if (grub_le_to_cpu64 (gpt->backup.header_lba) != sector) ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid backup GPT LBA"); ++ ++ gpt->status |= GRUB_GPT_BACKUP_HEADER_VALID; ++ ++ if (grub_gpt_read_entries (disk, gpt, &gpt->backup, ++ &entries, &entries_size)) ++ return grub_errno; ++ ++ if (gpt->status & GRUB_GPT_PRIMARY_ENTRIES_VALID) ++ { ++ if (entries_size != gpt->entries_size || ++ grub_memcmp (entries, gpt->entries, entries_size) != 0) ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "backup GPT out of sync"); ++ ++ grub_free (entries); ++ } ++ else ++ { ++ gpt->entries = entries; ++ gpt->entries_size = entries_size; ++ } ++ ++ gpt->status |= GRUB_GPT_BACKUP_ENTRIES_VALID; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_gpt_read_entries (grub_disk_t disk, grub_gpt_t gpt, ++ struct grub_gpt_header *header, ++ void **ret_entries, ++ grub_size_t *ret_entries_size) ++{ ++ void *entries = NULL; ++ grub_uint32_t count, size, crc; ++ grub_uint64_t sector; ++ grub_disk_addr_t addr; ++ grub_size_t entries_size; ++ ++ /* Grub doesn't include calloc, hence the manual overflow check. */ ++ count = grub_le_to_cpu32 (header->maxpart); ++ size = grub_le_to_cpu32 (header->partentry_size); ++ entries_size = count *size; ++ if (size && entries_size / size != count) ++ { ++ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); ++ goto fail; ++ } ++ ++ /* Double check that the header was validated properly. */ ++ if (entries_size < GRUB_GPT_DEFAULT_ENTRIES_SIZE) ++ return grub_error (GRUB_ERR_BUG, "invalid GPT entries table size"); ++ ++ entries = grub_malloc (entries_size); ++ if (!entries) ++ goto fail; ++ ++ sector = grub_le_to_cpu64 (header->partitions); ++ grub_dprintf ("gpt", "reading GPT %lu entries from sector 0x%llx\n", ++ (unsigned long) count, ++ (unsigned long long) sector); ++ ++ addr = grub_gpt_sector_to_addr (gpt, sector); ++ if (grub_disk_read (disk, addr, 0, entries_size, entries)) ++ goto fail; ++ ++ grub_gpt_lecrc32 (&crc, entries, entries_size); ++ if (crc != header->partentry_crc32) ++ { ++ grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid GPT entry crc32"); ++ goto fail; ++ } ++ ++ *ret_entries = entries; ++ *ret_entries_size = entries_size; ++ return GRUB_ERR_NONE; ++ ++fail: ++ grub_free (entries); ++ return grub_errno; ++} ++ ++grub_gpt_t ++grub_gpt_read (grub_disk_t disk) ++{ ++ grub_gpt_t gpt; ++ ++ grub_dprintf ("gpt", "reading GPT from %s\n", disk->name); ++ ++ gpt = grub_zalloc (sizeof (*gpt)); ++ if (!gpt) ++ goto fail; ++ ++ if (grub_disk_read (disk, 0, 0, sizeof (gpt->mbr), &gpt->mbr)) ++ goto fail; ++ ++ /* Check the MBR but errors aren't reported beyond the status bit. */ ++ if (grub_gpt_pmbr_check (&gpt->mbr)) ++ grub_errno = GRUB_ERR_NONE; ++ else ++ gpt->status |= GRUB_GPT_PROTECTIVE_MBR; ++ ++ /* If both the primary and backup fail report the primary's error. */ ++ if (grub_gpt_read_primary (disk, gpt)) ++ { ++ grub_error_push (); ++ grub_gpt_read_backup (disk, gpt); ++ grub_error_pop (); ++ } ++ else ++ grub_gpt_read_backup (disk, gpt); ++ ++ /* If either succeeded clear any possible error from the other. */ ++ if (grub_gpt_primary_valid (gpt) || grub_gpt_backup_valid (gpt)) ++ grub_errno = GRUB_ERR_NONE; ++ else ++ goto fail; ++ ++ return gpt; ++ ++fail: ++ grub_gpt_free (gpt); ++ return NULL; ++} ++ ++struct grub_gpt_partentry * ++grub_gpt_get_partentry (grub_gpt_t gpt, grub_uint32_t n) ++{ ++ struct grub_gpt_header *header; ++ grub_size_t offset; ++ ++ header = grub_gpt_get_header (gpt); ++ if (!header) ++ return NULL; ++ ++ if (n >= grub_le_to_cpu32 (header->maxpart)) ++ return NULL; ++ ++ offset = (grub_size_t) grub_le_to_cpu32 (header->partentry_size) * n; ++ return (struct grub_gpt_partentry *) ((char *) gpt->entries + offset); ++} ++ ++grub_err_t ++grub_gpt_repair (grub_disk_t disk, grub_gpt_t gpt) ++{ ++ /* Skip if there is nothing to do. */ ++ if (grub_gpt_both_valid (gpt)) ++ return GRUB_ERR_NONE; ++ ++ grub_dprintf ("gpt", "repairing GPT for %s\n", disk->name); ++ ++ if (disk->log_sector_size != gpt->log_sector_size) ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "GPT sector size must match disk sector size"); ++ ++ if (grub_gpt_primary_valid (gpt)) ++ { ++ grub_uint64_t backup_header; ++ ++ grub_dprintf ("gpt", "primary GPT is valid\n"); ++ ++ /* Relocate backup to end if disk if the disk has grown. */ ++ backup_header = grub_le_to_cpu64 (gpt->primary.alternate_lba); ++ if (grub_gpt_disk_size_valid (disk) && ++ disk->total_sectors - 1 > backup_header) ++ { ++ backup_header = disk->total_sectors - 1; ++ grub_dprintf ("gpt", "backup GPT header relocated to 0x%llx\n", ++ (unsigned long long) backup_header); ++ ++ gpt->primary.alternate_lba = grub_cpu_to_le64 (backup_header); ++ } ++ ++ grub_memcpy (&gpt->backup, &gpt->primary, sizeof (gpt->backup)); ++ gpt->backup.header_lba = gpt->primary.alternate_lba; ++ gpt->backup.alternate_lba = gpt->primary.header_lba; ++ gpt->backup.partitions = grub_cpu_to_le64 (backup_header - ++ grub_gpt_size_to_sectors (gpt, gpt->entries_size)); ++ } ++ else if (grub_gpt_backup_valid (gpt)) ++ { ++ grub_dprintf ("gpt", "backup GPT is valid\n"); ++ ++ grub_memcpy (&gpt->primary, &gpt->backup, sizeof (gpt->primary)); ++ gpt->primary.header_lba = gpt->backup.alternate_lba; ++ gpt->primary.alternate_lba = gpt->backup.header_lba; ++ gpt->primary.partitions = grub_cpu_to_le64_compile_time (2); ++ } ++ else ++ return grub_error (GRUB_ERR_BUG, "No valid GPT"); ++ ++ if (grub_gpt_update (gpt)) ++ return grub_errno; ++ ++ grub_dprintf ("gpt", "repairing GPT for %s successful\n", disk->name); ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_gpt_update (grub_gpt_t gpt) ++{ ++ grub_uint32_t crc; ++ ++ /* Clear status bits, require revalidation of everything. */ ++ gpt->status &= ~(GRUB_GPT_PRIMARY_HEADER_VALID | ++ GRUB_GPT_PRIMARY_ENTRIES_VALID | ++ GRUB_GPT_BACKUP_HEADER_VALID | ++ GRUB_GPT_BACKUP_ENTRIES_VALID); ++ ++ /* Writing headers larger than our header structure are unsupported. */ ++ gpt->primary.headersize = ++ grub_cpu_to_le32_compile_time (sizeof (gpt->primary)); ++ gpt->backup.headersize = ++ grub_cpu_to_le32_compile_time (sizeof (gpt->backup)); ++ ++ grub_gpt_lecrc32 (&crc, gpt->entries, gpt->entries_size); ++ gpt->primary.partentry_crc32 = crc; ++ gpt->backup.partentry_crc32 = crc; ++ ++ grub_gpt_header_lecrc32 (&gpt->primary.crc32, &gpt->primary); ++ grub_gpt_header_lecrc32 (&gpt->backup.crc32, &gpt->backup); ++ ++ if (grub_gpt_check_primary (gpt)) ++ { ++ grub_error_push (); ++ return grub_error (GRUB_ERR_BUG, "Generated invalid GPT primary header"); ++ } ++ ++ gpt->status |= (GRUB_GPT_PRIMARY_HEADER_VALID | ++ GRUB_GPT_PRIMARY_ENTRIES_VALID); ++ ++ if (grub_gpt_check_backup (gpt)) ++ { ++ grub_error_push (); ++ return grub_error (GRUB_ERR_BUG, "Generated invalid GPT backup header"); ++ } ++ ++ gpt->status |= (GRUB_GPT_BACKUP_HEADER_VALID | ++ GRUB_GPT_BACKUP_ENTRIES_VALID); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_gpt_write_table (grub_disk_t disk, grub_gpt_t gpt, ++ struct grub_gpt_header *header) ++{ ++ grub_disk_addr_t addr; ++ ++ if (grub_le_to_cpu32 (header->headersize) != sizeof (*header)) ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ "Header size is %u, must be %u", ++ grub_le_to_cpu32 (header->headersize), ++ sizeof (*header)); ++ ++ addr = grub_gpt_sector_to_addr (gpt, grub_le_to_cpu64 (header->header_lba)); ++ if (addr == 0) ++ return grub_error (GRUB_ERR_BUG, ++ "Refusing to write GPT header to address 0x0"); ++ if (grub_disk_write (disk, addr, 0, sizeof (*header), header)) ++ return grub_errno; ++ ++ addr = grub_gpt_sector_to_addr (gpt, grub_le_to_cpu64 (header->partitions)); ++ if (addr < 2) ++ return grub_error (GRUB_ERR_BUG, ++ "Refusing to write GPT entries to address 0x%llx", ++ (unsigned long long) addr); ++ if (grub_disk_write (disk, addr, 0, gpt->entries_size, gpt->entries)) ++ return grub_errno; ++ ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_gpt_write (grub_disk_t disk, grub_gpt_t gpt) ++{ ++ grub_uint64_t backup_header; ++ ++ /* TODO: update/repair protective MBRs too. */ ++ ++ if (!grub_gpt_both_valid (gpt)) ++ return grub_error (GRUB_ERR_BAD_PART_TABLE, "Invalid GPT data"); ++ ++ /* Write the backup GPT first so if writing fails the update is aborted ++ * and the primary is left intact. However if the backup location is ++ * inaccessible we have to just skip and hope for the best, the backup ++ * will need to be repaired in the OS. */ ++ backup_header = grub_le_to_cpu64 (gpt->backup.header_lba); ++ if (grub_gpt_disk_size_valid (disk) && ++ backup_header >= disk->total_sectors) ++ { ++ grub_printf ("warning: backup GPT located at 0x%llx, " ++ "beyond last disk sector at 0x%llx\n", ++ (unsigned long long) backup_header, ++ (unsigned long long) disk->total_sectors - 1); ++ grub_printf ("warning: only writing primary GPT, " ++ "the backup GPT must be repaired from the OS\n"); ++ } ++ else ++ { ++ grub_dprintf ("gpt", "writing backup GPT to %s\n", disk->name); ++ if (grub_gpt_write_table (disk, gpt, &gpt->backup)) ++ return grub_errno; ++ } ++ ++ grub_dprintf ("gpt", "writing primary GPT to %s\n", disk->name); ++ if (grub_gpt_write_table (disk, gpt, &gpt->primary)) ++ return grub_errno; ++ ++ return GRUB_ERR_NONE; ++} ++ ++void ++grub_gpt_free (grub_gpt_t gpt) ++{ ++ if (!gpt) ++ return; ++ ++ grub_free (gpt->entries); ++ grub_free (gpt); ++} +diff --git a/include/grub/gpt_partition.h b/include/grub/gpt_partition.h +index 7a93f4329..5c4372dce 100644 +--- a/include/grub/gpt_partition.h ++++ b/include/grub/gpt_partition.h +@@ -21,6 +21,7 @@ + + #include + #include ++#include + + struct grub_gpt_part_guid + { +@@ -30,25 +31,46 @@ struct grub_gpt_part_guid + grub_uint8_t data4[8]; + } GRUB_PACKED; + typedef struct grub_gpt_part_guid grub_gpt_part_guid_t; ++typedef struct grub_gpt_part_guid grub_gpt_guid_t; ++typedef struct grub_gpt_part_guid grub_gpt_part_type_t; + +-#define GRUB_GPT_PARTITION_TYPE_EMPTY \ +- { 0x0, 0x0, 0x0, \ +- { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } \ ++/* Format the raw little-endian GUID as a newly allocated string. */ ++char * grub_gpt_guid_to_str (grub_gpt_guid_t *guid); ++ ++ ++#define GRUB_GPT_GUID_INIT(a, b, c, d1, d2, d3, d4, d5, d6, d7, d8) \ ++ { \ ++ grub_cpu_to_le32_compile_time (a), \ ++ grub_cpu_to_le16_compile_time (b), \ ++ grub_cpu_to_le16_compile_time (c), \ ++ { d1, d2, d3, d4, d5, d6, d7, d8 } \ + } + ++#define GRUB_GPT_PARTITION_TYPE_EMPTY \ ++ GRUB_GPT_GUID_INIT (0x0, 0x0, 0x0, \ ++ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0) ++ ++#define GRUB_GPT_PARTITION_TYPE_EFI_SYSTEM \ ++ GRUB_GPT_GUID_INIT (0xc12a7328, 0xf81f, 0x11d2, \ ++ 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b) ++ + #define GRUB_GPT_PARTITION_TYPE_BIOS_BOOT \ +- { grub_cpu_to_le32_compile_time (0x21686148), \ +- grub_cpu_to_le16_compile_time (0x6449), \ +- grub_cpu_to_le16_compile_time (0x6e6f), \ +- { 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 } \ +- } ++ GRUB_GPT_GUID_INIT (0x21686148, 0x6449, 0x6e6f, \ ++ 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49) + + #define GRUB_GPT_PARTITION_TYPE_LDM \ +- { grub_cpu_to_le32_compile_time (0x5808C8AAU),\ +- grub_cpu_to_le16_compile_time (0x7E8F), \ +- grub_cpu_to_le16_compile_time (0x42E0), \ +- { 0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34, 0xCF, 0xB3 } \ +- } ++ GRUB_GPT_GUID_INIT (0x5808c8aa, 0x7e8f, 0x42e0, \ ++ 0x85, 0xd2, 0xe1, 0xe9, 0x04, 0x34, 0xcf, 0xb3) ++ ++#define GRUB_GPT_PARTITION_TYPE_USR_X86_64 \ ++ GRUB_GPT_GUID_INIT (0x5dfbf5f4, 0x2848, 0x4bac, \ ++ 0xaa, 0x5e, 0x0d, 0x9a, 0x20, 0xb7, 0x45, 0xa6) ++ ++#define GRUB_GPT_HEADER_MAGIC \ ++ { 0x45, 0x46, 0x49, 0x20, 0x50, 0x41, 0x52, 0x54 } ++ ++#define GRUB_GPT_HEADER_VERSION \ ++ grub_cpu_to_le32_compile_time (0x00010000U) + + struct grub_gpt_header + { +@@ -57,11 +79,11 @@ struct grub_gpt_header + grub_uint32_t headersize; + grub_uint32_t crc32; + grub_uint32_t unused1; +- grub_uint64_t primary; +- grub_uint64_t backup; ++ grub_uint64_t header_lba; ++ grub_uint64_t alternate_lba; + grub_uint64_t start; + grub_uint64_t end; +- grub_uint8_t guid[16]; ++ grub_gpt_part_guid_t guid; + grub_uint64_t partitions; + grub_uint32_t maxpart; + grub_uint32_t partentry_size; +@@ -75,13 +97,168 @@ struct grub_gpt_partentry + grub_uint64_t start; + grub_uint64_t end; + grub_uint64_t attrib; +- char name[72]; ++ grub_uint16_t name[36]; + } GRUB_PACKED; + ++enum grub_gpt_part_attr_offset ++{ ++ /* Standard partition attribute bits defined by UEFI. */ ++ GRUB_GPT_PART_ATTR_OFFSET_REQUIRED = 0, ++ GRUB_GPT_PART_ATTR_OFFSET_NO_BLOCK_IO_PROTOCOL = 1, ++ GRUB_GPT_PART_ATTR_OFFSET_LEGACY_BIOS_BOOTABLE = 2, ++ ++ /* De facto standard attribute bits defined by Microsoft and reused by ++ * http://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec */ ++ GRUB_GPT_PART_ATTR_OFFSET_READ_ONLY = 60, ++ GRUB_GPT_PART_ATTR_OFFSET_NO_AUTO = 63, ++ ++ /* Partition attributes for priority based selection, ++ * Currently only valid for PARTITION_TYPE_USR_X86_64. ++ * TRIES_LEFT and PRIORITY are 4 bit wide fields. */ ++ GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_PRIORITY = 48, ++ GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_TRIES_LEFT = 52, ++ GRUB_GPT_PART_ATTR_OFFSET_GPTPRIO_SUCCESSFUL = 56, ++}; ++ ++/* Helpers for reading/writing partition attributes. */ ++static inline grub_uint64_t ++grub_gpt_entry_attribute (struct grub_gpt_partentry *entry, ++ enum grub_gpt_part_attr_offset offset, ++ unsigned int bits) ++{ ++ grub_uint64_t attrib = grub_le_to_cpu64 (entry->attrib); ++ ++ return (attrib >> offset) & ((1ULL << bits) - 1); ++} ++ ++static inline void ++grub_gpt_entry_set_attribute (struct grub_gpt_partentry *entry, ++ grub_uint64_t value, ++ enum grub_gpt_part_attr_offset offset, ++ unsigned int bits) ++{ ++ grub_uint64_t attrib, mask; ++ ++ mask = (((1ULL << bits) - 1) << offset); ++ attrib = grub_le_to_cpu64 (entry->attrib) & ~mask; ++ attrib |= ((value << offset) & mask); ++ entry->attrib = grub_cpu_to_le64 (attrib); ++} ++ ++/* Basic GPT partmap module. */ + grub_err_t + grub_gpt_partition_map_iterate (grub_disk_t disk, + grub_partition_iterate_hook_t hook, + void *hook_data); + ++/* Advanced GPT library. */ ++ ++/* Status bits for the grub_gpt.status field. */ ++#define GRUB_GPT_PROTECTIVE_MBR 0x01 ++#define GRUB_GPT_HYBRID_MBR 0x02 ++#define GRUB_GPT_PRIMARY_HEADER_VALID 0x04 ++#define GRUB_GPT_PRIMARY_ENTRIES_VALID 0x08 ++#define GRUB_GPT_BACKUP_HEADER_VALID 0x10 ++#define GRUB_GPT_BACKUP_ENTRIES_VALID 0x20 ++ ++/* UEFI requires the entries table to be at least 16384 bytes for a ++ * total of 128 entries given the standard 128 byte entry size. */ ++#define GRUB_GPT_DEFAULT_ENTRIES_SIZE 16384 ++#define GRUB_GPT_DEFAULT_ENTRIES_LENGTH \ ++ (GRUB_GPT_DEFAULT_ENTRIES_SIZE / sizeof (struct grub_gpt_partentry)) ++ ++struct grub_gpt ++{ ++ /* Bit field indicating which structures on disk are valid. */ ++ unsigned status; ++ ++ /* Protective or hybrid MBR. */ ++ struct grub_msdos_partition_mbr mbr; ++ ++ /* Each of the two GPT headers. */ ++ struct grub_gpt_header primary; ++ struct grub_gpt_header backup; ++ ++ /* Only need one entries table, on disk both copies are identical. ++ * The on disk entry size may be larger than our partentry struct so ++ * the table cannot be indexed directly. */ ++ void *entries; ++ grub_size_t entries_size; ++ ++ /* Logarithm of sector size, in case GPT and disk driver disagree. */ ++ unsigned int log_sector_size; ++}; ++typedef struct grub_gpt *grub_gpt_t; ++ ++/* Helpers for checking the gpt status field. */ ++static inline int ++grub_gpt_mbr_valid (grub_gpt_t gpt) ++{ ++ return ((gpt->status & GRUB_GPT_PROTECTIVE_MBR) || ++ (gpt->status & GRUB_GPT_HYBRID_MBR)); ++} ++ ++static inline int ++grub_gpt_primary_valid (grub_gpt_t gpt) ++{ ++ return ((gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID) && ++ (gpt->status & GRUB_GPT_PRIMARY_ENTRIES_VALID)); ++} ++ ++static inline int ++grub_gpt_backup_valid (grub_gpt_t gpt) ++{ ++ return ((gpt->status & GRUB_GPT_BACKUP_HEADER_VALID) && ++ (gpt->status & GRUB_GPT_BACKUP_ENTRIES_VALID)); ++} ++ ++static inline int ++grub_gpt_both_valid (grub_gpt_t gpt) ++{ ++ return grub_gpt_primary_valid (gpt) && grub_gpt_backup_valid (gpt); ++} ++ ++/* Translate GPT sectors to GRUB's 512 byte block addresses. */ ++static inline grub_disk_addr_t ++grub_gpt_sector_to_addr (grub_gpt_t gpt, grub_uint64_t sector) ++{ ++ return (sector << (gpt->log_sector_size - GRUB_DISK_SECTOR_BITS)); ++} ++ ++/* Allocates and fills new grub_gpt structure, free with grub_gpt_free. */ ++grub_gpt_t grub_gpt_read (grub_disk_t disk); ++ ++/* Helper for indexing into the entries table. ++ * Returns NULL when the end of the table has been reached. */ ++struct grub_gpt_partentry * grub_gpt_get_partentry (grub_gpt_t gpt, ++ grub_uint32_t n); ++ ++/* Sync and update primary and backup headers if either are invalid. */ ++grub_err_t grub_gpt_repair (grub_disk_t disk, grub_gpt_t gpt); ++ ++/* Recompute checksums and revalidate everything, must be called after ++ * modifying any GPT data. */ ++grub_err_t grub_gpt_update (grub_gpt_t gpt); ++ ++/* Write headers and entry tables back to disk. */ ++grub_err_t grub_gpt_write (grub_disk_t disk, grub_gpt_t gpt); ++ ++void grub_gpt_free (grub_gpt_t gpt); ++ ++grub_err_t grub_gpt_pmbr_check (struct grub_msdos_partition_mbr *mbr); ++grub_err_t grub_gpt_header_check (struct grub_gpt_header *gpt, ++ unsigned int log_sector_size); ++ ++ ++/* Utilities for simple partition data lookups, usage is intended to ++ * be similar to fs->label and fs->uuid functions. */ ++ ++/* Return the partition label of the device DEVICE in LABEL. ++ * The label is in a new buffer and should be freed by the caller. */ ++grub_err_t grub_gpt_part_label (grub_device_t device, char **label); ++ ++/* Return the partition uuid of the device DEVICE in UUID. ++ * The uuid is in a new buffer and should be freed by the caller. */ ++grub_err_t grub_gpt_part_uuid (grub_device_t device, char **uuid); + + #endif /* ! GRUB_GPT_PARTITION_HEADER */ +diff --git a/include/grub/search.h b/include/grub/search.h +index d80347df3..c2f40abe9 100644 +--- a/include/grub/search.h ++++ b/include/grub/search.h +@@ -25,5 +25,9 @@ void grub_search_fs_uuid (const char *key, const char *var, int no_floppy, + char **hints, unsigned nhints); + void grub_search_label (const char *key, const char *var, int no_floppy, + char **hints, unsigned nhints); ++void grub_search_part_uuid (const char *key, const char *var, int no_floppy, ++ char **hints, unsigned nhints); ++void grub_search_part_label (const char *key, const char *var, int no_floppy, ++ char **hints, unsigned nhints); + + #endif +diff --git a/tests/gpt_unit_test.c b/tests/gpt_unit_test.c +new file mode 100644 +index 000000000..53f686912 +--- /dev/null ++++ b/tests/gpt_unit_test.c +@@ -0,0 +1,807 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2014 CoreOS, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* from gnulib */ ++#include ++ ++/* Confirm that the GPT structures conform to the sizes in the spec: ++ * The header size "must be greater than or equal to 92 and must be less ++ * than or equal to the logical block size." ++ * The partition entry size must be "a value of 128*(2^n) where n is an ++ * integer greater than or equal to zero (e.g., 128, 256, 512, etc.)." */ ++verify (sizeof (struct grub_gpt_header) == 92); ++verify (sizeof (struct grub_gpt_partentry) == 128); ++ ++/* GPT section sizes. */ ++#define HEADER_SIZE (sizeof (struct grub_gpt_header)) ++#define HEADER_PAD (GRUB_DISK_SECTOR_SIZE - HEADER_SIZE) ++#define ENTRY_SIZE (sizeof (struct grub_gpt_partentry)) ++#define TABLE_ENTRIES 0x80 ++#define TABLE_SIZE (TABLE_ENTRIES * ENTRY_SIZE) ++#define TABLE_SECTORS (TABLE_SIZE / GRUB_DISK_SECTOR_SIZE) ++ ++/* Double check that the table size calculation was valid. */ ++verify (TABLE_SECTORS * GRUB_DISK_SECTOR_SIZE == TABLE_SIZE); ++ ++/* GPT section locations for a 1MiB disk. */ ++#define DISK_SECTORS 0x800 ++#define DISK_SIZE (GRUB_DISK_SECTOR_SIZE * DISK_SECTORS) ++#define PRIMARY_HEADER_SECTOR 0x1 ++#define PRIMARY_TABLE_SECTOR 0x2 ++#define BACKUP_HEADER_SECTOR (DISK_SECTORS - 0x1) ++#define BACKUP_TABLE_SECTOR (BACKUP_HEADER_SECTOR - TABLE_SECTORS) ++ ++#define DATA_START_SECTOR (PRIMARY_TABLE_SECTOR + TABLE_SECTORS) ++#define DATA_END_SECTOR (BACKUP_TABLE_SECTOR - 0x1) ++#define DATA_SECTORS (BACKUP_TABLE_SECTOR - DATA_START_SECTOR) ++#define DATA_SIZE (GRUB_DISK_SECTOR_SIZE * DATA_SECTORS) ++ ++struct test_disk ++{ ++ struct grub_msdos_partition_mbr mbr; ++ ++ struct grub_gpt_header primary_header; ++ grub_uint8_t primary_header_pad[HEADER_PAD]; ++ struct grub_gpt_partentry primary_entries[TABLE_ENTRIES]; ++ ++ grub_uint8_t data[DATA_SIZE]; ++ ++ struct grub_gpt_partentry backup_entries[TABLE_ENTRIES]; ++ struct grub_gpt_header backup_header; ++ grub_uint8_t backup_header_pad[HEADER_PAD]; ++} GRUB_PACKED; ++ ++/* Sanity check that all the above ugly math was correct. */ ++verify (sizeof (struct test_disk) == DISK_SIZE); ++ ++struct test_data ++{ ++ int fd; ++ grub_device_t dev; ++ struct test_disk *raw; ++}; ++ ++ ++/* Sample primary GPT header for a 1MB disk. */ ++static const struct grub_gpt_header example_primary = { ++ .magic = GRUB_GPT_HEADER_MAGIC, ++ .version = GRUB_GPT_HEADER_VERSION, ++ .headersize = sizeof (struct grub_gpt_header), ++ .crc32 = grub_cpu_to_le32_compile_time (0xb985abe0), ++ .header_lba = grub_cpu_to_le64_compile_time (PRIMARY_HEADER_SECTOR), ++ .alternate_lba = grub_cpu_to_le64_compile_time (BACKUP_HEADER_SECTOR), ++ .start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR), ++ .end = grub_cpu_to_le64_compile_time (DATA_END_SECTOR), ++ .guid = GRUB_GPT_GUID_INIT(0x69c131ad, 0x67d6, 0x46c6, ++ 0x93, 0xc4, 0x12, 0x4c, 0x75, 0x52, 0x56, 0xac), ++ .partitions = grub_cpu_to_le64_compile_time (PRIMARY_TABLE_SECTOR), ++ .maxpart = grub_cpu_to_le32_compile_time (TABLE_ENTRIES), ++ .partentry_size = grub_cpu_to_le32_compile_time (ENTRY_SIZE), ++ .partentry_crc32 = grub_cpu_to_le32_compile_time (0x074e052c), ++}; ++ ++static const struct grub_gpt_partentry example_entries[TABLE_ENTRIES] = { ++ { ++ .type = GRUB_GPT_PARTITION_TYPE_EFI_SYSTEM, ++ .guid = GRUB_GPT_GUID_INIT (0xa0f1792e, 0xb4ce, 0x4136, 0xbc, 0xf2, ++ 0x1a, 0xfc, 0x13, 0x3c, 0x28, 0x28), ++ .start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR), ++ .end = grub_cpu_to_le64_compile_time (0x3f), ++ .attrib = 0x0, ++ .name = { ++ grub_cpu_to_le16_compile_time ('E'), ++ grub_cpu_to_le16_compile_time ('F'), ++ grub_cpu_to_le16_compile_time ('I'), ++ grub_cpu_to_le16_compile_time (' '), ++ grub_cpu_to_le16_compile_time ('S'), ++ grub_cpu_to_le16_compile_time ('Y'), ++ grub_cpu_to_le16_compile_time ('S'), ++ grub_cpu_to_le16_compile_time ('T'), ++ grub_cpu_to_le16_compile_time ('E'), ++ grub_cpu_to_le16_compile_time ('M'), ++ 0x0, ++ } ++ }, ++ { ++ .type = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT, ++ .guid = GRUB_GPT_GUID_INIT (0x876c898d, 0x1b40, 0x4727, 0xa1, 0x61, ++ 0xed, 0xf9, 0xb5, 0x48, 0x66, 0x74), ++ .start = grub_cpu_to_le64_compile_time (0x40), ++ .end = grub_cpu_to_le64_compile_time (0x7f), ++ .attrib = grub_cpu_to_le64_compile_time ( ++ 1ULL << GRUB_GPT_PART_ATTR_OFFSET_LEGACY_BIOS_BOOTABLE), ++ .name = { ++ grub_cpu_to_le16_compile_time ('B'), ++ grub_cpu_to_le16_compile_time ('I'), ++ grub_cpu_to_le16_compile_time ('O'), ++ grub_cpu_to_le16_compile_time ('S'), ++ grub_cpu_to_le16_compile_time (' '), ++ grub_cpu_to_le16_compile_time ('B'), ++ grub_cpu_to_le16_compile_time ('O'), ++ grub_cpu_to_le16_compile_time ('O'), ++ grub_cpu_to_le16_compile_time ('T'), ++ 0x0, ++ } ++ }, ++}; ++ ++/* And the backup header. */ ++static const struct grub_gpt_header example_backup = { ++ .magic = GRUB_GPT_HEADER_MAGIC, ++ .version = GRUB_GPT_HEADER_VERSION, ++ .headersize = sizeof (struct grub_gpt_header), ++ .crc32 = grub_cpu_to_le32_compile_time (0x0af785eb), ++ .header_lba = grub_cpu_to_le64_compile_time (BACKUP_HEADER_SECTOR), ++ .alternate_lba = grub_cpu_to_le64_compile_time (PRIMARY_HEADER_SECTOR), ++ .start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR), ++ .end = grub_cpu_to_le64_compile_time (DATA_END_SECTOR), ++ .guid = GRUB_GPT_GUID_INIT(0x69c131ad, 0x67d6, 0x46c6, ++ 0x93, 0xc4, 0x12, 0x4c, 0x75, 0x52, 0x56, 0xac), ++ .partitions = grub_cpu_to_le64_compile_time (BACKUP_TABLE_SECTOR), ++ .maxpart = grub_cpu_to_le32_compile_time (TABLE_ENTRIES), ++ .partentry_size = grub_cpu_to_le32_compile_time (ENTRY_SIZE), ++ .partentry_crc32 = grub_cpu_to_le32_compile_time (0x074e052c), ++}; ++ ++/* Sample protective MBR for the same 1MB disk. Note, this matches ++ * parted and fdisk behavior. The UEFI spec uses different values. */ ++static const struct grub_msdos_partition_mbr example_pmbr = { ++ .entries = {{.flag = 0x00, ++ .start_head = 0x00, ++ .start_sector = 0x01, ++ .start_cylinder = 0x00, ++ .type = 0xee, ++ .end_head = 0xfe, ++ .end_sector = 0xff, ++ .end_cylinder = 0xff, ++ .start = grub_cpu_to_le32_compile_time (0x1), ++ .length = grub_cpu_to_le32_compile_time (DISK_SECTORS - 0x1), ++ }}, ++ .signature = grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE), ++}; ++ ++/* If errors are left in grub's error stack things can get confused. */ ++static void ++assert_error_stack_empty (void) ++{ ++ do ++ { ++ grub_test_assert (grub_errno == GRUB_ERR_NONE, ++ "error on stack: %s", grub_errmsg); ++ } ++ while (grub_error_pop ()); ++} ++ ++static grub_err_t ++execute_command2 (const char *name, const char *arg1, const char *arg2) ++{ ++ grub_command_t cmd; ++ grub_err_t err; ++ char *argv[2]; ++ ++ cmd = grub_command_find (name); ++ if (!cmd) ++ grub_fatal ("can't find command %s", name); ++ ++ argv[0] = strdup (arg1); ++ argv[1] = strdup (arg2); ++ err = (cmd->func) (cmd, 2, argv); ++ free (argv[0]); ++ free (argv[1]); ++ ++ return err; ++} ++ ++static void ++sync_disk (struct test_data *data) ++{ ++ if (msync (data->raw, DISK_SIZE, MS_SYNC | MS_INVALIDATE) < 0) ++ grub_fatal ("Syncing disk failed: %s", strerror (errno)); ++ ++ grub_disk_cache_invalidate_all (); ++} ++ ++static void ++reset_disk (struct test_data *data) ++{ ++ memset (data->raw, 0, DISK_SIZE); ++ ++ /* Initialize image with valid example tables. */ ++ memcpy (&data->raw->mbr, &example_pmbr, sizeof (data->raw->mbr)); ++ memcpy (&data->raw->primary_header, &example_primary, ++ sizeof (data->raw->primary_header)); ++ memcpy (&data->raw->primary_entries, &example_entries, ++ sizeof (data->raw->primary_entries)); ++ memcpy (&data->raw->backup_entries, &example_entries, ++ sizeof (data->raw->backup_entries)); ++ memcpy (&data->raw->backup_header, &example_backup, ++ sizeof (data->raw->backup_header)); ++ ++ sync_disk (data); ++} ++ ++static void ++open_disk (struct test_data *data) ++{ ++ const char *loop = "loop0"; ++ char template[] = "/tmp/grub_gpt_test.XXXXXX"; ++ char host[sizeof ("(host)") + sizeof (template)]; ++ ++ data->fd = mkstemp (template); ++ if (data->fd < 0) ++ grub_fatal ("Creating %s failed: %s", template, strerror (errno)); ++ ++ if (ftruncate (data->fd, DISK_SIZE) < 0) ++ { ++ int err = errno; ++ unlink (template); ++ grub_fatal ("Resizing %s failed: %s", template, strerror (err)); ++ } ++ ++ data->raw = mmap (NULL, DISK_SIZE, PROT_READ | PROT_WRITE, ++ MAP_SHARED, data->fd, 0); ++ if (data->raw == MAP_FAILED) ++ { ++ int err = errno; ++ unlink (template); ++ grub_fatal ("Maping %s failed: %s", template, strerror (err)); ++ } ++ ++ snprintf (host, sizeof (host), "(host)%s", template); ++ if (execute_command2 ("loopback", loop, host) != GRUB_ERR_NONE) ++ { ++ unlink (template); ++ grub_fatal ("loopback %s %s failed: %s", loop, host, grub_errmsg); ++ } ++ ++ if (unlink (template) < 0) ++ grub_fatal ("Unlinking %s failed: %s", template, strerror (errno)); ++ ++ reset_disk (data); ++ ++ data->dev = grub_device_open (loop); ++ if (!data->dev) ++ grub_fatal ("Opening %s failed: %s", loop, grub_errmsg); ++} ++ ++static void ++close_disk (struct test_data *data) ++{ ++ char *loop; ++ ++ assert_error_stack_empty (); ++ ++ if (munmap (data->raw, DISK_SIZE) || close (data->fd)) ++ grub_fatal ("Closing disk image failed: %s", strerror (errno)); ++ ++ loop = strdup (data->dev->disk->name); ++ grub_test_assert (grub_device_close (data->dev) == GRUB_ERR_NONE, ++ "Closing disk device failed: %s", grub_errmsg); ++ ++ grub_test_assert (execute_command2 ("loopback", "-d", loop) == ++ GRUB_ERR_NONE, "loopback -d %s failed: %s", loop, ++ grub_errmsg); ++ ++ free (loop); ++} ++ ++static grub_gpt_t ++read_disk (struct test_data *data) ++{ ++ grub_gpt_t gpt; ++ ++ gpt = grub_gpt_read (data->dev->disk); ++ if (gpt == NULL) ++ grub_fatal ("grub_gpt_read failed: %s", grub_errmsg); ++ ++ return gpt; ++} ++ ++static void ++pmbr_test (void) ++{ ++ struct grub_msdos_partition_mbr mbr; ++ ++ memset (&mbr, 0, sizeof (mbr)); ++ ++ /* Empty is invalid. */ ++ grub_gpt_pmbr_check (&mbr); ++ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE, ++ "unexpected error: %s", grub_errmsg); ++ grub_errno = GRUB_ERR_NONE; ++ ++ /* A table without a protective partition is invalid. */ ++ mbr.signature = grub_cpu_to_le16_compile_time (GRUB_PC_PARTITION_SIGNATURE); ++ grub_gpt_pmbr_check (&mbr); ++ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE, ++ "unexpected error: %s", grub_errmsg); ++ grub_errno = GRUB_ERR_NONE; ++ ++ /* A table with a protective type is ok. */ ++ memcpy (&mbr, &example_pmbr, sizeof (mbr)); ++ grub_gpt_pmbr_check (&mbr); ++ grub_test_assert (grub_errno == GRUB_ERR_NONE, ++ "unexpected error: %s", grub_errmsg); ++ grub_errno = GRUB_ERR_NONE; ++} ++ ++static void ++header_test (void) ++{ ++ struct grub_gpt_header primary, backup; ++ ++ /* Example headers should be valid. */ ++ memcpy (&primary, &example_primary, sizeof (primary)); ++ grub_gpt_header_check (&primary, GRUB_DISK_SECTOR_BITS); ++ grub_test_assert (grub_errno == GRUB_ERR_NONE, ++ "unexpected error: %s", grub_errmsg); ++ grub_errno = GRUB_ERR_NONE; ++ ++ memcpy (&backup, &example_backup, sizeof (backup)); ++ grub_gpt_header_check (&backup, GRUB_DISK_SECTOR_BITS); ++ grub_test_assert (grub_errno == GRUB_ERR_NONE, ++ "unexpected error: %s", grub_errmsg); ++ grub_errno = GRUB_ERR_NONE; ++ ++ /* Twiddle the GUID to invalidate the CRC. */ ++ primary.guid.data1 = 0; ++ grub_gpt_header_check (&primary, GRUB_DISK_SECTOR_BITS); ++ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE, ++ "unexpected error: %s", grub_errmsg); ++ grub_errno = GRUB_ERR_NONE; ++ ++ backup.guid.data1 = 0; ++ grub_gpt_header_check (&backup, GRUB_DISK_SECTOR_BITS); ++ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE, ++ "unexpected error: %s", grub_errmsg); ++ grub_errno = GRUB_ERR_NONE; ++} ++ ++static void ++read_valid_test (void) ++{ ++ struct test_data data; ++ grub_gpt_t gpt; ++ ++ open_disk (&data); ++ gpt = read_disk (&data); ++ grub_test_assert (gpt->status == (GRUB_GPT_PROTECTIVE_MBR | ++ GRUB_GPT_PRIMARY_HEADER_VALID | ++ GRUB_GPT_PRIMARY_ENTRIES_VALID | ++ GRUB_GPT_BACKUP_HEADER_VALID | ++ GRUB_GPT_BACKUP_ENTRIES_VALID), ++ "unexpected status: 0x%02x", gpt->status); ++ grub_gpt_free (gpt); ++ close_disk (&data); ++} ++ ++static void ++read_invalid_entries_test (void) ++{ ++ struct test_data data; ++ grub_gpt_t gpt; ++ ++ open_disk (&data); ++ ++ /* Corrupt the first entry in both tables. */ ++ memset (&data.raw->primary_entries[0], 0x55, ++ sizeof (data.raw->primary_entries[0])); ++ memset (&data.raw->backup_entries[0], 0x55, ++ sizeof (data.raw->backup_entries[0])); ++ sync_disk (&data); ++ ++ gpt = grub_gpt_read (data.dev->disk); ++ grub_test_assert (gpt == NULL, "no error reported for corrupt entries"); ++ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE, ++ "unexpected error: %s", grub_errmsg); ++ grub_errno = GRUB_ERR_NONE; ++ ++ close_disk (&data); ++} ++ ++static void ++read_fallback_test (void) ++{ ++ struct test_data data; ++ grub_gpt_t gpt; ++ ++ open_disk (&data); ++ ++ /* Corrupt the primary header. */ ++ memset (&data.raw->primary_header.guid, 0x55, ++ sizeof (data.raw->primary_header.guid)); ++ sync_disk (&data); ++ gpt = read_disk (&data); ++ grub_test_assert ((gpt->status & GRUB_GPT_PRIMARY_HEADER_VALID) == 0, ++ "unreported corrupt primary header"); ++ grub_gpt_free (gpt); ++ reset_disk (&data); ++ ++ /* Corrupt the backup header. */ ++ memset (&data.raw->backup_header.guid, 0x55, ++ sizeof (data.raw->backup_header.guid)); ++ sync_disk (&data); ++ gpt = read_disk (&data); ++ grub_test_assert ((gpt->status & GRUB_GPT_BACKUP_HEADER_VALID) == 0, ++ "unreported corrupt backup header"); ++ grub_gpt_free (gpt); ++ reset_disk (&data); ++ ++ /* Corrupt the primary entry table. */ ++ memset (&data.raw->primary_entries[0], 0x55, ++ sizeof (data.raw->primary_entries[0])); ++ sync_disk (&data); ++ gpt = read_disk (&data); ++ grub_test_assert ((gpt->status & GRUB_GPT_PRIMARY_ENTRIES_VALID) == 0, ++ "unreported corrupt primary entries table"); ++ grub_gpt_free (gpt); ++ reset_disk (&data); ++ ++ /* Corrupt the backup entry table. */ ++ memset (&data.raw->backup_entries[0], 0x55, ++ sizeof (data.raw->backup_entries[0])); ++ sync_disk (&data); ++ gpt = read_disk (&data); ++ grub_test_assert ((gpt->status & GRUB_GPT_BACKUP_ENTRIES_VALID) == 0, ++ "unreported corrupt backup entries table"); ++ grub_gpt_free (gpt); ++ reset_disk (&data); ++ ++ /* If primary is corrupt and disk size is unknown fallback fails. */ ++ memset (&data.raw->primary_header.guid, 0x55, ++ sizeof (data.raw->primary_header.guid)); ++ sync_disk (&data); ++ data.dev->disk->total_sectors = GRUB_DISK_SIZE_UNKNOWN; ++ gpt = grub_gpt_read (data.dev->disk); ++ grub_test_assert (gpt == NULL, "no error reported"); ++ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE, ++ "unexpected error: %s", grub_errmsg); ++ grub_errno = GRUB_ERR_NONE; ++ ++ close_disk (&data); ++} ++ ++static void ++repair_test (void) ++{ ++ struct test_data data; ++ grub_gpt_t gpt; ++ ++ open_disk (&data); ++ ++ /* Erase/Repair primary. */ ++ memset (&data.raw->primary_header, 0, sizeof (data.raw->primary_header)); ++ sync_disk (&data); ++ gpt = read_disk (&data); ++ grub_gpt_repair (data.dev->disk, gpt); ++ grub_test_assert (grub_errno == GRUB_ERR_NONE, ++ "repair failed: %s", grub_errmsg); ++ if (memcmp (&gpt->primary, &example_primary, sizeof (gpt->primary))) ++ { ++ printf ("Invalid restored primary header:\n"); ++ hexdump (16, (char*)&gpt->primary, sizeof (gpt->primary)); ++ printf ("Expected primary header:\n"); ++ hexdump (16, (char*)&example_primary, sizeof (example_primary)); ++ grub_test_assert (0, "repair did not restore primary header"); ++ } ++ grub_gpt_free (gpt); ++ reset_disk (&data); ++ ++ /* Erase/Repair backup. */ ++ memset (&data.raw->backup_header, 0, sizeof (data.raw->backup_header)); ++ sync_disk (&data); ++ gpt = read_disk (&data); ++ grub_gpt_repair (data.dev->disk, gpt); ++ grub_test_assert (grub_errno == GRUB_ERR_NONE, ++ "repair failed: %s", grub_errmsg); ++ if (memcmp (&gpt->backup, &example_backup, sizeof (gpt->backup))) ++ { ++ printf ("Invalid restored backup header:\n"); ++ hexdump (16, (char*)&gpt->backup, sizeof (gpt->backup)); ++ printf ("Expected backup header:\n"); ++ hexdump (16, (char*)&example_backup, sizeof (example_backup)); ++ grub_test_assert (0, "repair did not restore backup header"); ++ } ++ grub_gpt_free (gpt); ++ reset_disk (&data); ++ ++ close_disk (&data); ++} ++ ++/* Finding/reading/writing the backup GPT may be difficult if the OS and ++ * BIOS report different sizes for the same disk. We need to gracefully ++ * recognize this and avoid causing trouble for the OS. */ ++static void ++weird_disk_size_test (void) ++{ ++ struct test_data data; ++ grub_gpt_t gpt; ++ ++ open_disk (&data); ++ ++ /* Chop off 65536 bytes (128 512B sectors) which may happen when the ++ * BIOS thinks you are using a software RAID system that reserves that ++ * area for metadata when in fact you are not and using the bare disk. */ ++ grub_test_assert(data.dev->disk->total_sectors == DISK_SECTORS, ++ "unexpected disk size: 0x%llx", ++ (unsigned long long) data.dev->disk->total_sectors); ++ data.dev->disk->total_sectors -= 128; ++ ++ gpt = read_disk (&data); ++ assert_error_stack_empty (); ++ /* Reading the alternate_lba should have been blocked and reading ++ * the (new) end of disk should have found no useful data. */ ++ grub_test_assert ((gpt->status & GRUB_GPT_BACKUP_HEADER_VALID) == 0, ++ "unreported missing backup header"); ++ ++ /* We should be able to reconstruct the backup header and the location ++ * of the backup should remain unchanged, trusting the GPT data over ++ * what the BIOS is telling us. Further changes are left to the OS. */ ++ grub_gpt_repair (data.dev->disk, gpt); ++ grub_test_assert (grub_errno == GRUB_ERR_NONE, ++ "repair failed: %s", grub_errmsg); ++ grub_test_assert (memcmp (&gpt->primary, &example_primary, ++ sizeof (gpt->primary)) == 0, ++ "repair corrupted primary header"); ++ ++ grub_gpt_free (gpt); ++ close_disk (&data); ++} ++ ++static void ++iterate_partitions_test (void) ++{ ++ struct test_data data; ++ struct grub_gpt_partentry *p; ++ grub_gpt_t gpt; ++ grub_uint32_t n; ++ ++ open_disk (&data); ++ gpt = read_disk (&data); ++ ++ for (n = 0; (p = grub_gpt_get_partentry (gpt, n)) != NULL; n++) ++ grub_test_assert (memcmp (p, &example_entries[n], sizeof (*p)) == 0, ++ "unexpected partition %d data", n); ++ ++ grub_test_assert (n == TABLE_ENTRIES, "unexpected partition limit: %d", n); ++ ++ grub_gpt_free (gpt); ++ close_disk (&data); ++} ++ ++static void ++large_partitions_test (void) ++{ ++ struct test_data data; ++ struct grub_gpt_partentry *p; ++ grub_gpt_t gpt; ++ grub_uint32_t n; ++ ++ open_disk (&data); ++ ++ /* Double the entry size, cut the number of entries in half. */ ++ data.raw->primary_header.maxpart = ++ data.raw->backup_header.maxpart = ++ grub_cpu_to_le32_compile_time (TABLE_ENTRIES/2); ++ data.raw->primary_header.partentry_size = ++ data.raw->backup_header.partentry_size = ++ grub_cpu_to_le32_compile_time (ENTRY_SIZE*2); ++ data.raw->primary_header.partentry_crc32 = ++ data.raw->backup_header.partentry_crc32 = ++ grub_cpu_to_le32_compile_time (0xf2c45af8); ++ data.raw->primary_header.crc32 = grub_cpu_to_le32_compile_time (0xde00cc8f); ++ data.raw->backup_header.crc32 = grub_cpu_to_le32_compile_time (0x6d72e284); ++ ++ memset (&data.raw->primary_entries, 0, ++ sizeof (data.raw->primary_entries)); ++ for (n = 0; n < TABLE_ENTRIES/2; n++) ++ memcpy (&data.raw->primary_entries[n*2], &example_entries[n], ++ sizeof (data.raw->primary_entries[0])); ++ memcpy (&data.raw->backup_entries, &data.raw->primary_entries, ++ sizeof (data.raw->backup_entries)); ++ ++ sync_disk(&data); ++ gpt = read_disk (&data); ++ ++ for (n = 0; (p = grub_gpt_get_partentry (gpt, n)) != NULL; n++) ++ grub_test_assert (memcmp (p, &example_entries[n], sizeof (*p)) == 0, ++ "unexpected partition %d data", n); ++ ++ grub_test_assert (n == TABLE_ENTRIES/2, "unexpected partition limit: %d", n); ++ ++ grub_gpt_free (gpt); ++ ++ /* Editing memory beyond the entry structure should still change the crc. */ ++ data.raw->primary_entries[1].attrib = 0xff; ++ ++ sync_disk(&data); ++ gpt = read_disk (&data); ++ grub_test_assert (gpt->status == (GRUB_GPT_PROTECTIVE_MBR | ++ GRUB_GPT_PRIMARY_HEADER_VALID | ++ GRUB_GPT_BACKUP_HEADER_VALID | ++ GRUB_GPT_BACKUP_ENTRIES_VALID), ++ "unexpected status: 0x%02x", gpt->status); ++ grub_gpt_free (gpt); ++ ++ close_disk (&data); ++} ++ ++static void ++invalid_partsize_test (void) ++{ ++ struct grub_gpt_header header = { ++ .magic = GRUB_GPT_HEADER_MAGIC, ++ .version = GRUB_GPT_HEADER_VERSION, ++ .headersize = sizeof (struct grub_gpt_header), ++ .crc32 = grub_cpu_to_le32_compile_time (0x1ff2a054), ++ .header_lba = grub_cpu_to_le64_compile_time (PRIMARY_HEADER_SECTOR), ++ .alternate_lba = grub_cpu_to_le64_compile_time (BACKUP_HEADER_SECTOR), ++ .start = grub_cpu_to_le64_compile_time (DATA_START_SECTOR), ++ .end = grub_cpu_to_le64_compile_time (DATA_END_SECTOR), ++ .guid = GRUB_GPT_GUID_INIT(0x69c131ad, 0x67d6, 0x46c6, ++ 0x93, 0xc4, 0x12, 0x4c, 0x75, 0x52, 0x56, 0xac), ++ .partitions = grub_cpu_to_le64_compile_time (PRIMARY_TABLE_SECTOR), ++ .maxpart = grub_cpu_to_le32_compile_time (TABLE_ENTRIES), ++ /* Triple the entry size, which is not valid. */ ++ .partentry_size = grub_cpu_to_le32_compile_time (ENTRY_SIZE*3), ++ .partentry_crc32 = grub_cpu_to_le32_compile_time (0x074e052c), ++ }; ++ ++ grub_gpt_header_check(&header, GRUB_DISK_SECTOR_BITS); ++ grub_test_assert (grub_errno == GRUB_ERR_BAD_PART_TABLE, ++ "unexpected error: %s", grub_errmsg); ++ grub_test_assert (strcmp(grub_errmsg, "invalid GPT entry size") == 0, ++ "unexpected error: %s", grub_errmsg); ++ grub_errno = GRUB_ERR_NONE; ++} ++ ++static void ++search_part_label_test (void) ++{ ++ struct test_data data; ++ const char *test_result; ++ char *expected_result; ++ ++ open_disk (&data); ++ ++ expected_result = grub_xasprintf ("%s,gpt1", data.dev->disk->name); ++ grub_env_unset ("test_result"); ++ grub_search_part_label ("EFI SYSTEM", "test_result", 0, NULL, 0); ++ test_result = grub_env_get ("test_result"); ++ grub_test_assert (test_result && strcmp (test_result, expected_result) == 0, ++ "wrong device: %s (%s)", test_result, expected_result); ++ grub_free (expected_result); ++ ++ expected_result = grub_xasprintf ("%s,gpt2", data.dev->disk->name); ++ grub_env_unset ("test_result"); ++ grub_search_part_label ("BIOS BOOT", "test_result", 0, NULL, 0); ++ test_result = grub_env_get ("test_result"); ++ grub_test_assert (test_result && strcmp (test_result, expected_result) == 0, ++ "wrong device: %s (%s)", test_result, expected_result); ++ grub_free (expected_result); ++ ++ grub_env_unset ("test_result"); ++ grub_search_part_label ("bogus name", "test_result", 0, NULL, 0); ++ test_result = grub_env_get ("test_result"); ++ grub_test_assert (test_result == NULL, ++ "unexpected device: %s", test_result); ++ grub_test_assert (grub_errno == GRUB_ERR_FILE_NOT_FOUND, ++ "unexpected error: %s", grub_errmsg); ++ grub_errno = GRUB_ERR_NONE; ++ ++ close_disk (&data); ++} ++ ++static void ++search_part_uuid_test (void) ++{ ++ struct test_data data; ++ const char gpt1_uuid[] = "A0F1792E-B4CE-4136-BCF2-1AFC133C2828"; ++ const char gpt2_uuid[] = "876c898d-1b40-4727-a161-edf9b5486674"; ++ const char bogus_uuid[] = "1534c928-c50e-4866-9daf-6a9fd7918a76"; ++ const char *test_result; ++ char *expected_result; ++ ++ open_disk (&data); ++ ++ expected_result = grub_xasprintf ("%s,gpt1", data.dev->disk->name); ++ grub_env_unset ("test_result"); ++ grub_search_part_uuid (gpt1_uuid, "test_result", 0, NULL, 0); ++ test_result = grub_env_get ("test_result"); ++ grub_test_assert (test_result && strcmp (test_result, expected_result) == 0, ++ "wrong device: %s (%s)", test_result, expected_result); ++ grub_free (expected_result); ++ ++ expected_result = grub_xasprintf ("%s,gpt2", data.dev->disk->name); ++ grub_env_unset ("test_result"); ++ grub_search_part_uuid (gpt2_uuid, "test_result", 0, NULL, 0); ++ test_result = grub_env_get ("test_result"); ++ grub_test_assert (test_result && strcmp (test_result, expected_result) == 0, ++ "wrong device: %s (%s)", test_result, expected_result); ++ grub_free (expected_result); ++ ++ grub_env_unset ("test_result"); ++ grub_search_part_uuid (bogus_uuid, "test_result", 0, NULL, 0); ++ test_result = grub_env_get ("test_result"); ++ grub_test_assert (test_result == NULL, ++ "unexpected device: %s", test_result); ++ grub_test_assert (grub_errno == GRUB_ERR_FILE_NOT_FOUND, ++ "unexpected error: %s", grub_errmsg); ++ grub_errno = GRUB_ERR_NONE; ++ ++ close_disk (&data); ++} ++ ++void ++grub_unit_test_init (void) ++{ ++ grub_init_all (); ++ grub_hostfs_init (); ++ grub_host_init (); ++ grub_test_register ("gpt_pmbr_test", pmbr_test); ++ grub_test_register ("gpt_header_test", header_test); ++ grub_test_register ("gpt_read_valid_test", read_valid_test); ++ grub_test_register ("gpt_read_invalid_test", read_invalid_entries_test); ++ grub_test_register ("gpt_read_fallback_test", read_fallback_test); ++ grub_test_register ("gpt_repair_test", repair_test); ++ grub_test_register ("gpt_iterate_partitions_test", iterate_partitions_test); ++ grub_test_register ("gpt_large_partitions_test", large_partitions_test); ++ grub_test_register ("gpt_invalid_partsize_test", invalid_partsize_test); ++ grub_test_register ("gpt_weird_disk_size_test", weird_disk_size_test); ++ grub_test_register ("gpt_search_part_label_test", search_part_label_test); ++ grub_test_register ("gpt_search_uuid_test", search_part_uuid_test); ++} ++ ++void ++grub_unit_test_fini (void) ++{ ++ grub_test_unregister ("gpt_pmbr_test"); ++ grub_test_unregister ("gpt_header_test"); ++ grub_test_unregister ("gpt_read_valid_test"); ++ grub_test_unregister ("gpt_read_invalid_test"); ++ grub_test_unregister ("gpt_read_fallback_test"); ++ grub_test_unregister ("gpt_repair_test"); ++ grub_test_unregister ("gpt_iterate_partitions_test"); ++ grub_test_unregister ("gpt_large_partitions_test"); ++ grub_test_unregister ("gpt_invalid_partsize_test"); ++ grub_test_unregister ("gpt_weird_disk_size_test"); ++ grub_test_unregister ("gpt_search_part_label_test"); ++ grub_test_unregister ("gpt_search_part_uuid_test"); ++ grub_fini_all (); ++} +diff --git a/tests/gptprio_test.in b/tests/gptprio_test.in +new file mode 100644 +index 000000000..c5cf0f3b7 +--- /dev/null ++++ b/tests/gptprio_test.in +@@ -0,0 +1,207 @@ ++#! /bin/bash ++set -e ++ ++# Copyright (C) 2010 Free Software Foundation, Inc. ++# Copyright (C) 2014 CoreOS, Inc. ++# ++# GRUB is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++# ++# GRUB is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with GRUB. If not, see . ++ ++sgdisk=sgdisk ++grubshell=@builddir@/grub-shell ++ ++if ! which "${sgdisk}" >/dev/null 2>&1; then ++ echo "sgdisk not installed; cannot test gptprio." ++ exit 77 ++fi ++ ++. "@builddir@/grub-core/modinfo.sh" ++ ++case "${grub_modinfo_target_cpu}-${grub_modinfo_platform}" in ++ mips-qemu_mips | mipsel-qemu_mips | i386-qemu | i386-multiboot | i386-coreboot | mipsel-loongson) ++ disk=ata0 ++ ;; ++ powerpc-ieee1275) ++ disk=ieee1275//pci@80000000/mac-io@4/ata-3@20000/disk@0 ++ # FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label. ++ exit 0 ++ ;; ++ sparc64-ieee1275) ++ disk=ieee1275//pci@1fe\,0/pci-ata@5/ide0@500/disk@0 ++ # FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label. ++ exit 0 ++ ;; ++ i386-ieee1275) ++ disk=ieee1275/d ++ # FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label. ++ exit 0 ++ ;; ++ mips-arc) ++ # FIXME: ARC firmware has bugs which prevent it from accessing hard disk w/o dvh disklabel. ++ exit 0 ;; ++ mipsel-arc) ++ disk=arc/scsi0/disk0/rdisk0 ++ ;; ++ *) ++ disk=hd0 ++ ;; ++esac ++img1="`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"`" || exit 1 ++trap "rm -f '${img1}'" EXIT ++ ++prio_type="5dfbf5f4-2848-4bac-aa5e-0d9a20b745a6" ++declare -a prio_uuid ++prio_uuid[2]="9b003904-d006-4ab3-97f1-73f547b7af1a" ++prio_uuid[3]="1aa5a658-5b02-414d-9b71-f7e6c151f0cd" ++prio_uuid[4]="8aa0240d-98af-42b0-b32a-ccbe0572d62b" ++ ++create_disk_image () { ++ size=$1 ++ rm -f "${img1}" ++ dd if=/dev/zero of="${img1}" bs=512 count=1 seek=$((size - 1)) status=none ++ ${sgdisk} \ ++ -n 1:0:+1 -c 1:ESP -t 1:ef00 \ ++ -n 2:0:+1 -c 2:A -t 2:"${prio_type}" -u 2:"${prio_uuid[2]}" \ ++ -n 3:0:+1 -c 3:B -t 3:"${prio_type}" -u 3:"${prio_uuid[3]}" \ ++ -n 4:0:+1 -c 4:C -t 4:"${prio_type}" -u 4:"${prio_uuid[4]}" \ ++ "${img1}" >/dev/null ++} ++ ++wipe_disk_area () { ++ sector=$1 ++ size=$2 ++ dd if=/dev/zero of="${img1}" bs=512 count=${size} seek=${sector} conv=notrunc status=none ++} ++ ++is_zero () { ++ sector=$1 ++ size=$2 ++ cmp -s -i $((sector * 512)) -n $((size * 512)) /dev/zero "${img1}" ++} ++ ++check_is_zero () { ++ sector=$1 ++ size=$2 ++ if ! is_zero "$@"; then ++ echo "$size sector(s) starting at $sector should be all zero" ++ exit 1 ++ fi ++} ++ ++check_not_zero () { ++ sector=$1 ++ size=$2 ++ if is_zero "$@"; then ++ echo "$size sector(s) starting at $sector should not be all zero" ++ exit 1 ++ fi ++} ++ ++fmt_prio () { ++ priority=$(( ( $1 & 15 ) << 48 )) ++ tries=$(( ( $2 & 15 ) << 52 )) ++ success=$(( ( $3 & 1 ) << 56 )) ++ printf %016x $(( priority | tries | success )) ++} ++ ++set_prio () { ++ part="$1" ++ attr=$(fmt_prio $2 $3 $4) ++ ${sgdisk} -A "${part}:=:${attr}" "${img1}" >/dev/null ++} ++ ++check_prio () { ++ part="$1" ++ expect=$(fmt_prio $2 $3 $4) ++ result=$(LANG=C ${sgdisk} -i "${part}" "${img1}" 2>&1 \ ++ | awk '/^Attribute flags: / {print $3}') ++ if [[ "${expect}" != "${result}" ]]; then ++ echo "Partition ${part} has attributes ${result:-??}, not ${expect}" ++ exit 1 ++ fi ++} ++ ++run_next() { ++ "${grubshell}" --disk="${img1}" --modules=gptprio <. ++ ++parted=parted ++grubshell=@builddir@/grub-shell ++ ++. "@builddir@/grub-core/modinfo.sh" ++ ++case "${grub_modinfo_target_cpu}-${grub_modinfo_platform}" in ++ mips-qemu_mips | mipsel-qemu_mips | i386-qemu | i386-multiboot | i386-coreboot | mipsel-loongson) ++ disk=ata0 ++ ;; ++ powerpc-ieee1275) ++ disk=ieee1275//pci@80000000/mac-io@4/ata-3@20000/disk@0 ++ # FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label. ++ exit 0 ++ ;; ++ sparc64-ieee1275) ++ disk=ieee1275//pci@1fe\,0/pci-ata@5/ide0@500/disk@0 ++ # FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label. ++ exit 0 ++ ;; ++ i386-ieee1275) ++ disk=ieee1275/d ++ # FIXME: QEMU firmware has bugs which prevent it from accessing hard disk w/o recognised label. ++ exit 0 ++ ;; ++ mips-arc) ++ # FIXME: ARC firmware has bugs which prevent it from accessing hard disk w/o dvh disklabel. ++ exit 0 ;; ++ mipsel-arc) ++ disk=arc/scsi0/disk0/rdisk0 ++ ;; ++ *) ++ disk=hd0 ++ ;; ++esac ++img1="`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"`" || exit 1 ++img2="`mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX"`" || exit 1 ++trap "rm -f '${img1}' '${img2}'" EXIT ++ ++create_disk_image () { ++ size=$1 ++ rm -f "${img1}" ++ dd if=/dev/zero of="${img1}" bs=512 count=1 seek=$((size - 1)) status=none ++ ${parted} -a none -s "${img1}" mklabel gpt ++ cp "${img1}" "${img2}" ++} ++ ++wipe_disk_area () { ++ sector=$1 ++ size=$2 ++ dd if=/dev/zero of="${img2}" bs=512 count=${size} seek=${sector} conv=notrunc status=none ++} ++ ++do_repair () { ++ output="`echo "gptrepair ($disk)" | "${grubshell}" --disk="${img2}"`" ++ if echo "${output}" | grep ^error; then ++ return 1 ++ fi ++ if echo "${output}" | grep -v GPT; then ++ echo "Unexpected output ${output}" ++ return 1 ++ fi ++ echo "${output}" ++} ++ ++echo "Nothing to repair:" ++create_disk_image 100 ++do_repair ++cmp "${img1}" "${img2}" ++echo ++ ++echo "Repair primary (MBR left intact)" ++create_disk_image 100 ++wipe_disk_area 1 1 ++do_repair ++cmp "${img1}" "${img2}" ++echo ++ ++echo "Repair backup" ++create_disk_image 100 ++wipe_disk_area 99 1 ++do_repair ++cmp "${img1}" "${img2}" ++echo +-- +2.34.1 + diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-verity-hash.patch b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-verity-hash.patch new file mode 100644 index 00000000000..ed892d90dd2 --- /dev/null +++ b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/files/grub-2.06-add-verity-hash.patch @@ -0,0 +1,134 @@ +From 14d4760aacb8896f99422c06d100e5231e09e797 Mon Sep 17 00:00:00 2001 +From: Sayan Chowdhury +Date: Thu, 24 Aug 2023 00:00:00 +0530 +Subject: Add verity hash passthrough + +Read the verity hash from the kernel binary and pass it to the running +system via the kernel command line + +The patch is prepared using the coreos/grub PRs, picking the only +required ones, and dropping the others. The README.md file in the +coreos-overlay/sys-boot/grub/ contains more contexual information +along with the commits used to create the patch. + +Authored-by: Matthew Garrett +Signed-off-by: Sayan Chowdhury +--- + grub-core/loader/arm64/linux.c | 6 +++- + grub-core/loader/i386/linux.c | 3 ++ + include/grub/verity-hash.h | 51 ++++++++++++++++++++++++++++++++++ + 3 files changed, 59 insertions(+), 1 deletion(-) + create mode 100644 include/grub/verity-hash.h + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index ef3e9f944..17bed4e15 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -34,6 +34,8 @@ + #include + #include + ++#include ++ + GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; +@@ -333,7 +335,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + grub_dprintf ("linux", "kernel @ %p\n", kernel_addr); + +- cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE); ++ cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE) ++ + VERITY_CMDLINE_LENGTH; + linux_args = grub_malloc (cmdline_size); + if (!linux_args) + { +@@ -350,6 +353,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + + if (grub_errno == GRUB_ERR_NONE) + { ++ grub_pass_verity_hash (kernel_addr, linux_args, cmdline_size); + grub_loader_set (grub_linux_boot, grub_linux_unload, 0); + loaded = 1; + } +diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c +index 9f74a96b1..1c76ac5bf 100644 +--- a/grub-core/loader/i386/linux.c ++++ b/grub-core/loader/i386/linux.c +@@ -38,6 +38,8 @@ + #include + #include + ++#include ++ + GRUB_MOD_LICENSE ("GPLv3+"); + + #ifdef GRUB_MACHINE_PCBIOS +@@ -1006,6 +1008,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + ++ grub_pass_verity_hash(&lh, linux_cmdline, maximal_cmdline_size); + len = prot_file_size; + if (grub_file_read (file, prot_mode_mem, len) != len && !grub_errno) + grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), +diff --git a/include/grub/verity-hash.h b/include/grub/verity-hash.h +new file mode 100644 +index 000000000..448d9aff0 +--- /dev/null ++++ b/include/grub/verity-hash.h +@@ -0,0 +1,51 @@ ++/* CoreOS verity hash */ ++ ++#define VERITY_ARG " verity.usrhash=" ++#define VERITY_ARG_LENGTH (sizeof (VERITY_ARG) - 1) ++#define VERITY_HASH_LENGTH 64 ++#define VERITY_CMDLINE_LENGTH ((VERITY_ARG_LENGTH)+(VERITY_HASH_LENGTH)) ++ ++#if defined(__aarch64__) ++# define VERITY_HASH_OFFSET 512 ++#elif defined(__i386__) || defined(__amd64__) ++# define VERITY_HASH_OFFSET 0x40 ++#else ++# error Unsupported arch ++#endif ++ ++ ++/** ++ * grub_pass_verity_hash - Reads the CoreOS verity hash value from a well known ++ * kernel image offset and adds a kernel command line argument for it. ++ * ++ * @pImage: Kernel image buffer. ++ * @cmdline: Kernel command line buffer. ++ * @cmdline_max_len: Kernel command line buffer length. ++ */ ++ ++static inline void grub_pass_verity_hash(const void *pImage, ++ char *cmdline, ++ grub_size_t cmdline_max_len) ++{ ++ const char *buf = pImage; ++ grub_size_t cmdline_len; ++ int i; ++ ++ for (i=VERITY_HASH_OFFSET; i '9') // Not a number ++ if (buf[i] < 'a' || buf[i] > 'f') // Not a hex letter ++ return; ++ } ++ ++ cmdline_len = grub_strlen(cmdline); ++ if (cmdline_len + VERITY_CMDLINE_LENGTH > cmdline_max_len) ++ return; ++ ++ grub_memcpy (cmdline + cmdline_len, VERITY_ARG, VERITY_ARG_LENGTH); ++ cmdline_len += VERITY_ARG_LENGTH; ++ grub_memcpy (cmdline + cmdline_len, buf + VERITY_HASH_OFFSET, ++ VERITY_HASH_LENGTH); ++ cmdline_len += VERITY_HASH_LENGTH; ++ cmdline[cmdline_len] = '\0'; ++} +-- +2.34.1 + diff --git a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-2.06-r9.ebuild b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-2.06-r9.ebuild index f372a2ec6a0..72140d4ab9b 100644 --- a/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-2.06-r9.ebuild +++ b/sdk_container/src/third_party/coreos-overlay/sys-boot/grub/grub-2.06-r9.ebuild @@ -54,7 +54,8 @@ if [[ ${PV} != 9999 ]]; then " S=${WORKDIR}/${P%_*} fi - KEYWORDS="amd64 ~arm ~arm64 ~ia64 ~ppc ~ppc64 ~riscv ~sparc x86" + # Flatcar: Mark as stable for arm64. + KEYWORDS="amd64 ~arm arm64 ~ia64 ~ppc ~ppc64 ~riscv ~sparc x86" else inherit git-r3 EGIT_REPO_URI="https://git.savannah.gnu.org/git/grub.git" @@ -67,6 +68,9 @@ PATCHES=( "${FILESDIR}"/gfxpayload.patch "${FILESDIR}"/grub-2.02_beta2-KERNEL_GLOBS.patch "${FILESDIR}"/grub-2.06-test-words.patch + # Flatcar: Add our patches. + "${FILESDIR}"/grub-2.06-add-verity-hash.patch + "${FILESDIR}"/grub-2.06-add-gpt-partition-scheme.patch ) DEJAVU=dejavu-sans-ttf-2.37 @@ -84,6 +88,9 @@ IUSE="device-mapper doc efiemu +fonts mount nls sdl test +themes truetype libzfs GRUB_ALL_PLATFORMS=( coreboot efi-32 efi-64 emu ieee1275 loongson multiboot qemu qemu-mips pc uboot xen xen-32 xen-pvh ) + +# Flatcar: Add arm64 to the list of platforms +GRUB_ALL_PLATFORMS+=( arm64 ) IUSE+=" ${GRUB_ALL_PLATFORMS[@]/#/grub_platforms_}" REQUIRED_USE=" @@ -93,12 +100,14 @@ REQUIRED_USE=" grub_platforms_loongson? ( fonts ) " +# Flatcar: Add a dependency on aarch64 cross gcc for arm64 platform. BDEPEND=" ${PYTHON_DEPS} >=sys-devel/flex-2.5.35 sys-devel/bison sys-apps/help2man sys-apps/texinfo + grub_platforms_arm64? ( cross-aarch64-cros-linux-gnu/gcc ) fonts? ( media-libs/freetype:2 virtual/pkgconfig @@ -205,6 +214,8 @@ grub_configure() { efi*) platform=efi ;; xen-pvh) platform=xen_pvh ;; xen*) platform=xen ;; + # Flatcar: Handle arm64 as efi platform + arm64*) platform=efi ;; guessed) ;; *) platform=${MULTIBUILD_VARIANT} ;; esac From 409d84cdd78e650b2a42258e1b45ce5f049b9a04 Mon Sep 17 00:00:00 2001 From: Krzesimir Nowak Date: Thu, 12 Oct 2023 13:26:33 +0200 Subject: [PATCH 3/3] changelog: Add an entry --- changelog/security/2023-10-12-grub-update.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/security/2023-10-12-grub-update.md diff --git a/changelog/security/2023-10-12-grub-update.md b/changelog/security/2023-10-12-grub-update.md new file mode 100644 index 00000000000..7e36bbab06e --- /dev/null +++ b/changelog/security/2023-10-12-grub-update.md @@ -0,0 +1 @@ +- grub ([CVE-2023-4692](https://nvd.nist.gov/vuln/detail/CVE-2023-4692), [CVE-2023-4693](https://nvd.nist.gov/vuln/detail/CVE-2023-4693))